Add import profile from file

This commit is contained in:
世界
2024-03-17 01:00:21 +08:00
parent 720b5621d2
commit ae7166a699
14 changed files with 105 additions and 14 deletions

View File

@@ -2,10 +2,12 @@ package io.nekohasekai.sfa.ui.main
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@@ -84,12 +86,18 @@ class ConfigurationFragment : Fragment() {
class AddProfileDialog : BottomSheetDialogFragment(R.layout.sheet_add_profile) { class AddProfileDialog : BottomSheetDialogFragment(R.layout.sheet_add_profile) {
private val importFromFile =
registerForActivityResult(ActivityResultContracts.GetContent(), ::onImportResult)
private val scanQrCode = private val scanQrCode =
registerForActivityResult(QRScanActivity.Contract(), ::onScanResult) registerForActivityResult(QRScanActivity.Contract(), ::onScanResult)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val binding = SheetAddProfileBinding.bind(view) val binding = SheetAddProfileBinding.bind(view)
binding.importFromFile.setOnClickListener {
importFromFile.launch("*/*")
}
binding.scanQrCode.setOnClickListener { binding.scanQrCode.setOnClickListener {
scanQrCode.launch(null) scanQrCode.launch(null)
} }
@@ -99,6 +107,11 @@ class ConfigurationFragment : Fragment() {
} }
} }
private fun onImportResult(result: Uri?) {
dismiss()
(activity as? MainActivity ?: return).onNewIntent(Intent(Intent.ACTION_VIEW, result))
}
private fun onScanResult(result: Intent?) { private fun onScanResult(result: Intent?) {
dismiss() dismiss()
(activity as? MainActivity ?: return).onNewIntent(result ?: return) (activity as? MainActivity ?: return).onNewIntent(result ?: return)

View File

@@ -15,7 +15,9 @@ import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.nekohasekai.libbox.Libbox import io.nekohasekai.libbox.Libbox
import io.nekohasekai.sfa.R import io.nekohasekai.sfa.R
@@ -36,6 +38,13 @@ class QRScanActivity : AbstractActivity<ActivityQrScanBinding>() {
setTitle(R.string.profile_add_scan_qr_code) setTitle(R.string.profile_add_scan_qr_code)
analysisExecutor = Executors.newSingleThreadExecutor() analysisExecutor = Executors.newSingleThreadExecutor()
binding.previewView.implementationMode = PreviewView.ImplementationMode.COMPATIBLE
binding.previewView.previewStreamState.observe(this) {
if (it === PreviewView.StreamState.STREAMING) {
binding.progress.isVisible = false
binding.previewView.implementationMode = PreviewView.ImplementationMode.PERFORMANCE
}
}
if (ContextCompat.checkSelfPermission( if (ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA this, Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED ) == PackageManager.PERMISSION_GRANTED

View File

@@ -30,10 +30,13 @@ import io.nekohasekai.sfa.databinding.ViewAppListItemBinding
import io.nekohasekai.sfa.ktx.clipboardText import io.nekohasekai.sfa.ktx.clipboardText
import io.nekohasekai.sfa.ui.shared.AbstractActivity import io.nekohasekai.sfa.ui.shared.AbstractActivity
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.util.concurrent.atomic.AtomicInteger
import java.util.zip.ZipFile import java.util.zip.ZipFile
class PerAppProxyActivity : AbstractActivity<ActivityPerAppProxyBinding>() { class PerAppProxyActivity : AbstractActivity<ActivityPerAppProxyBinding>() {
@@ -530,18 +533,26 @@ class PerAppProxyActivity : AbstractActivity<ActivityPerAppProxyBinding>() {
).setView(binding.root).setCancelable(false).create() ).setView(binding.root).setCancelable(false).create()
progress.show() progress.show()
lifecycleScope.launch { lifecycleScope.launch {
val foundApps = withContext(Dispatchers.IO) { val startTime = System.currentTimeMillis()
val foundApps = withContext(Dispatchers.Default) {
mutableMapOf<String, PackageCache>().also { foundApps -> mutableMapOf<String, PackageCache>().also { foundApps ->
currentPackages.forEachIndexed { index, it -> val progressInt = AtomicInteger()
if (scanChinaPackage(it.packageName)) { currentPackages.map { it ->
foundApps[it.packageName] = it async {
if (scanChinaPackage(it.packageName)) {
foundApps[it.packageName] = it
}
runOnUiThread {
binding.progress.progress = progressInt.addAndGet(1)
}
} }
withContext(Dispatchers.Main) { }.awaitAll()
binding.progress.progress = index + 1
}
}
} }
} }
Log.d(
"PerAppProxyActivity",
"Scan China apps took ${(System.currentTimeMillis() - startTime).toDouble() / 1000}s"
)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
progress.dismiss() progress.dismiss()
if (foundApps.isEmpty()) { if (foundApps.isEmpty()) {

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:tint="#000000"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp">
<path
android:fillColor="@android:color/white"
android:pathData="M14,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.89,2 1.99,2H15v-8h5V8L14,2zM13,9V3.5L18.5,9H13zM17,21.66V16h5.66v2h-2.24l2.95,2.95l-1.41,1.41L19,19.41l0,2.24H17z" />
</vector>

View File

@@ -28,6 +28,7 @@
android:id="@+id/profileLayout" android:id="@+id/profileLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp" android:padding="16dp"

View File

@@ -8,6 +8,19 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?colorSurface"
android:gravity="center">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</LinearLayout>
<include layout="@layout/view_appbar" /> <include layout="@layout/view_appbar" />
</FrameLayout> </FrameLayout>

View File

@@ -4,7 +4,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout" android:id="@+id/appbar_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -31,9 +30,10 @@
android:id="@+id/scanVPNResult" android:id="@+id/scanVPNResult"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingBottom="16dp" android:paddingBottom="16dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior" /> app:layout_behavior="@string/appbar_scrolling_view_behavior" />

View File

@@ -24,6 +24,7 @@
android:id="@+id/profileList" android:id="@+id/profileList"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
android:padding="16dp" android:padding="16dp"
android:scrollbars="vertical" /> android:scrollbars="vertical" />

View File

@@ -14,6 +14,9 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/container" android:id="@+id/container"
android:clipToPadding="false"
android:padding="16dp"
android:clipChildren="false"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />

View File

@@ -23,6 +23,7 @@
android:id="@+id/logView" android:id="@+id/logView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
android:padding="16dp" android:padding="16dp"
android:visibility="gone" /> android:visibility="gone" />

View File

@@ -15,6 +15,31 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/import_from_file"
android:layout_width="match_parent"
android:layout_height="64dp"
android:background="?selectableItemBackground"
android:orientation="horizontal">
<ImageView
android:layout_width="64dp"
android:padding="18dp"
app:tint="?colorControlNormal"
android:layout_height="match_parent"
android:src="@drawable/ic_baseline_file_open_24" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceListItem"
android:text="@string/profile_add_import_file"
android:gravity="center_vertical"
android:layout_height="match_parent">
</TextView>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/scan_qr_code" android:id="@+id/scan_qr_code"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -32,7 +57,7 @@
<TextView <TextView
android:layout_width="0dp" android:layout_width="0dp"
android:layout_weight="1" android:layout_weight="1"
android:textSize="16sp" android:textAppearance="?android:attr/textAppearanceListItem"
android:text="@string/profile_add_scan_qr_code" android:text="@string/profile_add_scan_qr_code"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_height="match_parent"> android:layout_height="match_parent">
@@ -57,7 +82,7 @@
<TextView <TextView
android:layout_width="0dp" android:layout_width="0dp"
android:layout_weight="1" android:layout_weight="1"
android:textSize="16sp" android:textAppearance="?android:attr/textAppearanceListItem"
android:text="@string/profile_add_create_manually" android:text="@string/profile_add_create_manually"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_height="match_parent"> android:layout_height="match_parent">

View File

@@ -6,8 +6,8 @@
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:layout_marginBottom="16dp"
android:padding="16dp"> android:orientation="vertical">
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewElevatedStyle" style="?attr/materialCardViewElevatedStyle"

View File

@@ -4,6 +4,7 @@
style="?attr/preferenceFragmentListStyle" style="?attr/preferenceFragmentListStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingTop="0dp" android:paddingTop="0dp"
android:paddingBottom="0dp" /> android:paddingBottom="0dp" />

View File

@@ -41,6 +41,7 @@
<string name="profile_source_create_new">Create New</string> <string name="profile_source_create_new">Create New</string>
<string name="profile_source_import">Import</string> <string name="profile_source_import">Import</string>
<string name="profile_add_import_file">Import from file</string>
<string name="profile_add_scan_qr_code">Scan QR code</string> <string name="profile_add_scan_qr_code">Scan QR code</string>
<string name="profile_add_scan_use_front_camera">Front camera</string> <string name="profile_add_scan_use_front_camera">Front camera</string>
<string name="profile_add_scan_use_vendor_analyzer">MLKit analyzer</string> <string name="profile_add_scan_use_vendor_analyzer">MLKit analyzer</string>