Refactor QR code and file chooser handling in activities
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
package com.v2ray.ang.helper
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.v2ray.ang.ui.ScannerActivity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for scanning QR codes.
|
||||||
|
*
|
||||||
|
* This class encapsulates the logic for launching the QR code scanner activity
|
||||||
|
* and handling the scan result.
|
||||||
|
*/
|
||||||
|
class QRCodeScannerHelper(private val activity: AppCompatActivity) {
|
||||||
|
private var scanCallback: ((String?) -> Unit)? = null
|
||||||
|
|
||||||
|
private val scanLauncher: ActivityResultLauncher<Intent> =
|
||||||
|
activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
if (result.resultCode == AppCompatActivity.RESULT_OK) {
|
||||||
|
val scanResult = result.data?.getStringExtra("SCAN_RESULT")
|
||||||
|
scanCallback?.invoke(scanResult)
|
||||||
|
} else {
|
||||||
|
scanCallback?.invoke(null)
|
||||||
|
}
|
||||||
|
scanCallback = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch the QR code scanner activity.
|
||||||
|
*
|
||||||
|
* @param onResult Callback invoked with the scan result (null if cancelled or failed)
|
||||||
|
*/
|
||||||
|
fun launch(onResult: (String?) -> Unit) {
|
||||||
|
scanCallback = onResult
|
||||||
|
scanLauncher.launch(Intent(activity, ScannerActivity::class.java))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -188,9 +188,7 @@ class BackupActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreViaLocal() {
|
private fun restoreViaLocal() {
|
||||||
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
showFileChooser()
|
||||||
showFileChooser()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun backupViaWebDav() {
|
private fun backupViaWebDav() {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.v2ray.ang.util.MyContextWrapper
|
|||||||
import com.v2ray.ang.dto.PermissionType
|
import com.v2ray.ang.dto.PermissionType
|
||||||
import com.v2ray.ang.helper.FileChooserHelper
|
import com.v2ray.ang.helper.FileChooserHelper
|
||||||
import com.v2ray.ang.helper.PermissionHelper
|
import com.v2ray.ang.helper.PermissionHelper
|
||||||
|
import com.v2ray.ang.helper.QRCodeScannerHelper
|
||||||
import com.v2ray.ang.util.Utils
|
import com.v2ray.ang.util.Utils
|
||||||
|
|
||||||
|
|
||||||
@@ -42,11 +43,13 @@ abstract class BaseActivity : AppCompatActivity() {
|
|||||||
private var progressBar: LinearProgressIndicator? = null
|
private var progressBar: LinearProgressIndicator? = null
|
||||||
private lateinit var fileChooser : FileChooserHelper
|
private lateinit var fileChooser : FileChooserHelper
|
||||||
private lateinit var permissionRequester : PermissionHelper
|
private lateinit var permissionRequester : PermissionHelper
|
||||||
|
private lateinit var qrCodeScanner : QRCodeScannerHelper
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
fileChooser = FileChooserHelper(this)
|
fileChooser = FileChooserHelper(this)
|
||||||
permissionRequester = PermissionHelper(this)
|
permissionRequester = PermissionHelper(this)
|
||||||
|
qrCodeScanner = QRCodeScannerHelper(this)
|
||||||
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
if (!Utils.getDarkModeStatus(this)) {
|
if (!Utils.getDarkModeStatus(this)) {
|
||||||
@@ -247,6 +250,20 @@ abstract class BaseActivity : AppCompatActivity() {
|
|||||||
mimeType: String = "*/*",
|
mimeType: String = "*/*",
|
||||||
onResult: (Uri?) -> Unit
|
onResult: (Uri?) -> Unit
|
||||||
) {
|
) {
|
||||||
fileChooser.launch(mimeType, onResult)
|
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
||||||
|
fileChooser.launch(mimeType, onResult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch QR code scanner with camera permission check.
|
||||||
|
* Convenience method that delegates to qrCodeScanner helper.
|
||||||
|
*
|
||||||
|
* @param onResult Callback invoked with the scan result string (null if cancelled or failed)
|
||||||
|
*/
|
||||||
|
protected fun launchQRCodeScanner(onResult: (String?) -> Unit) {
|
||||||
|
checkAndRequestPermission(PermissionType.CAMERA) {
|
||||||
|
qrCodeScanner.launch(onResult)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,12 +64,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val scanQRCodeForConfig = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
|
||||||
if (it.resultCode == RESULT_OK) {
|
|
||||||
importBatchConfig(it.data?.getStringExtra("SCAN_RESULT"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
@@ -370,8 +364,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
* import config from qrcode
|
* import config from qrcode
|
||||||
*/
|
*/
|
||||||
private fun importQRcode(): Boolean {
|
private fun importQRcode(): Boolean {
|
||||||
checkAndRequestPermission(PermissionType.CAMERA) {
|
launchQRCodeScanner { scanResult ->
|
||||||
scanQRCodeForConfig.launch(Intent(this, ScannerActivity::class.java))
|
if (scanResult != null) {
|
||||||
|
importBatchConfig(scanResult)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -425,9 +421,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
*/
|
*/
|
||||||
private fun importConfigLocal(): Boolean {
|
private fun importConfigLocal(): Boolean {
|
||||||
try {
|
try {
|
||||||
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
showFileChooser()
|
||||||
showFileChooser()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(AppConfig.TAG, "Failed to import config from local file", e)
|
Log.e(AppConfig.TAG, "Failed to import config from local file", e)
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.os.Bundle
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@@ -150,8 +149,10 @@ class RoutingSettingActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun importQRcode(): Boolean {
|
private fun importQRcode(): Boolean {
|
||||||
checkAndRequestPermission(PermissionType.CAMERA) {
|
launchQRCodeScanner { scanResult ->
|
||||||
scanQRcodeForRulesets.launch(Intent(this, ScannerActivity::class.java))
|
if (scanResult != null) {
|
||||||
|
importRulesetsFromQRcode(scanResult)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -166,11 +167,6 @@ class RoutingSettingActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val scanQRcodeForRulesets = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
|
||||||
if (it.resultCode == RESULT_OK) {
|
|
||||||
importRulesetsFromQRcode(it.data?.getStringExtra("SCAN_RESULT"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun importRulesetsFromQRcode(qrcode: String?): Boolean {
|
private fun importRulesetsFromQRcode(qrcode: String?): Boolean {
|
||||||
AlertDialog.Builder(this).setMessage(R.string.routing_settings_import_rulesets_tip)
|
AlertDialog.Builder(this).setMessage(R.string.routing_settings_import_rulesets_tip)
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ package com.v2ray.ang.ui
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.extension.toastError
|
import com.v2ray.ang.extension.toastError
|
||||||
import com.v2ray.ang.extension.toastSuccess
|
import com.v2ray.ang.extension.toastSuccess
|
||||||
import com.v2ray.ang.handler.AngConfigManager
|
import com.v2ray.ang.handler.AngConfigManager
|
||||||
import com.v2ray.ang.dto.PermissionType
|
|
||||||
|
|
||||||
class ScScannerActivity : BaseActivity() {
|
class ScScannerActivity : BaseActivity() {
|
||||||
|
|
||||||
@@ -17,26 +15,20 @@ class ScScannerActivity : BaseActivity() {
|
|||||||
importQRcode()
|
importQRcode()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun importQRcode(): Boolean {
|
private fun importQRcode() {
|
||||||
checkAndRequestPermission(PermissionType.CAMERA) {
|
launchQRCodeScanner { scanResult ->
|
||||||
scanQRCode.launch(Intent(this, ScannerActivity::class.java))
|
if (scanResult != null) {
|
||||||
}
|
val (count, countSub) = AngConfigManager.importBatchConfig(scanResult, "", false)
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private val scanQRCode = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
if (count + countSub > 0) {
|
||||||
if (it.resultCode == RESULT_OK) {
|
toastSuccess(R.string.toast_success)
|
||||||
val scanResult = it.data?.getStringExtra("SCAN_RESULT").orEmpty()
|
} else {
|
||||||
val (count, countSub) = AngConfigManager.importBatchConfig(scanResult, "", false)
|
toastError(R.string.toast_failure)
|
||||||
|
}
|
||||||
|
|
||||||
if (count + countSub > 0) {
|
startActivity(Intent(this, MainActivity::class.java))
|
||||||
toastSuccess(R.string.toast_success)
|
|
||||||
} else {
|
|
||||||
toastError(R.string.toast_failure)
|
|
||||||
}
|
}
|
||||||
|
finish()
|
||||||
startActivity(Intent(this, MainActivity::class.java))
|
|
||||||
}
|
}
|
||||||
finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,9 +72,7 @@ class ScannerActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.select_photo -> {
|
R.id.select_photo -> {
|
||||||
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
showFileChooser()
|
||||||
showFileChooser()
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import android.provider.OpenableColumns
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@@ -91,12 +90,6 @@ class UserAssetActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showFileChooser() {
|
private fun showFileChooser() {
|
||||||
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
|
||||||
showFileChooser2()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showFileChooser2() {
|
|
||||||
launchFileChooser { uri ->
|
launchFileChooser { uri ->
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
return@launchFileChooser
|
return@launchFileChooser
|
||||||
@@ -148,17 +141,14 @@ class UserAssetActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun importAssetFromQRcode(): Boolean {
|
private fun importAssetFromQRcode(): Boolean {
|
||||||
checkAndRequestPermission(PermissionType.CAMERA) {
|
launchQRCodeScanner { scanResult ->
|
||||||
scanQRCodeForAssetURL.launch(Intent(this, ScannerActivity::class.java))
|
if (scanResult != null) {
|
||||||
|
importAsset(scanResult)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private val scanQRCodeForAssetURL = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
|
||||||
if (it.resultCode == RESULT_OK) {
|
|
||||||
importAsset(it.data?.getStringExtra("SCAN_RESULT"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun importAsset(url: String?): Boolean {
|
private fun importAsset(url: String?): Boolean {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user