Add import profile from file
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
12
app/src/main/res/drawable/ic_baseline_file_open_24.xml
Normal file
12
app/src/main/res/drawable/ic_baseline_file_open_24.xml
Normal 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>
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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" />
|
||||||
|
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user