Standardise HTTP action
* Rename IAction uses to simplify code * Renamed SimpleIntentIAction to IntentAction * Renamed IntentAction#executeForIntent to createIntent * Added suspend modifier to IAction#execute to simplify later work * Added parseAndNormalizeUri * Optimized usage of Coroutines in WifiAction * Replaced one java Pattern instance with Kotlin Regex * Simplify DecodeFragment#openUrl by moving stuff into it's own action * Added OpenOrSearchAction * Added WebAction * Added DEFAULT_ACTION * IgnoreCase in SchemeAction
This commit is contained in:
@@ -2,18 +2,22 @@ package de.markusfisch.android.binaryeye.actions
|
||||
|
||||
import de.markusfisch.android.binaryeye.actions.mail.MailAction
|
||||
import de.markusfisch.android.binaryeye.actions.otpauth.OtpauthAction
|
||||
import de.markusfisch.android.binaryeye.actions.search.OpenOrSearchAction
|
||||
import de.markusfisch.android.binaryeye.actions.sms.SmsAction
|
||||
import de.markusfisch.android.binaryeye.actions.tel.TelAction
|
||||
import de.markusfisch.android.binaryeye.actions.vtype.vcard.VCardAction
|
||||
import de.markusfisch.android.binaryeye.actions.vtype.vevent.VEventAction
|
||||
import de.markusfisch.android.binaryeye.actions.web.WebAction
|
||||
import de.markusfisch.android.binaryeye.actions.wifi.WifiAction
|
||||
|
||||
object ActionRegistry {
|
||||
val DEFAULT_ACTION: IAction = OpenOrSearchAction
|
||||
|
||||
val REGISTRY: Set<IAction> = setOf(
|
||||
MailAction, OtpauthAction, SmsAction, TelAction, VCardAction, VEventAction, WifiAction
|
||||
MailAction, OtpauthAction, SmsAction, TelAction, VCardAction, VEventAction, WebAction, WifiAction
|
||||
)
|
||||
|
||||
fun getAction(data: ByteArray): IAction? = REGISTRY.find {
|
||||
fun getAction(data: ByteArray): IAction = REGISTRY.find {
|
||||
it.canExecuteOn(data)
|
||||
}
|
||||
} ?: DEFAULT_ACTION
|
||||
}
|
||||
|
||||
@@ -4,21 +4,22 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import de.markusfisch.android.binaryeye.app.execShareIntent
|
||||
import de.markusfisch.android.binaryeye.app.parseAndNormalizeUri
|
||||
|
||||
interface IAction {
|
||||
val iconResId: Int
|
||||
val titleResId: Int
|
||||
|
||||
fun canExecuteOn(data: ByteArray): Boolean
|
||||
fun execute(context: Context, data: ByteArray)
|
||||
suspend fun execute(context: Context, data: ByteArray)
|
||||
}
|
||||
|
||||
abstract class SimpleIntentIAction : IAction {
|
||||
abstract class IntentAction : IAction {
|
||||
abstract val errorMsg: Int
|
||||
|
||||
final override fun execute(context: Context, data: ByteArray) {
|
||||
final override suspend fun execute(context: Context, data: ByteArray) {
|
||||
val intent =
|
||||
executeForIntent(context, data) ?: return Toast.makeText(
|
||||
createIntent(context, data) ?: return Toast.makeText(
|
||||
context,
|
||||
errorMsg,
|
||||
Toast.LENGTH_LONG
|
||||
@@ -26,11 +27,25 @@ abstract class SimpleIntentIAction : IAction {
|
||||
execShareIntent(context, intent)
|
||||
}
|
||||
|
||||
abstract fun executeForIntent(context: Context, data: ByteArray): Intent?
|
||||
abstract suspend fun createIntent(context: Context, data: ByteArray): Intent?
|
||||
}
|
||||
|
||||
fun IAction?.validateOrGetNew(data: ByteArray): IAction? {
|
||||
return this?.takeIf {
|
||||
canExecuteOn(data)
|
||||
} ?: ActionRegistry.getAction(data)
|
||||
abstract class SchemeAction : IAction {
|
||||
abstract val scheme: String
|
||||
open val intentAction: String = Intent.ACTION_VIEW
|
||||
open val buildRegex: Boolean = false
|
||||
|
||||
final override fun canExecuteOn(data: ByteArray): Boolean {
|
||||
val content = String(data)
|
||||
return if (buildRegex) {
|
||||
content.matches("""^$scheme://[\w\W]+$""".toRegex(RegexOption.IGNORE_CASE))
|
||||
} else {
|
||||
content.startsWith("$scheme://", ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
final override suspend fun execute(context: Context, data: ByteArray) {
|
||||
val uri = parseAndNormalizeUri(String(data))
|
||||
execShareIntent(context, Intent(intentAction, uri))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
|
||||
object MailAction : SimpleIntentIAction() {
|
||||
object MailAction : IntentAction() {
|
||||
private val mailRegex =
|
||||
"""^mail(?:to)?:([\w.%+-]+@[A-Za-z\d.-]+\.[A-Za-z]{2,6}(?:[?&](?:subject|body)=[\S\s]*?){0,2})$""".toRegex()
|
||||
|
||||
@@ -18,7 +18,7 @@ object MailAction : SimpleIntentIAction() {
|
||||
return String(data).matches(mailRegex)
|
||||
}
|
||||
|
||||
override fun executeForIntent(context: Context, data: ByteArray): Intent? {
|
||||
override suspend fun createIntent(context: Context, data: ByteArray): Intent? {
|
||||
val mailWithMessage = mailRegex.matchEntire(
|
||||
String(data)
|
||||
)?.groupValues?.get(1) ?: return null
|
||||
|
||||
+3
-3
@@ -3,9 +3,9 @@ package de.markusfisch.android.binaryeye.actions.otpauth
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
|
||||
object OtpauthAction : SimpleIntentIAction() {
|
||||
object OtpauthAction : IntentAction() {
|
||||
override val iconResId: Int = R.drawable.ic_action_otpauth
|
||||
override val titleResId: Int = R.string.otpauth_add
|
||||
override val errorMsg: Int = R.string.otpauth_error
|
||||
@@ -14,7 +14,7 @@ object OtpauthAction : SimpleIntentIAction() {
|
||||
return OtpauthParser(String(data)) != null
|
||||
}
|
||||
|
||||
override fun executeForIntent(context: Context, data: ByteArray): Intent? {
|
||||
override suspend fun createIntent(context: Context, data: ByteArray): Intent? {
|
||||
return OtpauthParser(String(data))?.let {
|
||||
Intent(Intent.ACTION_VIEW, it.uri)
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package de.markusfisch.android.binaryeye.actions.search
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.IAction
|
||||
import de.markusfisch.android.binaryeye.app.execShareIntent
|
||||
import de.markusfisch.android.binaryeye.app.parseAndNormalizeUri
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import java.net.URLEncoder
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
object OpenOrSearchAction : IAction {
|
||||
override val iconResId: Int = R.drawable.ic_action_search
|
||||
override val titleResId: Int = R.string.search_web
|
||||
|
||||
override fun canExecuteOn(data: ByteArray): Boolean = false
|
||||
|
||||
override suspend fun execute(context: Context, data: ByteArray) {
|
||||
val intent = openUri(context, String(data)) ?: return
|
||||
execShareIntent(context, intent)
|
||||
}
|
||||
|
||||
private suspend fun openUri(context: Context, data: String, search: Boolean = true): Intent? {
|
||||
val uri = parseAndNormalizeUri(data)
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
when {
|
||||
intent.resolveActivity(context.packageManager) != null -> return intent
|
||||
search -> return getSearchIntent(context, data)
|
||||
else -> Toast.makeText(
|
||||
context,
|
||||
R.string.cannot_resolve_action,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private suspend fun getSearchIntent(context: Context, query: String): Intent? {
|
||||
val names = context.resources.getStringArray(
|
||||
R.array.search_engines_names
|
||||
).toMutableList()
|
||||
val urls = context.resources.getStringArray(
|
||||
R.array.search_engines_values
|
||||
).toMutableList()
|
||||
if (prefs.openWithUrl.isNotEmpty()) {
|
||||
names.add(prefs.openWithUrl)
|
||||
urls.add(prefs.openWithUrl)
|
||||
}
|
||||
val queryUri = suspendCoroutine<String?> { continuation ->
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle(R.string.pick_search_engine)
|
||||
.setItems(names.toTypedArray()) { _, which ->
|
||||
continuation.resume(urls[which] + URLEncoder.encode(query, "utf-8"))
|
||||
}
|
||||
.setOnCancelListener {
|
||||
continuation.resume(null)
|
||||
}
|
||||
.show()
|
||||
} ?: return null
|
||||
return openUri(context, queryUri, false)
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
|
||||
object SmsAction : SimpleIntentIAction() {
|
||||
object SmsAction : IntentAction() {
|
||||
private val smsRegex =
|
||||
"""^sms(?:to)?:(\+?[0-9]+)(?::([\S\s]*))?$""".toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
@@ -18,7 +18,7 @@ object SmsAction : SimpleIntentIAction() {
|
||||
return String(data).matches(smsRegex)
|
||||
}
|
||||
|
||||
override fun executeForIntent(context: Context, data: ByteArray): Intent? {
|
||||
override suspend fun createIntent(context: Context, data: ByteArray): Intent? {
|
||||
val (number: String, message: String) = smsRegex.matchEntire(
|
||||
String(data)
|
||||
)?.let {
|
||||
|
||||
@@ -2,11 +2,11 @@ package de.markusfisch.android.binaryeye.actions.tel
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
import de.markusfisch.android.binaryeye.app.parseAndNormalizeUri
|
||||
|
||||
object TelAction : SimpleIntentIAction() {
|
||||
object TelAction : IntentAction() {
|
||||
private val telRegex = """^tel:(\+?[0-9]+)$""".toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
override val iconResId: Int = R.drawable.ic_action_tel
|
||||
@@ -17,7 +17,7 @@ object TelAction : SimpleIntentIAction() {
|
||||
return String(data).matches(telRegex)
|
||||
}
|
||||
|
||||
override fun executeForIntent(context: Context, data: ByteArray): Intent {
|
||||
return Intent(Intent.ACTION_DIAL, Uri.parse(String(data)))
|
||||
override suspend fun createIntent(context: Context, data: ByteArray): Intent {
|
||||
return Intent(Intent.ACTION_DIAL, parseAndNormalizeUri(String(data)))
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -6,10 +6,10 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.provider.ContactsContract
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
import de.markusfisch.android.binaryeye.actions.vtype.VTypeParser
|
||||
|
||||
object VCardAction : SimpleIntentIAction() {
|
||||
object VCardAction : IntentAction() {
|
||||
override val iconResId: Int
|
||||
get() = R.drawable.ic_action_vcard
|
||||
override val titleResId: Int
|
||||
@@ -21,7 +21,7 @@ object VCardAction : SimpleIntentIAction() {
|
||||
return VTypeParser.parseVType(String(data)) == "VCARD"
|
||||
}
|
||||
|
||||
override fun executeForIntent(context: Context, data: ByteArray): Intent? {
|
||||
override suspend fun createIntent(context: Context, data: ByteArray): Intent? {
|
||||
val info = VTypeParser.parseMap(String(data))
|
||||
|
||||
return Intent(Intent.ACTION_INSERT_OR_EDIT).apply {
|
||||
|
||||
+4
-4
@@ -7,12 +7,12 @@ import android.os.Build
|
||||
import android.provider.CalendarContract
|
||||
import android.support.annotation.RequiresApi
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.SimpleIntentIAction
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
import de.markusfisch.android.binaryeye.actions.vtype.VTypeParser
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
object VEventAction : SimpleIntentIAction() {
|
||||
object VEventAction : IntentAction() {
|
||||
override val iconResId: Int
|
||||
get() = R.drawable.ic_action_vevent
|
||||
override val titleResId: Int
|
||||
@@ -26,7 +26,7 @@ object VEventAction : SimpleIntentIAction() {
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
override fun executeForIntent(context: Context, data: ByteArray): Intent? {
|
||||
override suspend fun createIntent(context: Context, data: ByteArray): Intent? {
|
||||
val info = VTypeParser.parseMap(String(data))
|
||||
|
||||
return Intent(Intent.ACTION_EDIT).apply {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.markusfisch.android.binaryeye.actions.web
|
||||
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.SchemeAction
|
||||
|
||||
object WebAction : SchemeAction() {
|
||||
override val iconResId: Int = R.drawable.ic_action_open
|
||||
override val titleResId: Int = R.string.open_url
|
||||
override val scheme: String = "https?"
|
||||
override val buildRegex: Boolean = true
|
||||
}
|
||||
@@ -7,7 +7,10 @@ import android.net.wifi.WifiManager
|
||||
import android.widget.Toast
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.IAction
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
|
||||
object WifiAction : IAction {
|
||||
override val iconResId = R.drawable.ic_action_wifi
|
||||
@@ -16,31 +19,29 @@ object WifiAction : IAction {
|
||||
override fun canExecuteOn(data: ByteArray): Boolean =
|
||||
WifiConfigurationFactory.parse(String(data)) != null
|
||||
|
||||
override fun execute(context: Context, data: ByteArray) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val wifiConfig = WifiConfigurationFactory.parse(
|
||||
String(data)
|
||||
) ?: return@launch
|
||||
val wifiManager = context.applicationContext.getSystemService(
|
||||
WIFI_SERVICE
|
||||
) as WifiManager
|
||||
override suspend fun execute(context: Context, data: ByteArray) = withContext(Dispatchers.IO) {
|
||||
val wifiConfig = WifiConfigurationFactory.parse(
|
||||
String(data)
|
||||
) ?: return@withContext
|
||||
val wifiManager = context.applicationContext.getSystemService(
|
||||
WIFI_SERVICE
|
||||
) as WifiManager
|
||||
|
||||
wifiManager.enableWifi(context)
|
||||
wifiManager.mayRemoveOldNetwork(wifiConfig)
|
||||
wifiManager.enableNewNetwork(wifiConfig)
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.wifi_added,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
wifiManager.enableWifi(context)
|
||||
wifiManager.mayRemoveOldNetwork(wifiConfig)
|
||||
wifiManager.enableNewNetwork(wifiConfig)
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.wifi_added,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun WifiManager.enableWifi(context: Context): Boolean {
|
||||
if (!this.isWifiEnabled) {
|
||||
if (!this.setWifiEnabled(true)) {
|
||||
if (!isWifiEnabled) {
|
||||
if (!setWifiEnabled(true)) {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
@@ -50,20 +51,18 @@ object WifiAction : IAction {
|
||||
}
|
||||
return false
|
||||
}
|
||||
var i = 0
|
||||
while (!this.isWifiEnabled) {
|
||||
if (i >= 10) {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.wifi_config_failed,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
return false
|
||||
// wait for wifi to really be enabled, takes some time
|
||||
withTimeoutOrNull(10000) {
|
||||
while (!isWifiEnabled) delay(500)
|
||||
} ?: if (!isWifiEnabled) {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.wifi_config_failed,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
delay(1000)
|
||||
i++
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -74,7 +73,7 @@ object WifiAction : IAction {
|
||||
) {
|
||||
configuredNetworks?.firstOrNull {
|
||||
it.SSID == wifiConfig.SSID &&
|
||||
it.allowedKeyManagement == wifiConfig.allowedKeyManagement
|
||||
it.allowedKeyManagement == wifiConfig.allowedKeyManagement
|
||||
}?.networkId?.also {
|
||||
removeNetwork(it)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import java.util.regex.Pattern
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
|
||||
private val nonPrintable = Pattern.compile("[\\x00-\\x08\\x0e-\\x1f]")
|
||||
private val nonPrintable = "[\\x00-\\x08\\x0e-\\x1f]".toRegex()
|
||||
|
||||
fun hasNonPrintableCharacters(s: String) = nonPrintable.matcher(s).find()
|
||||
fun hasNonPrintableCharacters(s: String) = nonPrintable.containsMatchIn(s)
|
||||
|
||||
fun parseAndNormalizeUri(input: String): Uri = Uri.parse(input).let {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) it.normalizeScheme() else it
|
||||
}
|
||||
|
||||
@@ -3,28 +3,35 @@ package de.markusfisch.android.binaryeye.fragment
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.support.v4.app.Fragment
|
||||
import android.text.ClipboardManager
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.*
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.IAction
|
||||
import de.markusfisch.android.binaryeye.actions.validateOrGetNew
|
||||
import de.markusfisch.android.binaryeye.app.*
|
||||
import de.markusfisch.android.binaryeye.actions.ActionRegistry
|
||||
import de.markusfisch.android.binaryeye.app.addFragment
|
||||
import de.markusfisch.android.binaryeye.app.hasNonPrintableCharacters
|
||||
import de.markusfisch.android.binaryeye.app.hasWritePermission
|
||||
import de.markusfisch.android.binaryeye.app.shareText
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URLEncoder
|
||||
|
||||
class DecodeFragment : Fragment() {
|
||||
private lateinit var contentView: EditText
|
||||
@@ -33,11 +40,14 @@ class DecodeFragment : Fragment() {
|
||||
private lateinit var format: BarcodeFormat
|
||||
private lateinit var actionMenuItem: MenuItem
|
||||
|
||||
private var action: IAction? = null
|
||||
private var action = ActionRegistry.DEFAULT_ACTION
|
||||
private var isBinary = false
|
||||
private val content: String
|
||||
get() = contentView.text.toString()
|
||||
|
||||
private val parentJob = Job()
|
||||
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Main + parentJob)
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
@@ -108,7 +118,10 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun updateViewsAndAction(bytes: ByteArray) {
|
||||
action = action.validateOrGetNew(bytes)
|
||||
val prevAction = action
|
||||
if (!prevAction.canExecuteOn(bytes)) {
|
||||
action = ActionRegistry.getAction(bytes)
|
||||
}
|
||||
formatView.text = resources.getQuantityString(
|
||||
R.plurals.barcode_info,
|
||||
bytes.size,
|
||||
@@ -116,19 +129,17 @@ class DecodeFragment : Fragment() {
|
||||
bytes.size
|
||||
)
|
||||
hexView.text = hexDump(bytes, 33)
|
||||
if (::actionMenuItem.isInitialized) {
|
||||
actionMenuItem.setIcon(action?.iconResId ?: R.drawable.ic_action_open)
|
||||
actionMenuItem.setTitle(action?.titleResId ?: R.string.open_url)
|
||||
if (::actionMenuItem.isInitialized && prevAction !== action) {
|
||||
actionMenuItem.setIcon(action.iconResId)
|
||||
actionMenuItem.setTitle(action.titleResId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.fragment_decode, menu)
|
||||
actionMenuItem = menu.findItem(R.id.open_url)
|
||||
action?.also { action ->
|
||||
actionMenuItem.setIcon(action.iconResId)
|
||||
actionMenuItem.setTitle(action.titleResId)
|
||||
}
|
||||
actionMenuItem.setIcon(action.iconResId)
|
||||
actionMenuItem.setTitle(action.titleResId)
|
||||
if (isBinary) {
|
||||
menu.findItem(R.id.copy_to_clipboard).isVisible = false
|
||||
menu.findItem(R.id.open_url).isVisible = false
|
||||
@@ -143,7 +154,7 @@ class DecodeFragment : Fragment() {
|
||||
true
|
||||
}
|
||||
R.id.open_url -> {
|
||||
openUrl(content)
|
||||
executeAction(content.toByteArray())
|
||||
true
|
||||
}
|
||||
R.id.create -> {
|
||||
@@ -171,56 +182,10 @@ class DecodeFragment : Fragment() {
|
||||
).show()
|
||||
}
|
||||
|
||||
private fun openUrl(
|
||||
url: String,
|
||||
executeCustomAction: Boolean = true,
|
||||
searchIfNoUrl: Boolean = true
|
||||
) {
|
||||
if (activity == null || url.isEmpty()) {
|
||||
return
|
||||
private fun executeAction(content: ByteArray) {
|
||||
if (activity != null && content.isNotEmpty()) scope.launch {
|
||||
action.execute(activity, content)
|
||||
}
|
||||
var uri = Uri.parse(url)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
uri = uri.normalizeScheme()
|
||||
}
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
when {
|
||||
executeCustomAction && action != null -> action?.also { action ->
|
||||
action.execute(activity, url.toByteArray())
|
||||
}
|
||||
intent.resolveActivity(activity.packageManager) != null -> {
|
||||
startActivity(intent)
|
||||
}
|
||||
searchIfNoUrl -> pickSearchEngineAndSearch(activity, url)
|
||||
else -> Toast.makeText(
|
||||
activity,
|
||||
R.string.cannot_resolve_action,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun pickSearchEngineAndSearch(context: Context, query: String) {
|
||||
val names = context.resources.getStringArray(
|
||||
R.array.search_engines_names
|
||||
).toMutableList()
|
||||
val urls = context.resources.getStringArray(
|
||||
R.array.search_engines_values
|
||||
).toMutableList()
|
||||
if (prefs.openWithUrl.isNotEmpty()) {
|
||||
names.add(prefs.openWithUrl)
|
||||
urls.add(prefs.openWithUrl)
|
||||
}
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle(R.string.pick_search_engine)
|
||||
.setItems(names.toTypedArray()) { _, which ->
|
||||
openUrl(
|
||||
urls[which] + URLEncoder.encode(query, "utf-8"),
|
||||
executeCustomAction = false,
|
||||
searchIfNoUrl = false
|
||||
)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
// dialogs don't have a parent layout and must therefore be
|
||||
@@ -249,6 +214,11 @@ class DecodeFragment : Fragment() {
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
parentJob.cancel()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CONTENT = "content"
|
||||
private const val FORMAT = "format"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp"
|
||||
android:tint="#FFFFFF" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="24dp">
|
||||
<path android:fillColor="#FF000000"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
</vector>
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">Konnte nicht zum Kalender hinzufügen</string>
|
||||
<string name="otpauth_add">2FA hinzufügen</string>
|
||||
<string name="otpauth_error">Konnte 2FA nicht hinzufügen</string>
|
||||
<string name="search_web">Suche im Internet</string>
|
||||
</resources>
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">Could not add to calendar</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">Could not add to calendar</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">Tidak bisa menambahkan ke kalender</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">Could not add to calendar</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">Could not add to calendar</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">Não foi possível adicionar ao calendário</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
@@ -55,4 +55,5 @@
|
||||
<string name="otpauth_add">Добавить 2FA</string>
|
||||
<string name="otpauth_error">Не удалось добавить 2FA</string>
|
||||
<string name="app_name">Binary Eye</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">无法添加到日历</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="open_with_url">Preferences</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
@@ -57,4 +57,5 @@
|
||||
<string name="vevent_failed">Could not add to calendar</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
</resources>
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip
|
||||
|
||||
Reference in New Issue
Block a user