Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecccf34418 | ||
|
|
4027ce2cc6 | ||
|
|
209e6c5c30 | ||
|
|
5e29f3fbe9 | ||
|
|
ba3d63277a | ||
|
|
fe34b7209d | ||
|
|
0efdca7b4a | ||
|
|
827fbedc1f | ||
|
|
107b5bafd4 | ||
|
|
19a71480fa | ||
|
|
909e97a591 | ||
|
|
bc2be96871 | ||
|
|
d834621d99 | ||
|
|
ad83be1a60 | ||
|
|
d65ea02b49 | ||
|
|
c8d1357ceb | ||
|
|
4c05d046e6 | ||
|
|
4423ee62c8 | ||
|
|
bc69f99f8b | ||
|
|
6b088031fd | ||
|
|
b27d03e9c0 | ||
|
|
9a13838f28 | ||
|
|
cce2a460f6 | ||
|
|
36352ecde2 | ||
|
|
9a0bc324cb | ||
|
|
6dabafd6a3 | ||
|
|
dde4b1e0bd | ||
|
|
8a8c7bd1ff | ||
|
|
a2aed42e25 | ||
|
|
a38b7b647f | ||
|
|
76e82ed842 | ||
|
|
fd54bc604e | ||
|
|
59b62ecbc4 | ||
|
|
de6a2863f3 | ||
|
|
4b2eb80612 | ||
|
|
2de40d2277 | ||
|
|
7673b7cb0d | ||
|
|
097c5e4453 | ||
|
|
1fab30089e | ||
|
|
f9bf16dd47 | ||
|
|
7a59126312 |
@@ -1,5 +1,28 @@
|
||||
# Change Log
|
||||
|
||||
## 1.68.7
|
||||
* Add icons to preferences screen
|
||||
* Update history listing on resume
|
||||
* Fix quiet zone for recreated barcodes
|
||||
* Fix automatic screen brightening
|
||||
* Migrate to CameraX
|
||||
|
||||
## 1.68.6
|
||||
* Update ZXingCpp
|
||||
* Ask for confirmation before deleting a scan from the result screen
|
||||
|
||||
## 1.68.5
|
||||
* Downgrade ZXingCpp for compatibilty
|
||||
|
||||
## 1.68.4
|
||||
* Fix generating 1D barcodes
|
||||
|
||||
## 1.68.3
|
||||
* Stability improvement
|
||||
|
||||
## 1.68.2
|
||||
* Fix barcode regeneration
|
||||
|
||||
## 1.68.1
|
||||
* Improve UI of search barcode dialog
|
||||
* Stability improvements
|
||||
|
||||
+13
-10
@@ -5,11 +5,11 @@ android {
|
||||
compileSdk sdk_version
|
||||
|
||||
defaultConfig {
|
||||
minSdk 9
|
||||
minSdk 21
|
||||
targetSdk sdk_version
|
||||
|
||||
versionCode 155
|
||||
versionName '1.68.1'
|
||||
versionCode 161
|
||||
versionName '1.68.7'
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
@@ -68,17 +68,20 @@ dependencies {
|
||||
// Kotlin
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2"
|
||||
implementation "androidx.core:core-ktx:1.17.0"
|
||||
|
||||
// Support
|
||||
implementation "com.android.support:appcompat-v7:$support_version"
|
||||
implementation "com.android.support:design:$support_version"
|
||||
implementation "com.android.support:preference-v7:$support_version"
|
||||
implementation "com.android.support:preference-v14:$support_version"
|
||||
implementation "androidx.appcompat:appcompat:1.7.1"
|
||||
implementation "com.google.android.material:material:1.13.0"
|
||||
implementation "androidx.preference:preference:1.2.1"
|
||||
|
||||
// External
|
||||
implementation 'com.github.markusfisch:CameraView:1.10.0'
|
||||
implementation 'com.github.markusfisch:ScalingImageView:1.4.1'
|
||||
implementation 'com.github.markusfisch:zxing-cpp:v3.0.1.0'
|
||||
implementation 'androidx.camera:camera-core:1.4.2'
|
||||
implementation 'androidx.camera:camera-camera2:1.4.2'
|
||||
implementation 'androidx.camera:camera-lifecycle:1.4.2'
|
||||
implementation 'androidx.camera:camera-view:1.4.2'
|
||||
implementation 'com.github.markusfisch:ScalingImageView:1.4.3'
|
||||
implementation 'com.github.markusfisch:zxing-cpp:v3.0.2.1'
|
||||
|
||||
// Testing
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
||||
Binary file not shown.
@@ -21,7 +21,7 @@
|
||||
<uses-feature android:name="android.hardware.camera"/>
|
||||
<uses-feature android:name="android.hardware.camera.autofocus"
|
||||
android:required="false" />
|
||||
<uses-sdk tools:overrideLibrary="android.support.v14.preference"/>
|
||||
<uses-sdk tools:overrideLibrary="androidx.preference"/>
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
@@ -112,7 +112,13 @@
|
||||
android:name=".activity.WelcomeActivity"
|
||||
android:exported="true"/>
|
||||
<activity
|
||||
android:name=".activity.MainActivity"
|
||||
android:name=".activity.PreferencesActivity"
|
||||
android:exported="true"/>
|
||||
<activity
|
||||
android:name=".activity.HistoryActivity"
|
||||
android:exported="true"/>
|
||||
<activity
|
||||
android:name=".activity.EncodeActivity"
|
||||
android:exported="true">
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
@@ -130,6 +136,21 @@
|
||||
<data android:scheme="binaryeye" android:host="encode"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.DecodeActivity"
|
||||
android:exported="false"/>
|
||||
<activity
|
||||
android:name=".activity.BarcodeActivity"
|
||||
android:exported="false"/>
|
||||
<activity
|
||||
android:name=".activity.ProfilesActivity"
|
||||
android:exported="false"/>
|
||||
<activity
|
||||
android:name=".activity.AutomatedActionsActivity"
|
||||
android:exported="false"/>
|
||||
<activity
|
||||
android:name=".activity.NetworkSuggestionsActivity"
|
||||
android:exported="false"/>
|
||||
<service
|
||||
android:name=".service.ScanTileService"
|
||||
android:icon="@drawable/ic_action_scan"
|
||||
@@ -142,7 +163,7 @@
|
||||
</intent-filter>
|
||||
</service>
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
|
||||
@@ -2,7 +2,7 @@ package de.markusfisch.android.binaryeye.actions.mail
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
|
||||
@@ -24,7 +24,7 @@ object MailAction : IntentAction() {
|
||||
)?.groupValues?.get(1) ?: return null
|
||||
return Intent(
|
||||
Intent.ACTION_SENDTO,
|
||||
Uri.parse("mailto:$mailWithMessage")
|
||||
"mailto:$mailWithMessage".toUri()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package de.markusfisch.android.binaryeye.actions.mail
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
|
||||
@@ -26,7 +26,7 @@ object MatMsgAction : IntentAction() {
|
||||
}
|
||||
return Intent(
|
||||
Intent.ACTION_SENDTO,
|
||||
Uri.parse("mailto:")
|
||||
"mailto:".toUri()
|
||||
).apply {
|
||||
mm.to?.let {
|
||||
putExtra(Intent.EXTRA_EMAIL, arrayOf(mm.to))
|
||||
|
||||
@@ -2,7 +2,7 @@ package de.markusfisch.android.binaryeye.actions.sms
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
|
||||
@@ -27,7 +27,7 @@ object SmsAction : IntentAction() {
|
||||
} ?: return null
|
||||
return Intent(
|
||||
Intent.ACTION_SENDTO,
|
||||
Uri.parse("smsto:$number")
|
||||
"smsto:$number".toUri()
|
||||
).apply {
|
||||
if (message.isNotEmpty()) {
|
||||
putExtra("sms_body", message)
|
||||
|
||||
+27
-30
@@ -3,7 +3,6 @@ package de.markusfisch.android.binaryeye.actions.vtype.vcard
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.provider.ContactsContract
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.IntentAction
|
||||
@@ -98,38 +97,36 @@ object VCardAction : IntentAction() {
|
||||
}
|
||||
putExtra(ContactsContract.Intents.Insert.POSTAL, addr.value.locationFormat)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
val urls = info["URL"]?.mapNotNull {
|
||||
it.value.takeIf { url -> url.isNotBlank() }?.let { url ->
|
||||
ContentValues(2).apply {
|
||||
put(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE
|
||||
)
|
||||
put(ContactsContract.CommonDataKinds.Website.URL, url)
|
||||
}
|
||||
val urls = info["URL"]?.mapNotNull {
|
||||
it.value.takeIf { url -> url.isNotBlank() }?.let { url ->
|
||||
ContentValues(2).apply {
|
||||
put(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE
|
||||
)
|
||||
put(ContactsContract.CommonDataKinds.Website.URL, url)
|
||||
}
|
||||
}
|
||||
val bDays = info["BDAY"]?.mapNotNull {
|
||||
it.value.takeIf { day -> day.isNotBlank() }?.let { day ->
|
||||
ContentValues(3).apply {
|
||||
put(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE
|
||||
)
|
||||
put(
|
||||
ContactsContract.CommonDataKinds.Event.TYPE,
|
||||
ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY
|
||||
)
|
||||
put(ContactsContract.CommonDataKinds.Event.START_DATE, day)
|
||||
}
|
||||
}
|
||||
}
|
||||
putParcelableArrayListExtra(
|
||||
ContactsContract.Intents.Insert.DATA,
|
||||
ArrayList(listOfNotNull(urls, bDays).flatten())
|
||||
)
|
||||
}
|
||||
val bDays = info["BDAY"]?.mapNotNull {
|
||||
it.value.takeIf { day -> day.isNotBlank() }?.let { day ->
|
||||
ContentValues(3).apply {
|
||||
put(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE
|
||||
)
|
||||
put(
|
||||
ContactsContract.CommonDataKinds.Event.TYPE,
|
||||
ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY
|
||||
)
|
||||
put(ContactsContract.CommonDataKinds.Event.START_DATE, day)
|
||||
}
|
||||
}
|
||||
}
|
||||
putParcelableArrayListExtra(
|
||||
ContactsContract.Intents.Insert.DATA,
|
||||
ArrayList(listOfNotNull(urls, bDays).flatten())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-6
@@ -2,9 +2,7 @@ package de.markusfisch.android.binaryeye.actions.vtype.vevent
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
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.IntentAction
|
||||
import de.markusfisch.android.binaryeye.actions.vtype.VTypeParser
|
||||
@@ -21,14 +19,10 @@ object VEventAction : IntentAction() {
|
||||
get() = R.string.vevent_failed
|
||||
|
||||
override fun canExecuteOn(data: ByteArray): Boolean {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return false
|
||||
}
|
||||
val type = VTypeParser.parseVType(String(data))
|
||||
return type == "VEVENT" || type == "VCALENDAR"
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
override suspend fun createIntent(context: Context, data: ByteArray): Intent? {
|
||||
val info = VTypeParser.parseMap(String(data))
|
||||
|
||||
|
||||
+17
-21
@@ -8,7 +8,7 @@ import android.net.wifi.WifiManager
|
||||
import android.net.wifi.WifiNetworkSuggestion
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.support.annotation.RequiresApi
|
||||
import androidx.annotation.RequiresApi
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
@@ -113,34 +113,30 @@ object WifiConnector {
|
||||
get() = inputMap["I"] ?: ""
|
||||
internal val eapMethod: Int?
|
||||
get() = if (inputMap["E"].isNullOrEmpty()) {
|
||||
requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
WifiEnterpriseConfig.Eap.NONE
|
||||
}
|
||||
WifiEnterpriseConfig.Eap.NONE
|
||||
} else when (inputMap["E"]?.uppercase()) {
|
||||
"AKA" -> requireSdk(Build.VERSION_CODES.LOLLIPOP) { WifiEnterpriseConfig.Eap.AKA }
|
||||
"AKA" -> WifiEnterpriseConfig.Eap.AKA
|
||||
"AKA_PRIME" -> requireSdk(Build.VERSION_CODES.M) { WifiEnterpriseConfig.Eap.AKA_PRIME }
|
||||
"NONE" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Eap.NONE }
|
||||
"PEAP" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Eap.PEAP }
|
||||
"PWD" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Eap.PWD }
|
||||
"SIM" -> requireSdk(Build.VERSION_CODES.LOLLIPOP) { WifiEnterpriseConfig.Eap.SIM }
|
||||
"TLS" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Eap.TLS }
|
||||
"TTLS" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Eap.TTLS }
|
||||
"NONE" -> WifiEnterpriseConfig.Eap.NONE
|
||||
"PEAP" -> WifiEnterpriseConfig.Eap.PEAP
|
||||
"PWD" -> WifiEnterpriseConfig.Eap.PWD
|
||||
"SIM" -> WifiEnterpriseConfig.Eap.SIM
|
||||
"TLS" -> WifiEnterpriseConfig.Eap.TLS
|
||||
"TTLS" -> WifiEnterpriseConfig.Eap.TTLS
|
||||
"UNAUTH_TLS" -> requireSdk(Build.VERSION_CODES.N) { WifiEnterpriseConfig.Eap.UNAUTH_TLS }
|
||||
else -> null
|
||||
}
|
||||
internal val phase2Method: Int?
|
||||
get() = if (inputMap["PH2"].isNullOrEmpty()) {
|
||||
requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
WifiEnterpriseConfig.Phase2.NONE
|
||||
}
|
||||
WifiEnterpriseConfig.Phase2.NONE
|
||||
} else when (inputMap["PH2"]?.uppercase()) {
|
||||
"AKA" -> requireSdk(Build.VERSION_CODES.O) { WifiEnterpriseConfig.Phase2.AKA }
|
||||
"AKA_PRIME" -> requireSdk(Build.VERSION_CODES.O) { WifiEnterpriseConfig.Phase2.AKA_PRIME }
|
||||
"GTC" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Phase2.GTC }
|
||||
"MSCHAP" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Phase2.MSCHAP }
|
||||
"MSCHAPV2" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Phase2.MSCHAPV2 }
|
||||
"NONE" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Phase2.NONE }
|
||||
"PAP" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) { WifiEnterpriseConfig.Phase2.PAP }
|
||||
"GTC" -> WifiEnterpriseConfig.Phase2.GTC
|
||||
"MSCHAP" -> WifiEnterpriseConfig.Phase2.MSCHAP
|
||||
"MSCHAPV2" -> WifiEnterpriseConfig.Phase2.MSCHAPV2
|
||||
"NONE" -> WifiEnterpriseConfig.Phase2.NONE
|
||||
"PAP" -> WifiEnterpriseConfig.Phase2.PAP
|
||||
"SIM" -> requireSdk(Build.VERSION_CODES.O) { WifiEnterpriseConfig.Phase2.SIM }
|
||||
else -> null
|
||||
}
|
||||
@@ -265,7 +261,7 @@ object WifiConnector {
|
||||
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP)
|
||||
}
|
||||
|
||||
"WPA2-EAP" -> requireSdk(Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
"WPA2-EAP" -> {
|
||||
passwordWithQuotes?.let {
|
||||
preSharedKey = it
|
||||
} ?: return null
|
||||
@@ -285,7 +281,7 @@ object WifiConnector {
|
||||
data.eapMethod ?: return null // non valid eapMethod
|
||||
enterpriseConfig.phase2Method =
|
||||
data.phase2Method ?: return null // non valid phase2Method
|
||||
} ?: return null // api isn't high enough
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
+13
-22
@@ -1,11 +1,9 @@
|
||||
package de.markusfisch.android.binaryeye.fragment
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
@@ -19,31 +17,28 @@ import de.markusfisch.android.binaryeye.automation.AutomatedAction
|
||||
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
|
||||
import de.markusfisch.android.binaryeye.view.systemBarListViewScrollListener
|
||||
|
||||
class AutomatedActionsFragment : Fragment() {
|
||||
class AutomatedActionsActivity : ScreenActivity() {
|
||||
private val actions = ArrayList<AutomatedAction>()
|
||||
|
||||
private lateinit var adapter: ActionsAdapter
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
state: Bundle?
|
||||
): View? {
|
||||
val ac = activity ?: return null
|
||||
ac.setTitle(R.string.automated_actions)
|
||||
|
||||
val view = inflater.inflate(
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setTitle(R.string.automated_actions)
|
||||
val frame = findViewById(R.id.content_frame) as ViewGroup
|
||||
val view = layoutInflater.inflate(
|
||||
R.layout.fragment_automated_actions,
|
||||
container,
|
||||
frame,
|
||||
false
|
||||
)
|
||||
frame.addView(view)
|
||||
|
||||
actions.clear()
|
||||
actions.addAll(prefs.automatedActions)
|
||||
|
||||
val listView = view.findViewById<ListView>(R.id.actions)
|
||||
listView.emptyView = view.findViewById(R.id.no_actions)
|
||||
adapter = ActionsAdapter(ac, actions)
|
||||
adapter = ActionsAdapter(this, actions)
|
||||
listView.adapter = adapter
|
||||
listView.setOnScrollListener(systemBarListViewScrollListener)
|
||||
listView.setOnItemClickListener { _, _, position, _ ->
|
||||
@@ -60,14 +55,11 @@ class AutomatedActionsFragment : Fragment() {
|
||||
|
||||
view.findViewById<View>(R.id.inset_layout).setPaddingFromWindowInsets()
|
||||
listView.setPaddingFromWindowInsets()
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private fun editAction(position: Int?) {
|
||||
val ac = activity ?: return
|
||||
val action = position?.let { actions[it] }
|
||||
val view = ac.layoutInflater.inflate(
|
||||
val view = layoutInflater.inflate(
|
||||
R.layout.dialog_automated_action,
|
||||
null
|
||||
)
|
||||
@@ -112,7 +104,7 @@ class AutomatedActionsFragment : Fragment() {
|
||||
typeGroup.check(initialTypeId)
|
||||
updateTypeSections(initialTypeId)
|
||||
|
||||
val dialog = AlertDialog.Builder(ac)
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
.setTitle(
|
||||
if (action == null) {
|
||||
R.string.automated_action_add
|
||||
@@ -207,8 +199,7 @@ class AutomatedActionsFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun confirmRemoveAction(position: Int) {
|
||||
val ac = activity ?: return
|
||||
AlertDialog.Builder(ac)
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(R.string.automated_action_remove_confirm)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
actions.removeAt(position)
|
||||
+53
-71
@@ -1,14 +1,13 @@
|
||||
package de.markusfisch.android.binaryeye.fragment
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Matrix
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
@@ -55,7 +54,7 @@ import java.util.Locale
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class BarcodeFragment : Fragment() {
|
||||
class BarcodeActivity : ScreenActivity() {
|
||||
private enum class FileType {
|
||||
PNG, JPG, SVG, TXT
|
||||
}
|
||||
@@ -65,36 +64,30 @@ class BarcodeFragment : Fragment() {
|
||||
|
||||
private lateinit var imageView: ConfinedScalingImageView
|
||||
private lateinit var barcode: Barcode<*>
|
||||
private lateinit var addToHistoryItem: MenuItem
|
||||
private lateinit var brightenScreenItem: MenuItem
|
||||
|
||||
private var contentView: View? = null
|
||||
private var addToHistoryItem: MenuItem? = null
|
||||
private var brightenScreenItem: MenuItem? = null
|
||||
private var currentBrightness = -1f
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
state: Bundle?
|
||||
): View? {
|
||||
val ac = activity ?: return null
|
||||
ac.setTitle(R.string.view_barcode)
|
||||
|
||||
val view = inflater.inflate(
|
||||
setTitle(R.string.view_barcode)
|
||||
val frame = findViewById(R.id.content_frame) as ViewGroup
|
||||
val view = layoutInflater.inflate(
|
||||
R.layout.fragment_barcode,
|
||||
container,
|
||||
frame,
|
||||
false
|
||||
)
|
||||
frame.addView(view)
|
||||
contentView = view
|
||||
|
||||
// Make `imageView` available for `onPause()`.
|
||||
imageView = view.findViewById(R.id.barcode)
|
||||
|
||||
val bitmap: Bitmap
|
||||
try {
|
||||
barcode = arguments?.toBarcode() ?: throw IllegalArgumentException(
|
||||
barcode = intent?.extras?.toBarcode() ?: throw IllegalArgumentException(
|
||||
"Illegal arguments"
|
||||
)
|
||||
// Catch exceptions from encoding.
|
||||
@@ -104,11 +97,9 @@ class BarcodeFragment : Fragment() {
|
||||
if (message.isNullOrEmpty()) {
|
||||
message = getString(R.string.error_encoding_barcode)
|
||||
}
|
||||
message?.let {
|
||||
ac.toast(message)
|
||||
}
|
||||
fragmentManager.popBackStack()
|
||||
return null
|
||||
toast(message)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
imageView.setImageBitmap(bitmap)
|
||||
@@ -140,8 +131,6 @@ class BarcodeFragment : Fragment() {
|
||||
imageView.doOnApplyWindowInsets { _, insets ->
|
||||
imageView.insets.set(insets)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private fun Bundle.toBarcode(): Barcode<*> {
|
||||
@@ -182,9 +171,9 @@ class BarcodeFragment : Fragment() {
|
||||
super.onResume()
|
||||
if (prefs.brightenScreen) {
|
||||
// Post to make sure brightenScreenItem is initialized.
|
||||
view?.post {
|
||||
contentView?.postDelayed({
|
||||
brightenScreen()
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,8 +187,8 @@ class BarcodeFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
parentJob.cancel()
|
||||
}
|
||||
|
||||
@@ -216,8 +205,8 @@ class BarcodeFragment : Fragment() {
|
||||
barcode.bitmap(),
|
||||
barcode.format
|
||||
)
|
||||
addToHistoryItem.isVisible = false
|
||||
context.toast(R.string.added_to_history)
|
||||
addToHistoryItem?.isVisible = false
|
||||
toast(R.string.added_to_history)
|
||||
true
|
||||
}
|
||||
|
||||
@@ -232,7 +221,7 @@ class BarcodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
R.id.export_to_file -> {
|
||||
context.pickFileType(R.string.export_as) { fileType ->
|
||||
pickFileType(R.string.export_as) { fileType ->
|
||||
when (fileType) {
|
||||
FileType.PNG,
|
||||
FileType.JPG -> askForSize { size ->
|
||||
@@ -261,10 +250,8 @@ class BarcodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun copyToClipboard(text: String, isSensitive: Boolean = false) {
|
||||
activity?.apply {
|
||||
copyToClipboard(text, isSensitive)
|
||||
toast(R.string.copied_to_clipboard)
|
||||
}
|
||||
(this as android.content.Context).copyToClipboard(text, isSensitive)
|
||||
toast(R.string.copied_to_clipboard)
|
||||
}
|
||||
|
||||
private fun deeplinkToCopy() = createEncodeDeeplink(
|
||||
@@ -288,21 +275,20 @@ class BarcodeFragment : Fragment() {
|
||||
// Dialogs do not have a parent view.
|
||||
@SuppressLint("InflateParams")
|
||||
private fun askForFileNameAndSave(fileType: FileType, bitmapSize: Int) {
|
||||
val ac = activity ?: return
|
||||
// Write permission is only required before Android Q.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
|
||||
!ac.hasWritePermission {
|
||||
!hasWritePermission {
|
||||
askForFileNameAndSave(fileType, bitmapSize)
|
||||
}
|
||||
) {
|
||||
return
|
||||
}
|
||||
val view = ac.layoutInflater.inflate(R.layout.dialog_save_file, null)
|
||||
val view = layoutInflater.inflate(R.layout.dialog_save_file, null)
|
||||
val editText = view.findViewById<EditText>(R.id.file_name)
|
||||
editText.setText(
|
||||
encodeFileName("${barcode.format}_${barcode.content}")
|
||||
)
|
||||
AlertDialog.Builder(ac)
|
||||
AlertDialog.Builder(this)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val fileName = editText.text.toString()
|
||||
@@ -344,12 +330,11 @@ class BarcodeFragment : Fragment() {
|
||||
// Dialogs do not have a parent view.
|
||||
@SuppressLint("InflateParams")
|
||||
private fun askForSize(write: (size: Int) -> Unit) {
|
||||
val ac = activity ?: return
|
||||
val view = ac.layoutInflater.inflate(R.layout.dialog_size, null)
|
||||
val view = layoutInflater.inflate(R.layout.dialog_size, null)
|
||||
val sizeView = view.findViewById<TextView>(R.id.size_display)
|
||||
val sizeBarView = view.findViewById<SeekBar>(R.id.size_bar)
|
||||
sizeBarView.initSizeBar(sizeView)
|
||||
AlertDialog.Builder(ac)
|
||||
AlertDialog.Builder(this)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
write(getSize(sizeBarView.progress))
|
||||
@@ -392,13 +377,12 @@ class BarcodeFragment : Fragment() {
|
||||
mimeType: String,
|
||||
write: (outputStream: OutputStream) -> Unit
|
||||
) {
|
||||
val ac = activity ?: return
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val message = ac.writeExternalFile(
|
||||
val message = writeExternalFile(
|
||||
fileName, mimeType, write
|
||||
).toSaveResult()
|
||||
withContext(Dispatchers.Main) {
|
||||
ac.toast(message)
|
||||
toast(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,21 +433,19 @@ class BarcodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun brightenScreen() {
|
||||
activity?.let {
|
||||
if (!isAdded) {
|
||||
return
|
||||
}
|
||||
currentBrightness = it.getScreenBrightness()
|
||||
it.setScreenBrightness(1f)
|
||||
brightenScreenItem.isChecked = true
|
||||
if (isFinishing || isDestroyed) {
|
||||
return
|
||||
}
|
||||
currentBrightness = getScreenBrightness()
|
||||
setScreenBrightness(1f)
|
||||
brightenScreenItem?.isChecked = true
|
||||
}
|
||||
|
||||
private fun restoreScreenBrightness() {
|
||||
if (currentBrightness > -1f && isAdded) {
|
||||
activity?.setScreenBrightness(currentBrightness)
|
||||
if (currentBrightness > -1f) {
|
||||
setScreenBrightness(currentBrightness)
|
||||
currentBrightness = -1f
|
||||
brightenScreenItem.isChecked = false
|
||||
brightenScreenItem?.isChecked = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,10 +464,11 @@ class BarcodeFragment : Fragment() {
|
||||
private const val MIME_SVG = "image/svg+xmg"
|
||||
private const val MIME_TXT = "text/plain"
|
||||
|
||||
fun newInstance(
|
||||
fun newIntent(
|
||||
context: Context,
|
||||
barcode: Barcode<*>,
|
||||
colors: Int = 0
|
||||
): Fragment {
|
||||
): Intent {
|
||||
val args = Bundle()
|
||||
when (barcode) {
|
||||
is ContentBarcode -> args.putEcLevelMargin(
|
||||
@@ -498,32 +481,31 @@ class BarcodeFragment : Fragment() {
|
||||
args.putInt(BIT_MATRIX_HEIGHT, barcode.bitMatrix.height)
|
||||
args.putByteArray(BIT_MATRIX_DATA, barcode.bitMatrix.data)
|
||||
}
|
||||
|
||||
else -> throw IllegalArgumentException("unknown barcode")
|
||||
}
|
||||
args.putContentFormatColors(
|
||||
barcode.content,
|
||||
barcode.format,
|
||||
colors
|
||||
)
|
||||
val fragment = BarcodeFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
return Intent(context, BarcodeActivity::class.java).apply {
|
||||
putExtras(args)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> newInstance(
|
||||
fun <T> newIntent(
|
||||
context: Context,
|
||||
content: T,
|
||||
format: BarcodeFormat,
|
||||
ecLevel: Int = -1,
|
||||
margin: Int = -1,
|
||||
margin: Int = 0,
|
||||
colors: Int = 0
|
||||
): Fragment {
|
||||
): Intent {
|
||||
val args = Bundle()
|
||||
args.putContentFormatColors(content, format, colors)
|
||||
args.putEcLevelMargin(ecLevel, margin)
|
||||
val fragment = BarcodeFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
return Intent(context, BarcodeActivity::class.java).apply {
|
||||
putExtras(args)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> Bundle.putContentFormatColors(
|
||||
@@ -8,18 +8,33 @@ import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Rect
|
||||
import android.hardware.Camera
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.FloatingActionButton
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewConfiguration
|
||||
import android.widget.EditText
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.camera.core.Camera
|
||||
import androidx.camera.core.CameraSelector
|
||||
import androidx.camera.core.FocusMeteringAction
|
||||
import androidx.camera.core.ImageAnalysis
|
||||
import androidx.camera.core.ImageProxy
|
||||
import androidx.camera.core.Preview
|
||||
import androidx.camera.core.TorchState
|
||||
import androidx.camera.core.resolutionselector.AspectRatioStrategy
|
||||
import androidx.camera.core.resolutionselector.ResolutionSelector
|
||||
import androidx.camera.core.resolutionselector.ResolutionStrategy
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.net.toUri
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.adapter.prettifyFormatName
|
||||
import de.markusfisch.android.binaryeye.app.PERMISSION_CAMERA
|
||||
@@ -49,7 +64,7 @@ import de.markusfisch.android.binaryeye.view.scanFeedback
|
||||
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
|
||||
import de.markusfisch.android.binaryeye.widget.DetectorView
|
||||
import de.markusfisch.android.binaryeye.widget.toast
|
||||
import de.markusfisch.android.cameraview.widget.CameraView
|
||||
import de.markusfisch.android.binaryeye.zxingcpp.migrateBarcodeFormatName
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.Binarizer
|
||||
@@ -58,19 +73,36 @@ import de.markusfisch.android.zxingcpp.ZxingCpp.Result
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.TextMode
|
||||
import java.io.FileInputStream
|
||||
import java.util.Scanner
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class CameraActivity : AppCompatActivity() {
|
||||
private val frameRoi = Rect()
|
||||
private val previewRect = Rect()
|
||||
private val viewBounds = Rect()
|
||||
private val matrix = Matrix()
|
||||
private val analyzerExecutor: ExecutorService =
|
||||
Executors.newSingleThreadExecutor()
|
||||
private val readerOptions = ReaderOptions(
|
||||
tryHarder = prefs.tryHarder,
|
||||
tryRotate = prefs.autoRotate,
|
||||
tryInvert = true,
|
||||
tryDownscale = true,
|
||||
maxNumberOfSymbols = 1,
|
||||
textMode = TextMode.PLAIN
|
||||
)
|
||||
|
||||
private lateinit var cameraView: CameraView
|
||||
private lateinit var cameraView: PreviewView
|
||||
private lateinit var detectorView: DetectorView
|
||||
private lateinit var zoomBar: SeekBar
|
||||
private lateinit var flashFab: FloatingActionButton
|
||||
|
||||
private var cameraProvider: ProcessCameraProvider? = null
|
||||
private var camera: Camera? = null
|
||||
private var currentProfile = prefs.profile
|
||||
private var shouldStoreSettings = true
|
||||
private var formatsToRead = setOf<BarcodeFormat>()
|
||||
@@ -84,19 +116,28 @@ class CameraActivity : AppCompatActivity() {
|
||||
private var restrictFormat: String? = null
|
||||
private var searchTerm: Regex? = null
|
||||
private var ignoreNext: String? = null
|
||||
private var fallbackBuffer: IntArray? = null
|
||||
private var requestCameraPermission = true
|
||||
private var useLocalAverage = false
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(
|
||||
requestCode,
|
||||
permissions,
|
||||
grantResults
|
||||
)
|
||||
when (requestCode) {
|
||||
PERMISSION_CAMERA -> if (grantResults.isNotEmpty() &&
|
||||
grantResults[0] != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
toast(R.string.camera_error)
|
||||
PERMISSION_CAMERA -> {
|
||||
if (grantResults.isNotEmpty() &&
|
||||
grantResults[0] != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
toast(R.string.camera_error)
|
||||
} else if (grantResults.isNotEmpty()) {
|
||||
bindCameraUseCases()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +147,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
resultCode: Int,
|
||||
resultData: Intent?
|
||||
) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
when (requestCode) {
|
||||
PICK_FILE_RESULT_CODE -> {
|
||||
if (resultCode == RESULT_OK && resultData != null) {
|
||||
@@ -133,12 +175,12 @@ class CameraActivity : AppCompatActivity() {
|
||||
|
||||
initBars()
|
||||
|
||||
cameraView = findViewById(R.id.camera_view) as CameraView
|
||||
detectorView = findViewById(R.id.detector_view) as DetectorView
|
||||
zoomBar = findViewById(R.id.zoom) as SeekBar
|
||||
flashFab = findViewById(R.id.flash) as FloatingActionButton
|
||||
cameraView = findViewById(R.id.camera_view)
|
||||
detectorView = findViewById(R.id.detector_view)
|
||||
zoomBar = findViewById(R.id.zoom)
|
||||
flashFab = findViewById(R.id.flash)
|
||||
|
||||
initCameraView()
|
||||
initPreviewView()
|
||||
initZoomBar()
|
||||
initDetectorView()
|
||||
|
||||
@@ -151,7 +193,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
fallbackBuffer = null
|
||||
analyzerExecutor.shutdown()
|
||||
releaseToneGenerators()
|
||||
}
|
||||
|
||||
@@ -171,7 +213,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
// for this session. Otherwise ActivityCompat.requestPermissions()
|
||||
// will trigger onResume() again and again.
|
||||
if (hasCameraPermission(requestCameraPermission)) {
|
||||
openCamera()
|
||||
bindCameraUseCases()
|
||||
}
|
||||
requestCameraPermission = false
|
||||
}
|
||||
@@ -181,7 +223,9 @@ class CameraActivity : AppCompatActivity() {
|
||||
if (prefs.defaultPreferences.getBoolean(welcomeShownName, false)) {
|
||||
return false
|
||||
}
|
||||
prefs.defaultPreferences.edit().putBoolean(welcomeShownName, true).apply()
|
||||
prefs.defaultPreferences.edit {
|
||||
putBoolean(welcomeShownName, true)
|
||||
}
|
||||
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
||||
val installedSince = System.currentTimeMillis() -
|
||||
packageInfo.firstInstallTime
|
||||
@@ -193,14 +237,9 @@ class CameraActivity : AppCompatActivity() {
|
||||
return false
|
||||
}
|
||||
shouldStoreSettings = false
|
||||
zoomBar.max = 0 // Reset zoom when there are no preferences yet.
|
||||
zoomBar.progress = INITIAL_ZOOM
|
||||
currentProfile = prefs.profile
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
recreate()
|
||||
} else {
|
||||
finish()
|
||||
startActivity(Intent(this, CameraActivity::class.java))
|
||||
}
|
||||
recreate()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -251,30 +290,19 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun openCamera() {
|
||||
cameraView.openAsync(
|
||||
CameraView.findCameraId(
|
||||
@Suppress("DEPRECATION")
|
||||
if (frontFacing) {
|
||||
Camera.CameraInfo.CAMERA_FACING_FRONT
|
||||
} else {
|
||||
Camera.CameraInfo.CAMERA_FACING_BACK
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
closeCamera()
|
||||
unbindCameraUseCases()
|
||||
if (shouldStoreSettings) {
|
||||
storeSettings()
|
||||
}
|
||||
shouldStoreSettings = true
|
||||
}
|
||||
|
||||
private fun closeCamera() {
|
||||
cameraView.close()
|
||||
private fun unbindCameraUseCases() {
|
||||
decoding = false
|
||||
cameraProvider?.unbindAll()
|
||||
camera = null
|
||||
}
|
||||
|
||||
private fun storeSettings() {
|
||||
@@ -284,7 +312,6 @@ class CameraActivity : AppCompatActivity() {
|
||||
|
||||
override fun onRestoreInstanceState(savedState: Bundle) {
|
||||
super.onRestoreInstanceState(savedState)
|
||||
zoomBar.max = savedState.getInt(ZOOM_MAX)
|
||||
zoomBar.progress = savedState.getInt(ZOOM_LEVEL)
|
||||
frontFacing = savedState.getBoolean(FRONT_FACING)
|
||||
bulkMode = savedState.getBoolean(BULK_MODE)
|
||||
@@ -293,7 +320,6 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putInt(ZOOM_MAX, zoomBar.max)
|
||||
outState.putInt(ZOOM_LEVEL, zoomBar.progress)
|
||||
outState.putBoolean(FRONT_FACING, frontFacing)
|
||||
outState.putBoolean(BULK_MODE, bulkMode)
|
||||
@@ -329,7 +355,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
R.id.history -> {
|
||||
startActivity(MainActivity.getHistoryIntent(this))
|
||||
startActivity(Intent(this, HistoryActivity::class.java))
|
||||
true
|
||||
}
|
||||
|
||||
@@ -369,7 +395,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
R.id.preferences -> {
|
||||
startActivity(MainActivity.getPreferencesIntent(this))
|
||||
startActivity(Intent(this, PreferencesActivity::class.java))
|
||||
true
|
||||
}
|
||||
|
||||
@@ -383,18 +409,19 @@ class CameraActivity : AppCompatActivity() {
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
else -> {
|
||||
super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBarcode() {
|
||||
startActivity(MainActivity.getEncodeIntent(this))
|
||||
startActivity(EncodeActivity.newIntent<String>(this))
|
||||
}
|
||||
|
||||
private fun switchCamera() {
|
||||
closeCamera()
|
||||
frontFacing = frontFacing xor true
|
||||
openCamera()
|
||||
bindCameraUseCases()
|
||||
}
|
||||
|
||||
private fun showRestrictionDialog() {
|
||||
@@ -447,7 +474,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
private fun openReadme() {
|
||||
val intent = Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse(getString(R.string.project_url))
|
||||
getString(R.string.project_url).toUri()
|
||||
)
|
||||
execShareIntent(intent)
|
||||
}
|
||||
@@ -460,8 +487,13 @@ class CameraActivity : AppCompatActivity() {
|
||||
.setTitle(R.string.profile)
|
||||
.setItems(profiles) { _, which ->
|
||||
val newProfile = when (which) {
|
||||
0 -> null
|
||||
else -> profiles[which]
|
||||
0 -> {
|
||||
null
|
||||
}
|
||||
|
||||
else -> {
|
||||
profiles[which]
|
||||
}
|
||||
}
|
||||
if (currentProfile != newProfile) {
|
||||
storeSettings()
|
||||
@@ -477,7 +509,13 @@ class CameraActivity : AppCompatActivity() {
|
||||
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
|
||||
if (text?.isEmpty() == false) {
|
||||
startActivity(MainActivity.getEncodeIntent(this, text, true))
|
||||
startActivity(EncodeActivity.newIntent(this, text).apply {
|
||||
addFlags(
|
||||
Intent.FLAG_ACTIVITY_NO_HISTORY or
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
)
|
||||
})
|
||||
finish()
|
||||
return
|
||||
}
|
||||
@@ -495,9 +533,13 @@ class CameraActivity : AppCompatActivity() {
|
||||
val scn = Scanner(fs).useDelimiter("\\A")
|
||||
if (scn.hasNext()) {
|
||||
startActivity(
|
||||
MainActivity.getEncodeIntent(
|
||||
this, scn.next(), true
|
||||
)
|
||||
EncodeActivity.newIntent(this, scn.next()).apply {
|
||||
addFlags(
|
||||
Intent.FLAG_ACTIVITY_NO_HISTORY or
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
)
|
||||
}
|
||||
)
|
||||
finish()
|
||||
}
|
||||
@@ -506,21 +548,27 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCameraView() {
|
||||
cameraView.setUseOrientationListener(true)
|
||||
private fun initPreviewView() {
|
||||
cameraView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
||||
updateFrameRoiAndMappingMatrix()
|
||||
}
|
||||
@Suppress("ClickableViewAccessibility")
|
||||
val touchSlop = ViewConfiguration.get(this).scaledTouchSlop
|
||||
cameraView.setOnTouchListener(object : View.OnTouchListener {
|
||||
var focus = true
|
||||
var downY = -1f
|
||||
var offset = -1f
|
||||
var progress = 0
|
||||
var hasSwiped = false
|
||||
|
||||
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
|
||||
event ?: return false
|
||||
val pos = event.y
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
downY = pos
|
||||
offset = pos
|
||||
progress = zoomBar.progress
|
||||
hasSwiped = false
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -535,136 +583,40 @@ class CameraActivity : AppCompatActivity() {
|
||||
maxValue,
|
||||
max(progress + change.roundToInt(), 0)
|
||||
)
|
||||
if (abs(pos - downY) > touchSlop) {
|
||||
hasSwiped = true
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP -> {
|
||||
// Stop calling focusTo() as soon as it returns false
|
||||
// to avoid throwing and catching future exceptions.
|
||||
if (focus) {
|
||||
focus = cameraView.focusTo(v, event.x, event.y)
|
||||
if (focus) {
|
||||
v?.performClick()
|
||||
return true
|
||||
if (!hasSwiped) {
|
||||
camera?.cameraControl?.apply {
|
||||
cancelFocusAndMetering()
|
||||
startFocusAndMetering(
|
||||
FocusMeteringAction.Builder(
|
||||
cameraView.meteringPointFactory.createPoint(
|
||||
event.x,
|
||||
event.y
|
||||
)
|
||||
).build()
|
||||
)
|
||||
}
|
||||
}
|
||||
v?.performClick()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
@Suppress("DEPRECATION")
|
||||
cameraView.setOnCameraListener(object : CameraView.OnCameraListener {
|
||||
override fun onConfigureParameters(
|
||||
parameters: Camera.Parameters
|
||||
) {
|
||||
zoomBar.visibility = if (parameters.isZoomSupported) {
|
||||
restoreZoomBarSettings()
|
||||
val max = parameters.maxZoom
|
||||
if (zoomBar.max != max) {
|
||||
zoomBar.max = max
|
||||
zoomBar.progress = max / 10
|
||||
storeZoomBarSettings()
|
||||
}
|
||||
parameters.zoom = zoomBar.progress
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
val sceneModes = parameters.supportedSceneModes
|
||||
sceneModes?.let {
|
||||
for (mode in sceneModes) {
|
||||
if (mode == Camera.Parameters.SCENE_MODE_BARCODE) {
|
||||
parameters.sceneMode = mode
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
CameraView.setAutoFocus(parameters)
|
||||
updateFlashFab(parameters.flashMode == null)
|
||||
}
|
||||
|
||||
override fun onCameraError() {
|
||||
this@CameraActivity.toast(R.string.camera_error)
|
||||
}
|
||||
|
||||
override fun onCameraReady(camera: Camera) {
|
||||
frameMetrics = FrameMetrics(
|
||||
cameraView.frameWidth,
|
||||
cameraView.frameHeight,
|
||||
cameraView.frameOrientation
|
||||
)
|
||||
updateFrameRoiAndMappingMatrix()
|
||||
ignoreNext = null
|
||||
decoding = true
|
||||
// These settings can't change while the camera is open.
|
||||
val options = ReaderOptions(
|
||||
tryHarder = prefs.tryHarder,
|
||||
tryRotate = prefs.autoRotate,
|
||||
tryInvert = true,
|
||||
tryDownscale = true,
|
||||
maxNumberOfSymbols = 1,
|
||||
textMode = TextMode.PLAIN
|
||||
)
|
||||
var useLocalAverage = false
|
||||
camera.setPreviewCallback { frameData, _ ->
|
||||
if (!decoding ||
|
||||
frameData == null ||
|
||||
frameData.isEmpty()
|
||||
) {
|
||||
return@setPreviewCallback
|
||||
}
|
||||
useLocalAverage = useLocalAverage xor true
|
||||
ZxingCpp.readByteArray(
|
||||
frameData,
|
||||
frameMetrics.width,
|
||||
frameRoi.left, frameRoi.top,
|
||||
frameRoi.width(), frameRoi.height(),
|
||||
frameMetrics.orientation,
|
||||
options.apply {
|
||||
// By default, ZXing uses LOCAL_AVERAGE, but
|
||||
// this does not work well with inverted
|
||||
// barcodes on low-contrast backgrounds.
|
||||
binarizer = if (useLocalAverage) {
|
||||
Binarizer.LOCAL_AVERAGE
|
||||
} else {
|
||||
Binarizer.GLOBAL_HISTOGRAM
|
||||
}
|
||||
formats = formatsToRead
|
||||
}
|
||||
)?.let { results ->
|
||||
val result = results.first()
|
||||
val text = result.text
|
||||
if (text == ignoreNext) {
|
||||
return@let
|
||||
}
|
||||
val term = searchTerm
|
||||
if (term != null &&
|
||||
!text.matches(term) &&
|
||||
!text.contains(term)
|
||||
) {
|
||||
ignoreNext = text
|
||||
errorFeedback()
|
||||
toast(R.string.does_not_match_search_term)
|
||||
return@let
|
||||
}
|
||||
postResult(result)
|
||||
decoding = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreviewStarted(camera: Camera) {
|
||||
}
|
||||
|
||||
override fun onCameraStopping(camera: Camera) {
|
||||
camera.setPreviewCallback(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun initZoomBar() {
|
||||
zoomBar.max = 100
|
||||
zoomBar.progress = INITIAL_ZOOM
|
||||
restoreZoomBarSettings()
|
||||
zoomBar.setOnSeekBarChangeListener(object :
|
||||
SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(
|
||||
@@ -672,35 +624,29 @@ class CameraActivity : AppCompatActivity() {
|
||||
progress: Int,
|
||||
fromUser: Boolean
|
||||
) {
|
||||
cameraView.camera?.setZoom(progress)
|
||||
val maxRatio = camera?.cameraInfo?.zoomState?.value
|
||||
?.maxZoomRatio ?: return
|
||||
camera?.cameraControl?.setZoomRatio(
|
||||
1f + progress / 100f * (maxRatio - 1f)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {}
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||
storeZoomBarSettings()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun Camera.setZoom(zoom: Int) {
|
||||
try {
|
||||
val params = parameters
|
||||
params.zoom = zoom
|
||||
parameters = params
|
||||
} catch (_: RuntimeException) {
|
||||
// Ignore. There's nothing we can do.
|
||||
private fun storeZoomBarSettings() {
|
||||
prefs.preferences.edit {
|
||||
putInt(ZOOM_LEVEL, zoomBar.progress)
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeZoomBarSettings() {
|
||||
val editor = prefs.preferences.edit()
|
||||
editor.putInt(ZOOM_MAX, zoomBar.max)
|
||||
editor.putInt(ZOOM_LEVEL, zoomBar.progress)
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
private fun restoreZoomBarSettings() {
|
||||
zoomBar.max = prefs.preferences.getInt(ZOOM_MAX, zoomBar.max)
|
||||
zoomBar.progress = prefs.preferences.getInt(
|
||||
ZOOM_LEVEL,
|
||||
zoomBar.progress
|
||||
@@ -719,52 +665,229 @@ class CameraActivity : AppCompatActivity() {
|
||||
detectorView.cropHandleName = "camera_crop_handle"
|
||||
}
|
||||
|
||||
private fun bindCameraUseCases() {
|
||||
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
|
||||
cameraProviderFuture.addListener({
|
||||
if (isDestroyed) {
|
||||
return@addListener
|
||||
}
|
||||
val provider = try {
|
||||
cameraProviderFuture.get()
|
||||
} catch (_: Exception) {
|
||||
toast(R.string.camera_error)
|
||||
return@addListener
|
||||
}
|
||||
cameraProvider = provider
|
||||
val resolutionSelector = ResolutionSelector.Builder()
|
||||
.setResolutionStrategy(
|
||||
ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY
|
||||
)
|
||||
.setAspectRatioStrategy(
|
||||
AspectRatioStrategy.RATIO_16_9_FALLBACK_AUTO_STRATEGY
|
||||
)
|
||||
.setAllowedResolutionMode(
|
||||
ResolutionSelector.PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE
|
||||
)
|
||||
.build()
|
||||
val preview = Preview.Builder()
|
||||
.setResolutionSelector(resolutionSelector)
|
||||
.build()
|
||||
val imageAnalysis = ImageAnalysis.Builder()
|
||||
.setResolutionSelector(resolutionSelector)
|
||||
.setBackpressureStrategy(
|
||||
ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
|
||||
)
|
||||
.build()
|
||||
|
||||
imageAnalysis.setAnalyzer(analyzerExecutor) { image ->
|
||||
analyzeImage(image)
|
||||
}
|
||||
|
||||
val cameraSelector = CameraSelector.Builder()
|
||||
.requireLensFacing(
|
||||
if (frontFacing) {
|
||||
CameraSelector.LENS_FACING_FRONT
|
||||
} else {
|
||||
CameraSelector.LENS_FACING_BACK
|
||||
}
|
||||
)
|
||||
.build()
|
||||
|
||||
try {
|
||||
provider.unbindAll()
|
||||
camera = provider.bindToLifecycle(
|
||||
this,
|
||||
cameraSelector,
|
||||
preview,
|
||||
imageAnalysis
|
||||
)
|
||||
preview.surfaceProvider = cameraView.surfaceProvider
|
||||
ignoreNext = null
|
||||
decoding = true
|
||||
useLocalAverage = false
|
||||
updateZoomState()
|
||||
updateFlashFab(camera?.cameraInfo?.hasFlashUnit() ?: false)
|
||||
updateFrameRoiAndMappingMatrix()
|
||||
} catch (_: Exception) {
|
||||
camera = null
|
||||
toast(R.string.camera_error)
|
||||
}
|
||||
}, ContextCompat.getMainExecutor(this))
|
||||
}
|
||||
|
||||
private fun analyzeImage(image: ImageProxy) {
|
||||
try {
|
||||
if (!decoding) {
|
||||
return
|
||||
}
|
||||
frameMetrics = FrameMetrics(
|
||||
image.width,
|
||||
image.height,
|
||||
image.imageInfo.rotationDegrees
|
||||
)
|
||||
updateFrameRoiAndMappingMatrix()
|
||||
if (frameRoi.width() < 1 || frameRoi.height() < 1) {
|
||||
return
|
||||
}
|
||||
useLocalAverage = useLocalAverage xor true
|
||||
val yPlane = image.planes[0]
|
||||
ZxingCpp.readYBuffer(
|
||||
yPlane.buffer,
|
||||
yPlane.rowStride,
|
||||
frameRoi,
|
||||
frameMetrics.orientation,
|
||||
readerOptions.apply {
|
||||
binarizer = if (useLocalAverage) {
|
||||
Binarizer.LOCAL_AVERAGE
|
||||
} else {
|
||||
Binarizer.GLOBAL_HISTOGRAM
|
||||
}
|
||||
formats = formatsToRead
|
||||
tryHarder = prefs.tryHarder
|
||||
tryRotate = prefs.autoRotate
|
||||
}
|
||||
)?.firstOrNull()?.let { result ->
|
||||
handleDecodeResult(result)
|
||||
}
|
||||
} finally {
|
||||
image.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDecodeResult(result: Result) {
|
||||
val text = result.text
|
||||
if (text == ignoreNext) {
|
||||
return
|
||||
}
|
||||
val term = searchTerm
|
||||
if (term != null &&
|
||||
!text.matches(term) &&
|
||||
!text.contains(term)
|
||||
) {
|
||||
ignoreNext = text
|
||||
cameraView.post {
|
||||
errorFeedback()
|
||||
toast(R.string.does_not_match_search_term)
|
||||
}
|
||||
return
|
||||
}
|
||||
decoding = false
|
||||
postResult(result)
|
||||
}
|
||||
|
||||
private fun updateZoomState() {
|
||||
zoomBar.visibility = if (
|
||||
camera?.cameraInfo?.zoomState?.value != null
|
||||
) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateFrameRoiAndMappingMatrix() {
|
||||
val viewRect = cameraView.previewRect
|
||||
if (viewRect.width() < 1 ||
|
||||
viewRect.height() < 1 ||
|
||||
viewBounds.set(0, 0, cameraView.width, cameraView.height)
|
||||
if (viewBounds.width() < 1 ||
|
||||
viewBounds.height() < 1 ||
|
||||
!frameMetrics.isValid()
|
||||
) {
|
||||
return
|
||||
}
|
||||
previewRect.setCovered(
|
||||
viewBounds.width(),
|
||||
viewBounds.height(),
|
||||
frameMetrics
|
||||
)
|
||||
val viewRoi = if (
|
||||
detectorView.roi.width() < 1 ||
|
||||
detectorView.roi.height() < 1
|
||||
) {
|
||||
viewRect
|
||||
viewBounds
|
||||
} else {
|
||||
detectorView.roi
|
||||
}
|
||||
frameRoi.setFrameRoi(frameMetrics, viewRect, viewRoi)
|
||||
matrix.setFrameToView(frameMetrics, viewRect, viewRoi)
|
||||
frameRoi.setFrameRoi(frameMetrics, previewRect, viewRoi)
|
||||
matrix.setFrameToView(frameMetrics, previewRect, viewRoi)
|
||||
}
|
||||
|
||||
private fun updateFlashFab(unavailable: Boolean) {
|
||||
if (unavailable) {
|
||||
flashFab.setImageResource(R.drawable.ic_action_create)
|
||||
flashFab.setOnClickListener { createBarcode() }
|
||||
} else {
|
||||
private fun updateFlashFab(available: Boolean) {
|
||||
if (available) {
|
||||
flashFab.setImageResource(R.drawable.ic_action_flash)
|
||||
flashFab.setOnClickListener { toggleTorchMode() }
|
||||
} else {
|
||||
flashFab.setImageResource(R.drawable.ic_action_create)
|
||||
flashFab.setOnClickListener { createBarcode() }
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun toggleTorchMode() {
|
||||
val camera = cameraView.camera ?: return
|
||||
val parameters = camera.parameters ?: return
|
||||
parameters.flashMode = if (
|
||||
parameters.flashMode != Camera.Parameters.FLASH_MODE_OFF
|
||||
val currentState = camera?.cameraInfo?.torchState?.value ?: return
|
||||
camera?.cameraControl?.enableTorch(
|
||||
currentState != TorchState.ON
|
||||
)
|
||||
}
|
||||
|
||||
private fun Rect.setCovered(
|
||||
viewWidth: Int,
|
||||
viewHeight: Int,
|
||||
frameMetrics: FrameMetrics
|
||||
) {
|
||||
val frameWidth: Int
|
||||
val frameHeight: Int
|
||||
when (frameMetrics.orientation) {
|
||||
90, 270 -> {
|
||||
frameWidth = frameMetrics.height
|
||||
frameHeight = frameMetrics.width
|
||||
}
|
||||
|
||||
else -> {
|
||||
frameWidth = frameMetrics.width
|
||||
frameHeight = frameMetrics.height
|
||||
}
|
||||
}
|
||||
if (frameWidth < 1 || frameHeight < 1) {
|
||||
set(0, 0, 0, 0)
|
||||
return
|
||||
}
|
||||
var coveredWidth = frameWidth
|
||||
var coveredHeight = frameHeight
|
||||
if (viewWidth.toLong() * coveredWidth <
|
||||
viewHeight.toLong() * coveredHeight
|
||||
) {
|
||||
Camera.Parameters.FLASH_MODE_OFF
|
||||
coveredWidth = coveredWidth * viewHeight / coveredHeight
|
||||
coveredHeight = viewHeight
|
||||
} else {
|
||||
Camera.Parameters.FLASH_MODE_TORCH
|
||||
}
|
||||
try {
|
||||
camera.parameters = parameters
|
||||
} catch (e: RuntimeException) {
|
||||
toast(e.message ?: getString(R.string.error_flash))
|
||||
coveredHeight = coveredHeight * viewWidth / coveredWidth
|
||||
coveredWidth = viewWidth
|
||||
}
|
||||
val left = (viewWidth - coveredWidth) / 2
|
||||
val top = (viewHeight - coveredHeight) / 2
|
||||
set(
|
||||
left,
|
||||
top,
|
||||
left + coveredWidth,
|
||||
top + coveredHeight
|
||||
)
|
||||
}
|
||||
|
||||
private fun postResult(result: Result) {
|
||||
@@ -792,9 +915,11 @@ class CameraActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
|
||||
returnUri != null -> execShareIntent(
|
||||
Intent(Intent.ACTION_VIEW, returnUri)
|
||||
)
|
||||
returnUri != null -> {
|
||||
execShareIntent(
|
||||
Intent(Intent.ACTION_VIEW, returnUri)
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
showResult(result, bulkMode)
|
||||
@@ -809,10 +934,12 @@ class CameraActivity : AppCompatActivity() {
|
||||
if (bulkMode) {
|
||||
when (prefs.ignoreDuplicates()) {
|
||||
Preferences.Companion.IgnoreDuplicates.Consecutive,
|
||||
Preferences.Companion.IgnoreDuplicates.Any ->
|
||||
Preferences.Companion.IgnoreDuplicates.Any -> {
|
||||
ignoreNext = result.text
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
if (prefs.showToastInBulkMode) {
|
||||
toast(result.text)
|
||||
@@ -826,8 +953,8 @@ class CameraActivity : AppCompatActivity() {
|
||||
|
||||
companion object {
|
||||
private const val PICK_FILE_RESULT_CODE = 1
|
||||
private const val ZOOM_MAX = "zoom_max"
|
||||
private const val ZOOM_LEVEL = "zoom_level"
|
||||
private const val INITIAL_ZOOM = 0
|
||||
private const val ZOOM_LEVEL = "zoom"
|
||||
private const val FRONT_FACING = "front_facing"
|
||||
private const val BULK_MODE = "bulk_mode"
|
||||
private const val RESTRICT_FORMAT = "restrict_format"
|
||||
@@ -836,7 +963,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
fun Set<String>.toFormatSet(): Set<BarcodeFormat> = map {
|
||||
BarcodeFormat.valueOf(it)
|
||||
BarcodeFormat.valueOf(it.migrateBarcodeFormatName())
|
||||
}.toSet()
|
||||
|
||||
fun Activity.showResult(
|
||||
@@ -890,7 +1017,9 @@ fun Activity.showResult(
|
||||
R.string.bluetooth_send_fail
|
||||
}
|
||||
|
||||
else -> R.string.bluetooth_send_success
|
||||
else -> {
|
||||
R.string.bluetooth_send_success
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -899,9 +1028,7 @@ fun Activity.showResult(
|
||||
return
|
||||
}
|
||||
if (!bulkMode) {
|
||||
startActivity(
|
||||
MainActivity.getDecodeIntent(this, scan)
|
||||
)
|
||||
startActivity(DecodeActivity.newIntent(this, scan))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,11 +1042,11 @@ private fun getReturnIntent(result: Result) = Intent().apply {
|
||||
}
|
||||
}
|
||||
|
||||
private fun completeUrl(urlTemplate: String, result: Result) = Uri.parse(
|
||||
urlTemplate
|
||||
.replace("{RESULT}", result.text.urlEncode())
|
||||
.replace("{RESULT_BYTES}", result.rawBytes.toHexString())
|
||||
.replace("{FORMAT}", result.format.name.urlEncode())
|
||||
// And support {CODE} from the old ZXing app, too.
|
||||
.replace("{CODE}", result.text.urlEncode())
|
||||
)
|
||||
private fun completeUrl(urlTemplate: String, result: Result) = (
|
||||
urlTemplate
|
||||
.replace("{RESULT}", result.text.urlEncode())
|
||||
.replace("{RESULT_BYTES}", result.rawBytes.toHexString())
|
||||
.replace("{FORMAT}", result.format.name.urlEncode())
|
||||
// And support {CODE} from the old ZXing app, too.
|
||||
.replace("{CODE}", result.text.urlEncode())
|
||||
).toUri()
|
||||
|
||||
+71
-81
@@ -1,14 +1,14 @@
|
||||
package de.markusfisch.android.binaryeye.fragment
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.app.Activity
|
||||
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.provider.DocumentsContract
|
||||
import android.support.design.widget.FloatingActionButton
|
||||
import android.support.v4.app.Fragment
|
||||
import android.text.Editable
|
||||
import android.text.Html
|
||||
import android.text.Spannable
|
||||
@@ -16,7 +16,6 @@ import android.text.SpannableString
|
||||
import android.text.TextWatcher
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.TypefaceSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
@@ -27,6 +26,8 @@ import android.widget.ImageView
|
||||
import android.widget.TableLayout
|
||||
import android.widget.TableRow
|
||||
import android.widget.TextView
|
||||
import androidx.core.net.toUri
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.ActionRegistry
|
||||
import de.markusfisch.android.binaryeye.actions.mail.MatMsg
|
||||
@@ -37,9 +38,7 @@ 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
|
||||
import de.markusfisch.android.binaryeye.actions.wifi.WifiConnector
|
||||
import de.markusfisch.android.binaryeye.activity.MainActivity
|
||||
import de.markusfisch.android.binaryeye.adapter.prettifyFormatName
|
||||
import de.markusfisch.android.binaryeye.app.addFragment
|
||||
import de.markusfisch.android.binaryeye.app.db
|
||||
import de.markusfisch.android.binaryeye.app.hasLocationPermission
|
||||
import de.markusfisch.android.binaryeye.app.hasWritePermission
|
||||
@@ -54,6 +53,8 @@ import de.markusfisch.android.binaryeye.content.toBarcode
|
||||
import de.markusfisch.android.binaryeye.content.toErrorCorrectionInt
|
||||
import de.markusfisch.android.binaryeye.content.wipeLastShareFile
|
||||
import de.markusfisch.android.binaryeye.database.Scan
|
||||
import de.markusfisch.android.binaryeye.database.toBundle
|
||||
import de.markusfisch.android.binaryeye.database.toScan
|
||||
import de.markusfisch.android.binaryeye.io.askForFileName
|
||||
import de.markusfisch.android.binaryeye.io.toSaveResult
|
||||
import de.markusfisch.android.binaryeye.io.writeExternalFile
|
||||
@@ -71,7 +72,7 @@ import java.io.File
|
||||
import java.security.MessageDigest
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class DecodeFragment : Fragment() {
|
||||
class DecodeActivity : ScreenActivity() {
|
||||
private lateinit var contentView: EditText
|
||||
private lateinit var formatView: TextView
|
||||
private lateinit var dataView: TableLayout
|
||||
@@ -105,11 +106,12 @@ class DecodeFragment : Fragment() {
|
||||
resultCode: Int,
|
||||
resultData: Intent?
|
||||
) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
when (requestCode) {
|
||||
OPEN_DOCUMENT -> {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
val uri = resultData?.data ?: return
|
||||
activity?.openPickedFile(uri)
|
||||
openPickedFile(uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,33 +119,20 @@ class DecodeFragment : Fragment() {
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
state: Bundle?
|
||||
): View {
|
||||
activity?.setTitle(R.string.content)
|
||||
|
||||
val view = inflater.inflate(
|
||||
setTitle(R.string.content)
|
||||
val frame = findViewById(R.id.content_frame) as ViewGroup
|
||||
val view = layoutInflater.inflate(
|
||||
R.layout.fragment_decode,
|
||||
container,
|
||||
frame,
|
||||
false
|
||||
)
|
||||
frame.addView(view)
|
||||
|
||||
val justScanned = activity?.intent?.hasExtra(
|
||||
MainActivity.DECODED
|
||||
) == true
|
||||
val justScanned = intent.hasExtra(DECODED) || intent.hasExtra(DECODED_SCAN)
|
||||
closeAutomatically = prefs.closeAutomatically && justScanned
|
||||
|
||||
scan = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
arguments?.getParcelable(SCAN, Scan::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
arguments?.getParcelable(SCAN)
|
||||
} ?: throw IllegalArgumentException("DecodeFragment needs a Scan")
|
||||
scan = intent?.extras?.getBundle(SCAN_BUNDLE)?.toScan()
|
||||
?: throw IllegalArgumentException("DecodeActivity needs a Scan")
|
||||
|
||||
isBinary = scan.text.isEmpty()
|
||||
originalBytes = scan.raw ?: scan.text.toByteArray()
|
||||
@@ -180,8 +169,6 @@ class DecodeFragment : Fragment() {
|
||||
|
||||
initContentAndFab(justScanned)
|
||||
updateViewsAndFab(scan.text, originalBytes)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@@ -304,7 +291,8 @@ class DecodeFragment : Fragment() {
|
||||
ContentBarcode(
|
||||
content,
|
||||
scan.format,
|
||||
scan.errorCorrectionLevel.toErrorCorrectionInt()
|
||||
scan.errorCorrectionLevel.toErrorCorrectionInt(),
|
||||
margin = 1
|
||||
)
|
||||
}
|
||||
try {
|
||||
@@ -312,8 +300,8 @@ class DecodeFragment : Fragment() {
|
||||
v.setOnClickListener {
|
||||
v.context.hideSoftKeyboard(contentView)
|
||||
v.post {
|
||||
fragmentManager?.addFragment(
|
||||
BarcodeFragment.newInstance(barcode)
|
||||
startActivity(
|
||||
BarcodeActivity.newIntent(this, barcode)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -375,7 +363,7 @@ class DecodeFragment : Fragment() {
|
||||
|
||||
is WebAction -> try {
|
||||
items.putAll(
|
||||
Uri.parse(text).run {
|
||||
text.toUri().run {
|
||||
mapOf(
|
||||
R.string.scheme to scheme,
|
||||
R.string.host to host,
|
||||
@@ -418,7 +406,7 @@ class DecodeFragment : Fragment() {
|
||||
R.string.gtin_issue_number to scan.issueNumber,
|
||||
)
|
||||
if (!scan.version.isNullOrBlank()) {
|
||||
val versionString = if (scan.format.name == "QR_CODE") {
|
||||
val versionString = if (scan.format == ZxingCpp.BarcodeFormat.QRCode) {
|
||||
getString(
|
||||
R.string.qr_version_and_modules,
|
||||
scan.version,
|
||||
@@ -433,7 +421,7 @@ class DecodeFragment : Fragment() {
|
||||
)
|
||||
)
|
||||
}
|
||||
if (scan.format == ZxingCpp.BarcodeFormat.QR_CODE &&
|
||||
if (scan.format == ZxingCpp.BarcodeFormat.QRCode &&
|
||||
scan.dataMask > -1
|
||||
) {
|
||||
items.putAll(
|
||||
@@ -480,7 +468,7 @@ class DecodeFragment : Fragment() {
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.fragment_decode, menu)
|
||||
if (id > 0L) {
|
||||
if (scan.id > 0L) {
|
||||
menu.findItem(R.id.remove).isVisible = true
|
||||
}
|
||||
if (action is WifiAction) {
|
||||
@@ -509,29 +497,26 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
R.id.share -> {
|
||||
context?.apply {
|
||||
shareText(textOrHex())
|
||||
maybeBackOrFinish()
|
||||
}
|
||||
shareText(textOrHex())
|
||||
maybeBackOrFinish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.share_file -> {
|
||||
context?.apply {
|
||||
val (data, name) = if (isBinary) {
|
||||
Pair(originalBytes, "barcode_content.bin")
|
||||
} else {
|
||||
Pair(content, "barcode_content.txt")
|
||||
}
|
||||
shareAsFile(data, name)
|
||||
maybeBackOrFinish()
|
||||
val (data, name) = if (isBinary) {
|
||||
Pair(originalBytes, "barcode_content.bin")
|
||||
} else {
|
||||
Pair(content, "barcode_content.txt")
|
||||
}
|
||||
shareAsFile(data, name)
|
||||
maybeBackOrFinish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.create -> {
|
||||
fragmentManager?.addFragment(
|
||||
EncodeFragment.newInstance(
|
||||
startActivity(
|
||||
EncodeActivity.newIntent(
|
||||
this,
|
||||
if (isBinary) originalBytes else content,
|
||||
format
|
||||
)
|
||||
@@ -540,8 +525,7 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
R.id.remove -> {
|
||||
db.removeScan(scan.id)
|
||||
backOrFinish()
|
||||
askToRemoveScan(scan.id)
|
||||
true
|
||||
}
|
||||
|
||||
@@ -549,6 +533,18 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun askToRemoveScan(id: Long) {
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(R.string.really_remove_scan)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
db.removeScan(id)
|
||||
backOrFinish()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun textOrHex() = if (isBinary) {
|
||||
originalBytes.toHexString()
|
||||
} else {
|
||||
@@ -570,12 +566,10 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun copyToClipboard(text: String, isSensitive: Boolean = false) {
|
||||
activity?.apply {
|
||||
copyToClipboard(text, isSensitive)
|
||||
// There's a clipboard popup from Android 13 on.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
toast(R.string.copied_to_clipboard)
|
||||
}
|
||||
(this as android.content.Context).copyToClipboard(text, isSensitive)
|
||||
// There's a clipboard popup from Android 13 on.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
toast(R.string.copied_to_clipboard)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,27 +580,21 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun backOrFinish() {
|
||||
val fm = fragmentManager
|
||||
if (fm != null && fm.backStackEntryCount > 0) {
|
||||
fm.popBackStack()
|
||||
} else {
|
||||
activity?.finish()
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun executeAction(str: String) {
|
||||
val ac = activity ?: return
|
||||
if (str.isEmpty() || openLocalDocument(str)) {
|
||||
return
|
||||
}
|
||||
if (action is WifiAction &&
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
|
||||
!ac.hasLocationPermission { executeAction(str) }
|
||||
!hasLocationPermission { executeAction(str) }
|
||||
) {
|
||||
return
|
||||
}
|
||||
scope.launch {
|
||||
action.execute(ac, str.toByteArray())
|
||||
action.execute(this@DecodeActivity, str.toByteArray())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,40 +630,42 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun askForFileNameAndSave(raw: ByteArray) {
|
||||
val ac = activity ?: return
|
||||
// Write permission is only required before Android Q.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
|
||||
!ac.hasWritePermission { askForFileNameAndSave(raw) }
|
||||
!hasWritePermission { askForFileNameAndSave(raw) }
|
||||
) {
|
||||
return
|
||||
}
|
||||
scope.launch(Dispatchers.Main) {
|
||||
val name = ac.askForFileName() ?: return@launch
|
||||
val name = askForFileName() ?: return@launch
|
||||
withContext(Dispatchers.IO) {
|
||||
val message = ac.writeExternalFile(
|
||||
val message = writeExternalFile(
|
||||
name,
|
||||
"application/octet-stream"
|
||||
) {
|
||||
it.write(raw)
|
||||
}.toSaveResult()
|
||||
withContext(Dispatchers.Main) {
|
||||
ac.toast(message)
|
||||
toast(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SCAN = "scan"
|
||||
const val DECODED_SCAN = "decoded_scan"
|
||||
const val DECODED = "decoded"
|
||||
private const val SCAN_BUNDLE = "scan_bundle"
|
||||
private const val OPEN_DOCUMENT = 1
|
||||
private const val SCHEME_FILE = "file://"
|
||||
|
||||
fun newInstance(scan: Scan): Fragment {
|
||||
fun newIntent(context: Context, scan: Scan): Intent {
|
||||
val args = Bundle()
|
||||
args.putParcelable(SCAN, scan)
|
||||
val fragment = DecodeFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
args.putBundle(SCAN_BUNDLE, scan.toBundle())
|
||||
return Intent(context, DecodeActivity::class.java).apply {
|
||||
putExtra(DECODED_SCAN, true)
|
||||
putExtras(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -753,7 +743,7 @@ private fun generateDpTrackingLink(bytes: ByteArray, format: String): String? {
|
||||
// Check for Deutsche Post Matrixcode stamp.
|
||||
var isStamp = false
|
||||
var rawData = bytes
|
||||
if (format == "DATA_MATRIX" &&
|
||||
if (format == ZxingCpp.BarcodeFormat.DataMatrix.name &&
|
||||
bytes.toString(Charsets.ISO_8859_1).startsWith("DEA5")
|
||||
) {
|
||||
if (bytes.size == 47) {
|
||||
+107
-82
@@ -1,12 +1,9 @@
|
||||
package de.markusfisch.android.binaryeye.fragment
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.widget.SwitchCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
@@ -18,11 +15,12 @@ import android.widget.CheckBox
|
||||
import android.widget.EditText
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.core.net.toUri
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.adapter.prettifyFormatName
|
||||
import de.markusfisch.android.binaryeye.app.addFragment
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.app.setFragment
|
||||
import de.markusfisch.android.binaryeye.net.isEncodeDeeplink
|
||||
import de.markusfisch.android.binaryeye.text.unescape
|
||||
import de.markusfisch.android.binaryeye.view.hideSoftKeyboard
|
||||
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
|
||||
@@ -31,7 +29,8 @@ import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
|
||||
import java.io.InputStream
|
||||
import kotlin.math.min
|
||||
|
||||
class EncodeFragment : Fragment() {
|
||||
|
||||
class EncodeActivity : ScreenActivity() {
|
||||
private lateinit var formatView: Spinner
|
||||
private lateinit var ecLabel: TextView
|
||||
private lateinit var ecSpinner: Spinner
|
||||
@@ -41,18 +40,33 @@ class EncodeFragment : Fragment() {
|
||||
private lateinit var contentView: EditText
|
||||
private lateinit var unescapeCheckBox: CheckBox
|
||||
|
||||
private val formats = arrayListOf(
|
||||
BarcodeFormat.AZTEC,
|
||||
BarcodeFormat.CODABAR,
|
||||
BarcodeFormat.CODE_39,
|
||||
BarcodeFormat.CODE_128,
|
||||
BarcodeFormat.DATA_MATRIX,
|
||||
BarcodeFormat.EAN_8,
|
||||
BarcodeFormat.EAN_13,
|
||||
private val writeableFormats = arrayListOf(
|
||||
BarcodeFormat.Aztec,
|
||||
BarcodeFormat.Codabar,
|
||||
BarcodeFormat.Code39,
|
||||
BarcodeFormat.Code39Ext,
|
||||
BarcodeFormat.Code32,
|
||||
BarcodeFormat.PZN,
|
||||
BarcodeFormat.Code93,
|
||||
BarcodeFormat.Code128,
|
||||
BarcodeFormat.DataBar,
|
||||
BarcodeFormat.DataBarOmni,
|
||||
BarcodeFormat.DataBarStk,
|
||||
BarcodeFormat.DataBarLtd,
|
||||
BarcodeFormat.DataBarExp,
|
||||
BarcodeFormat.DataBarExpStk,
|
||||
BarcodeFormat.DataMatrix,
|
||||
BarcodeFormat.DXFilmEdge,
|
||||
BarcodeFormat.EAN8,
|
||||
BarcodeFormat.EAN13,
|
||||
BarcodeFormat.ITF,
|
||||
BarcodeFormat.PDF_417,
|
||||
BarcodeFormat.QR_CODE,
|
||||
BarcodeFormat.UPC_A
|
||||
BarcodeFormat.MaxiCode,
|
||||
BarcodeFormat.PDF417,
|
||||
BarcodeFormat.QRCode,
|
||||
BarcodeFormat.MicroQRCode,
|
||||
BarcodeFormat.RMQRCode,
|
||||
BarcodeFormat.UPCA,
|
||||
BarcodeFormat.UPCE,
|
||||
)
|
||||
|
||||
private var bytes: ByteArray? = null
|
||||
@@ -62,16 +76,16 @@ class EncodeFragment : Fragment() {
|
||||
resultCode: Int,
|
||||
resultData: Intent?
|
||||
) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
when (requestCode) {
|
||||
PICK_FILE_RESULT_CODE -> {
|
||||
if (resultCode == Activity.RESULT_OK &&
|
||||
resultData != null &&
|
||||
resultData.data != null
|
||||
) {
|
||||
val ac = activity ?: return
|
||||
ac.hideSoftKeyboard(contentView)
|
||||
hideSoftKeyboard(contentView)
|
||||
val uri = resultData.data ?: return
|
||||
bytes = ac.contentResolver?.openInputStream(uri)?.use {
|
||||
bytes = contentResolver?.openInputStream(uri)?.use {
|
||||
it.readBytesMax(4096)
|
||||
} ?: return
|
||||
setEncodeByteArray()
|
||||
@@ -82,28 +96,20 @@ class EncodeFragment : Fragment() {
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
state: Bundle?
|
||||
): View? {
|
||||
val ac = activity ?: return null
|
||||
ac.setTitle(R.string.compose_barcode)
|
||||
|
||||
val view = inflater.inflate(
|
||||
setTitle(R.string.compose_barcode)
|
||||
val frame = findViewById(R.id.content_frame) as ViewGroup
|
||||
val view = layoutInflater.inflate(
|
||||
R.layout.fragment_encode,
|
||||
container,
|
||||
frame,
|
||||
false
|
||||
)
|
||||
frame.addView(view)
|
||||
|
||||
formatView = view.findViewById(R.id.format)
|
||||
val formatAdapter = ArrayAdapter(
|
||||
ac,
|
||||
this,
|
||||
android.R.layout.simple_spinner_item,
|
||||
formats.map { it.name.prettifyFormatName() }
|
||||
writeableFormats.map { it.name.prettifyFormatName() }
|
||||
)
|
||||
formatAdapter.setDropDownViewResource(
|
||||
android.R.layout.simple_spinner_dropdown_item
|
||||
@@ -116,11 +122,13 @@ class EncodeFragment : Fragment() {
|
||||
position: Int,
|
||||
id: Long
|
||||
) {
|
||||
val format = formats[position]
|
||||
val format = writeableFormats[position]
|
||||
val arrayId = when (format) {
|
||||
BarcodeFormat.AZTEC -> R.array.aztec_error_correction_levels
|
||||
BarcodeFormat.QR_CODE -> R.array.qr_error_correction_levels
|
||||
BarcodeFormat.PDF_417 -> R.array.pdf417_error_correction_levels
|
||||
BarcodeFormat.Aztec -> R.array.aztec_error_correction_levels
|
||||
BarcodeFormat.QRCode -> R.array.qr_error_correction_levels
|
||||
BarcodeFormat.MicroQRCode -> R.array.mqr_error_correction_levels
|
||||
BarcodeFormat.RMQRCode -> R.array.rmqr_error_correction_levels
|
||||
BarcodeFormat.PDF417 -> R.array.pdf417_error_correction_levels
|
||||
else -> 0
|
||||
}
|
||||
if (arrayId > 0) {
|
||||
@@ -138,14 +146,6 @@ class EncodeFragment : Fragment() {
|
||||
format.canBeInverted().setVisibilityFor(
|
||||
colorsLabel, colorsSpinner
|
||||
)
|
||||
when (format) {
|
||||
BarcodeFormat.AZTEC,
|
||||
BarcodeFormat.DATA_MATRIX,
|
||||
BarcodeFormat.QR_CODE,
|
||||
BarcodeFormat.PDF_417 -> true
|
||||
|
||||
else -> false
|
||||
}.setVisibilityFor(addQuietZoneSwitch)
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parentView: AdapterView<*>?) {}
|
||||
@@ -160,7 +160,7 @@ class EncodeFragment : Fragment() {
|
||||
position: Int,
|
||||
id: Long
|
||||
) {
|
||||
val format = formats[formatView.selectedItemPosition]
|
||||
val format = writeableFormats[formatView.selectedItemPosition]
|
||||
prefs.indexOfLastSelectedEcLevel = format.packEcLevel(
|
||||
prefs.indexOfLastSelectedEcLevel,
|
||||
position
|
||||
@@ -180,7 +180,7 @@ class EncodeFragment : Fragment() {
|
||||
unescapeCheckBox.isChecked = prefs.expandEscapeSequences
|
||||
|
||||
var complete = false
|
||||
val args = arguments
|
||||
val args = intent?.extras ?: getExtrasFromDeeplink()
|
||||
args?.getString(CONTENT_TEXT)?.let {
|
||||
contentView.setText(it)
|
||||
complete = it.isNotEmpty()
|
||||
@@ -194,7 +194,7 @@ class EncodeFragment : Fragment() {
|
||||
val barcodeFormat = args?.getString(FORMAT)
|
||||
if (barcodeFormat != null) {
|
||||
formatView.setSelection(
|
||||
formats.indexOf(barcodeFormat.toFormat())
|
||||
writeableFormats.indexOf(barcodeFormat.toFormat())
|
||||
)
|
||||
} else if (state == null) {
|
||||
formatView.post {
|
||||
@@ -214,11 +214,10 @@ class EncodeFragment : Fragment() {
|
||||
) {
|
||||
view.post {
|
||||
val content = view.context.getContent() ?: return@post
|
||||
fragmentManager?.setFragment(newEncodeFragment(content))
|
||||
startActivity(newBarcodeIntent(content))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
@@ -255,25 +254,21 @@ class EncodeFragment : Fragment() {
|
||||
hideSoftKeyboard(contentView)
|
||||
val content = getContent() ?: return
|
||||
contentView.post {
|
||||
fragmentManager?.addFragment(newEncodeFragment(content))
|
||||
startActivity(newBarcodeIntent(content))
|
||||
}
|
||||
}
|
||||
|
||||
private fun newEncodeFragment(content: Any): Fragment {
|
||||
val format = formats[formatView.selectedItemPosition]
|
||||
return BarcodeFragment.newInstance(
|
||||
private fun newBarcodeIntent(content: Any): Intent {
|
||||
val format = writeableFormats[formatView.selectedItemPosition]
|
||||
return BarcodeActivity.newIntent(
|
||||
this,
|
||||
content,
|
||||
format,
|
||||
format.getErrorCorrectionLevel(ecSpinner.selectedItemPosition),
|
||||
when (format) {
|
||||
BarcodeFormat.AZTEC,
|
||||
BarcodeFormat.DATA_MATRIX,
|
||||
BarcodeFormat.QR_CODE,
|
||||
BarcodeFormat.PDF_417 -> if (
|
||||
addQuietZoneSwitch.isChecked
|
||||
) 1 else 0
|
||||
|
||||
else -> -1
|
||||
if (addQuietZoneSwitch.isChecked) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
},
|
||||
if (format.canBeInverted()) {
|
||||
colorsSpinner.selectedItemPosition
|
||||
@@ -316,6 +311,28 @@ class EncodeFragment : Fragment() {
|
||||
unescapeCheckBox.isEnabled = false
|
||||
}
|
||||
|
||||
private fun getExtrasFromDeeplink(): Bundle? {
|
||||
val data = intent?.dataString ?: return null
|
||||
if (!isEncodeDeeplink(data)) {
|
||||
return null
|
||||
}
|
||||
val uri = data.toUri()
|
||||
return Bundle().apply {
|
||||
uri.getQueryParameter("content")?.let {
|
||||
putString(CONTENT_TEXT, it)
|
||||
}
|
||||
uri.getQueryParameter("format")?.let {
|
||||
putString(FORMAT, it)
|
||||
}
|
||||
putBoolean(
|
||||
EXECUTE,
|
||||
uri.getQueryParameter("execute").let {
|
||||
it == "" || it?.toBoolean() == true
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CONTENT_TEXT = "content_text"
|
||||
private const val CONTENT_RAW = "content_raw"
|
||||
@@ -323,11 +340,12 @@ class EncodeFragment : Fragment() {
|
||||
private const val EXECUTE = "execute"
|
||||
private const val PICK_FILE_RESULT_CODE = 1
|
||||
|
||||
fun <T> newInstance(
|
||||
fun <T> newIntent(
|
||||
context: Context,
|
||||
content: T? = null,
|
||||
format: String? = null,
|
||||
execute: Boolean = false
|
||||
): Fragment {
|
||||
): Intent {
|
||||
val args = Bundle()
|
||||
content?.let {
|
||||
when (content) {
|
||||
@@ -340,9 +358,9 @@ class EncodeFragment : Fragment() {
|
||||
args.putBoolean(EXECUTE, execute)
|
||||
}
|
||||
format?.let { args.putString(FORMAT, it) }
|
||||
val fragment = EncodeFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
return Intent(context, EncodeActivity::class.java).apply {
|
||||
putExtras(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,22 +381,26 @@ private fun BarcodeFormat.unpackEcLevel(packed: Int) =
|
||||
(packed shr ecLevelShift()) and 15
|
||||
|
||||
private fun BarcodeFormat.ecLevelShift() = when (this) {
|
||||
BarcodeFormat.AZTEC -> 0
|
||||
BarcodeFormat.QR_CODE -> 4
|
||||
BarcodeFormat.PDF_417 -> 8
|
||||
BarcodeFormat.Aztec -> 0
|
||||
BarcodeFormat.QRCode -> 4
|
||||
BarcodeFormat.MicroQRCode -> 3
|
||||
BarcodeFormat.RMQRCode -> 2
|
||||
BarcodeFormat.PDF417 -> 8
|
||||
else -> throw IllegalArgumentException("$this does not have error levels")
|
||||
}
|
||||
|
||||
private fun BarcodeFormat.canBeInverted() = when (this) {
|
||||
BarcodeFormat.AZTEC,
|
||||
BarcodeFormat.DATA_MATRIX,
|
||||
BarcodeFormat.QR_CODE -> true
|
||||
BarcodeFormat.Aztec,
|
||||
BarcodeFormat.DataMatrix,
|
||||
BarcodeFormat.QRCode,
|
||||
BarcodeFormat.MicroQRCode,
|
||||
BarcodeFormat.RMQRCode -> true
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun String.toFormat(
|
||||
default: BarcodeFormat = BarcodeFormat.QR_CODE
|
||||
default: BarcodeFormat = BarcodeFormat.QRCode
|
||||
): BarcodeFormat = try {
|
||||
BarcodeFormat.valueOf(this)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
@@ -386,9 +408,12 @@ private fun String.toFormat(
|
||||
}
|
||||
|
||||
private fun BarcodeFormat.getErrorCorrectionLevel(position: Int) = when (this) {
|
||||
BarcodeFormat.AZTEC -> position
|
||||
BarcodeFormat.QR_CODE -> (position + 1) * 2
|
||||
BarcodeFormat.PDF_417 -> position
|
||||
BarcodeFormat.Aztec -> position
|
||||
BarcodeFormat.QRCode,
|
||||
BarcodeFormat.MicroQRCode -> (position + 1) * 2
|
||||
|
||||
BarcodeFormat.RMQRCode -> (position + 1) * 4
|
||||
BarcodeFormat.PDF417 -> position
|
||||
else -> 0
|
||||
}.coerceIn(0, 8)
|
||||
|
||||
+47
-69
@@ -1,4 +1,4 @@
|
||||
package de.markusfisch.android.binaryeye.fragment
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
@@ -8,13 +8,6 @@ import android.database.Cursor
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.support.v4.app.ActivityCompat
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.view.ActionMode
|
||||
import android.support.v7.widget.SearchView
|
||||
import android.support.v7.widget.SwitchCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
@@ -23,9 +16,12 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ListView
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.adapter.ScansAdapter
|
||||
import de.markusfisch.android.binaryeye.app.addFragment
|
||||
import de.markusfisch.android.binaryeye.app.alertDialog
|
||||
import de.markusfisch.android.binaryeye.app.db
|
||||
import de.markusfisch.android.binaryeye.app.hasWritePermission
|
||||
@@ -38,7 +34,6 @@ import de.markusfisch.android.binaryeye.database.Database
|
||||
import de.markusfisch.android.binaryeye.database.exportCsv
|
||||
import de.markusfisch.android.binaryeye.database.exportDatabase
|
||||
import de.markusfisch.android.binaryeye.database.exportJson
|
||||
import de.markusfisch.android.binaryeye.database.use
|
||||
import de.markusfisch.android.binaryeye.io.askForFileName
|
||||
import de.markusfisch.android.binaryeye.io.toSaveResult
|
||||
import de.markusfisch.android.binaryeye.view.lockStatusBarColor
|
||||
@@ -53,7 +48,7 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class HistoryFragment : Fragment() {
|
||||
class HistoryActivity : ScreenActivity() {
|
||||
private lateinit var useHistorySwitch: SwitchCompat
|
||||
private lateinit var listView: ListView
|
||||
private lateinit var fab: View
|
||||
@@ -70,12 +65,10 @@ class HistoryFragment : Fragment() {
|
||||
R.menu.fragment_history_edit,
|
||||
menu
|
||||
)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
|
||||
// SDK35+ doesn't draw a status bar background anymore.
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM
|
||||
) {
|
||||
// SDK35+ doesn't draw a status bar background anymore.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
lockStatusBarColor()
|
||||
val ac = activity ?: return false
|
||||
val ac = this@HistoryActivity
|
||||
@Suppress("DEPRECATION")
|
||||
ac.window.statusBarColor = ContextCompat.getColor(
|
||||
ac,
|
||||
@@ -96,7 +89,7 @@ class HistoryFragment : Fragment() {
|
||||
mode: ActionMode,
|
||||
item: MenuItem
|
||||
): Boolean {
|
||||
val ac = activity ?: return false
|
||||
val ac = this@HistoryActivity
|
||||
return when (item.itemId) {
|
||||
R.id.copy_scan -> {
|
||||
scansAdapter?.getSelectedContent("\n")?.let {
|
||||
@@ -148,22 +141,10 @@ class HistoryFragment : Fragment() {
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
state: Bundle?
|
||||
): View? {
|
||||
val ac = activity ?: return null
|
||||
ac.setTitle(R.string.history)
|
||||
|
||||
val view = inflater.inflate(
|
||||
R.layout.fragment_history,
|
||||
container,
|
||||
false
|
||||
)
|
||||
setTitle(R.string.history)
|
||||
val frame = findViewById(R.id.content_frame) as ViewGroup
|
||||
val view = layoutInflater.inflate(R.layout.fragment_history, frame, false)
|
||||
frame.addView(view)
|
||||
|
||||
useHistorySwitch = view.findViewById(
|
||||
R.id.use_history
|
||||
@@ -180,8 +161,8 @@ class HistoryFragment : Fragment() {
|
||||
}
|
||||
listView.setOnItemLongClickListener { _, v, position, id ->
|
||||
scansAdapter?.select(v, id, position)
|
||||
if (actionMode == null && ac is AppCompatActivity) {
|
||||
actionMode = ac.delegate.startSupportActionMode(
|
||||
if (actionMode == null) {
|
||||
actionMode = delegate.startSupportActionMode(
|
||||
actionModeCallback
|
||||
)
|
||||
}
|
||||
@@ -198,10 +179,6 @@ class HistoryFragment : Fragment() {
|
||||
|
||||
view.findViewById<View>(R.id.inset_layout).setPaddingFromWindowInsets()
|
||||
listView.setPaddingFromWindowInsets()
|
||||
|
||||
update()
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
@@ -211,6 +188,11 @@ class HistoryFragment : Fragment() {
|
||||
wipeLastShareFile()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
update()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
listViewState = listView.onSaveInstanceState()
|
||||
@@ -235,35 +217,31 @@ class HistoryFragment : Fragment() {
|
||||
|
||||
private fun initSearchView(item: MenuItem?) {
|
||||
item ?: return
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
item.isVisible = false
|
||||
} else {
|
||||
val ac = activity ?: return
|
||||
val searchView = item.actionView as SearchView
|
||||
val searchManager = ac.getSystemService(
|
||||
Context.SEARCH_SERVICE
|
||||
) as SearchManager
|
||||
searchView.setSearchableInfo(
|
||||
searchManager.getSearchableInfo(ac.componentName)
|
||||
)
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
update(query)
|
||||
return false
|
||||
}
|
||||
val ac = this
|
||||
val searchView = item.actionView as SearchView
|
||||
val searchManager = ac.getSystemService(
|
||||
Context.SEARCH_SERVICE
|
||||
) as SearchManager
|
||||
searchView.setSearchableInfo(
|
||||
searchManager.getSearchableInfo(ac.componentName)
|
||||
)
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
update(query)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(query: String): Boolean {
|
||||
update(query)
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
override fun onQueryTextChange(query: String): Boolean {
|
||||
update(query)
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.clear -> {
|
||||
context.askToRemoveScans()
|
||||
this.askToRemoveScans()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -273,7 +251,7 @@ class HistoryFragment : Fragment() {
|
||||
}
|
||||
|
||||
R.id.share_as_file -> {
|
||||
context.pickListSeparatorAndShare(true)
|
||||
this.pickListSeparatorAndShare(true)
|
||||
true
|
||||
}
|
||||
|
||||
@@ -300,13 +278,13 @@ class HistoryFragment : Fragment() {
|
||||
scope.launch {
|
||||
val cursor = db.getScans(filter)
|
||||
withContext(Dispatchers.Main) {
|
||||
val ac = activity ?: return@withContext
|
||||
val ac = this@HistoryActivity
|
||||
val hasScans = cursor.count > 0
|
||||
if (filter == null) {
|
||||
if (!hasScans) {
|
||||
listView.emptyView = useHistorySwitch
|
||||
}
|
||||
ActivityCompat.invalidateOptionsMenu(ac)
|
||||
ac.invalidateOptionsMenu()
|
||||
}
|
||||
enableMenuItems(hasScans)
|
||||
fab.visibility = if (hasScans) {
|
||||
@@ -344,7 +322,7 @@ class HistoryFragment : Fragment() {
|
||||
private fun showScan(id: Long) = db.getScan(id)?.also { scan ->
|
||||
closeActionMode()
|
||||
try {
|
||||
fragmentManager?.addFragment(DecodeFragment.newInstance(scan))
|
||||
startActivity(DecodeActivity.newIntent(this, scan))
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// Ignore, can never happen.
|
||||
}
|
||||
@@ -418,7 +396,7 @@ class HistoryFragment : Fragment() {
|
||||
|
||||
private fun askToExportToFile() {
|
||||
scope.launch {
|
||||
val ac = activity ?: return@launch
|
||||
val ac = this@HistoryActivity
|
||||
progressView.useVisibility {
|
||||
// Write permission is only required before Android Q.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
|
||||
@@ -490,12 +468,12 @@ class HistoryFragment : Fragment() {
|
||||
text?.let {
|
||||
withContext(Dispatchers.Main) {
|
||||
if (asFile) {
|
||||
context.shareAsFile(
|
||||
this@HistoryActivity.shareAsFile(
|
||||
it,
|
||||
String.format("scans.%s", ext)
|
||||
)
|
||||
} else {
|
||||
context.shareText(it)
|
||||
this@HistoryActivity.shareText(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.PERMISSION_LOCATION
|
||||
import de.markusfisch.android.binaryeye.app.PERMISSION_WRITE
|
||||
import de.markusfisch.android.binaryeye.app.applyLocale
|
||||
import de.markusfisch.android.binaryeye.app.permissionGrantedCallback
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.app.setFragment
|
||||
import de.markusfisch.android.binaryeye.database.Scan
|
||||
import de.markusfisch.android.binaryeye.fragment.DecodeFragment
|
||||
import de.markusfisch.android.binaryeye.fragment.EncodeFragment
|
||||
import de.markusfisch.android.binaryeye.fragment.HistoryFragment
|
||||
import de.markusfisch.android.binaryeye.fragment.PreferencesFragment
|
||||
import de.markusfisch.android.binaryeye.net.isEncodeDeeplink
|
||||
import de.markusfisch.android.binaryeye.view.colorSystemAndToolBars
|
||||
import de.markusfisch.android.binaryeye.view.initBars
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
when (requestCode) {
|
||||
PERMISSION_LOCATION, PERMISSION_WRITE -> if (
|
||||
grantResults.isNotEmpty() &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
permissionGrantedCallback?.invoke()
|
||||
permissionGrantedCallback = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
val fm = supportFragmentManager
|
||||
if (fm != null && fm.backStackEntryCount > 0) {
|
||||
fm.popBackStack()
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
base?.applyLocale(prefs.customLocale)
|
||||
super.attachBaseContext(base)
|
||||
}
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
initBars()
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
supportFragmentManager.addOnBackStackChangedListener {
|
||||
colorSystemAndToolBars(this@MainActivity)
|
||||
}
|
||||
|
||||
if (state == null) {
|
||||
supportFragmentManager?.setFragment(getFragmentForIntent(intent))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PREFERENCES = "preferences"
|
||||
private const val HISTORY = "history"
|
||||
private const val ENCODE = "encode"
|
||||
const val DECODED = "decoded"
|
||||
|
||||
private fun getFragmentForIntent(intent: Intent?): Fragment {
|
||||
intent ?: return PreferencesFragment()
|
||||
return when {
|
||||
intent.hasExtra(PREFERENCES) -> PreferencesFragment()
|
||||
intent.hasExtra(HISTORY) -> HistoryFragment()
|
||||
|
||||
intent.dataString?.let(::isEncodeDeeplink) == true -> {
|
||||
val uri = Uri.parse(intent.dataString)
|
||||
EncodeFragment.newInstance(
|
||||
content = uri.getQueryParameter("content"),
|
||||
format = uri.getQueryParameter("format")?.uppercase(),
|
||||
execute = uri.getQueryParameter("execute")
|
||||
.let { it == "" || it.toBoolean() }
|
||||
)
|
||||
}
|
||||
|
||||
intent.hasExtra(ENCODE) -> EncodeFragment.newInstance(
|
||||
intent.getStringExtra(ENCODE)
|
||||
)
|
||||
|
||||
intent.hasExtra(DECODED) -> intent.getScanExtra(DECODED)?.let {
|
||||
DecodeFragment.newInstance(it)
|
||||
} ?: DecodeFragment()
|
||||
|
||||
else -> PreferencesFragment()
|
||||
}
|
||||
}
|
||||
|
||||
fun getPreferencesIntent(context: Context): Intent {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra(PREFERENCES, true)
|
||||
return intent
|
||||
}
|
||||
|
||||
fun getHistoryIntent(context: Context): Intent {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra(HISTORY, true)
|
||||
return intent
|
||||
}
|
||||
|
||||
fun getEncodeIntent(
|
||||
context: Context,
|
||||
text: String? = "",
|
||||
isExternal: Boolean = false
|
||||
): Intent {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra(ENCODE, text)
|
||||
if (isExternal) {
|
||||
val flagActivityClearTask = if (
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
|
||||
) {
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
} else 0
|
||||
intent.addFlags(
|
||||
Intent.FLAG_ACTIVITY_NO_HISTORY or
|
||||
flagActivityClearTask or
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
)
|
||||
}
|
||||
return intent
|
||||
}
|
||||
|
||||
fun getDecodeIntent(context: Context, scan: Scan): Intent {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra(DECODED, scan)
|
||||
return intent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Intent.getScanExtra(name: String): Scan? = try {
|
||||
if (
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
|
||||
) {
|
||||
@Suppress("DEPRECATION")
|
||||
getParcelableExtra(name)
|
||||
} else {
|
||||
getParcelableExtra(name, Scan::class.java)
|
||||
}
|
||||
} catch (_: Throwable) {
|
||||
null
|
||||
}
|
||||
+15
-21
@@ -1,43 +1,39 @@
|
||||
package de.markusfisch.android.binaryeye.fragment
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.net.wifi.WifiManager
|
||||
import android.net.wifi.WifiNetworkSuggestion
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.RequiresApi
|
||||
import android.support.v4.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ListView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.util.size
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
|
||||
import de.markusfisch.android.binaryeye.view.systemBarListViewScrollListener
|
||||
import de.markusfisch.android.binaryeye.widget.toast
|
||||
|
||||
class NetworkSuggestionsFragment : Fragment() {
|
||||
class NetworkSuggestionsActivity : ScreenActivity() {
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
state: Bundle?
|
||||
): View? {
|
||||
val ac = activity ?: return null
|
||||
ac.setTitle(R.string.network_suggestions)
|
||||
|
||||
val view = inflater.inflate(
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setTitle(R.string.network_suggestions)
|
||||
val frame = findViewById(R.id.content_frame) as ViewGroup
|
||||
val view = layoutInflater.inflate(
|
||||
R.layout.fragment_network_suggestions,
|
||||
container,
|
||||
frame,
|
||||
false
|
||||
)
|
||||
frame.addView(view)
|
||||
|
||||
val wm = ac.applicationContext.getSystemService(
|
||||
val wm = applicationContext.getSystemService(
|
||||
Context.WIFI_SERVICE
|
||||
) as WifiManager
|
||||
val suggestionArrayAdapter = ArrayAdapter(
|
||||
ac,
|
||||
this,
|
||||
android.R.layout.simple_list_item_checked,
|
||||
wm.networkSuggestions.map {
|
||||
Suggestion(
|
||||
@@ -58,7 +54,7 @@ class NetworkSuggestionsFragment : Fragment() {
|
||||
val removeList = ArrayList<WifiNetworkSuggestion>()
|
||||
val removeFromAdapter = ArrayList<Suggestion>()
|
||||
val checked = listView.checkedItemPositions
|
||||
val size = checked.size()
|
||||
val size = checked.size
|
||||
for (i in 0 until size) {
|
||||
if (checked.valueAt(i)) {
|
||||
val pos = checked.keyAt(i)
|
||||
@@ -76,13 +72,11 @@ class NetworkSuggestionsFragment : Fragment() {
|
||||
}
|
||||
wm.removeNetworkSuggestions(removeList)
|
||||
} else {
|
||||
ac.toast(
|
||||
toast(
|
||||
R.string.clear_network_suggestions_nothing_to_remove
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ import android.graphics.RectF
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.applyLocale
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
@@ -109,7 +110,7 @@ class PickActivity : AppCompatActivity() {
|
||||
cropHandleName = "picker_crop_handle"
|
||||
}
|
||||
|
||||
findViewById(R.id.scan).setOnClickListener {
|
||||
findViewById<View>(R.id.scan).setOnClickListener {
|
||||
showResult()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.applyLocale
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.fragment.PreferencesFragment
|
||||
import de.markusfisch.android.binaryeye.view.initBars
|
||||
|
||||
class PreferencesActivity : AppCompatActivity() {
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
base?.applyLocale(prefs.customLocale)
|
||||
super.attachBaseContext(base)
|
||||
}
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_main)
|
||||
initBars()
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
if (state == null) {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.content_frame, PreferencesFragment())
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
}
|
||||
+17
-27
@@ -1,10 +1,8 @@
|
||||
package de.markusfisch.android.binaryeye.fragment
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
@@ -17,30 +15,27 @@ import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
|
||||
import de.markusfisch.android.binaryeye.view.systemBarListViewScrollListener
|
||||
import de.markusfisch.android.binaryeye.widget.toast
|
||||
|
||||
class ProfilesFragment : Fragment() {
|
||||
class ProfilesActivity : ScreenActivity() {
|
||||
private val profiles = ArrayList<ProfileItem>()
|
||||
|
||||
private lateinit var adapter: ProfilesAdapter
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
state: Bundle?
|
||||
): View? {
|
||||
val ac = activity ?: return null
|
||||
ac.setTitle(R.string.profile)
|
||||
|
||||
val view = inflater.inflate(
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setTitle(R.string.profile)
|
||||
val frame = findViewById(R.id.content_frame) as ViewGroup
|
||||
val view = layoutInflater.inflate(
|
||||
R.layout.fragment_profiles,
|
||||
container,
|
||||
frame,
|
||||
false
|
||||
)
|
||||
frame.addView(view)
|
||||
|
||||
refreshProfiles()
|
||||
|
||||
val listView = view.findViewById<ListView>(R.id.profiles)
|
||||
listView.emptyView = view.findViewById(R.id.no_profiles)
|
||||
adapter = ProfilesAdapter(ac, profiles)
|
||||
adapter = ProfilesAdapter(this, profiles)
|
||||
listView.adapter = adapter
|
||||
listView.setOnScrollListener(systemBarListViewScrollListener)
|
||||
listView.setOnItemClickListener { _, _, position, _ ->
|
||||
@@ -57,8 +52,6 @@ class ProfilesFragment : Fragment() {
|
||||
|
||||
view.findViewById<View>(R.id.inset_layout).setPaddingFromWindowInsets()
|
||||
listView.setPaddingFromWindowInsets()
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private fun refreshProfiles() {
|
||||
@@ -78,48 +71,45 @@ class ProfilesFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun selectProfile(position: Int) {
|
||||
val ac = activity ?: return
|
||||
val profile = profiles[position].name
|
||||
if (prefs.profile == profile) {
|
||||
return
|
||||
}
|
||||
prefs.load(ac, profile)
|
||||
prefs.load(this, profile)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
// Dialogs do not have a parent view.
|
||||
@Suppress("InflateParams")
|
||||
private fun addProfile() {
|
||||
val ac = activity ?: return
|
||||
val view = ac.layoutInflater.inflate(
|
||||
val view = layoutInflater.inflate(
|
||||
R.layout.dialog_profile_name, null
|
||||
)
|
||||
val editText = view.findViewById<EditText>(R.id.name)
|
||||
AlertDialog.Builder(ac)
|
||||
AlertDialog.Builder(this)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val name = editText.text.toString().trim()
|
||||
if (name.isNotEmpty() && prefs.addProfile(name)) {
|
||||
prefs.load(ac, name)
|
||||
prefs.load(this, name)
|
||||
refreshProfiles()
|
||||
} else {
|
||||
ac.toast(R.string.profile_invalid_name)
|
||||
toast(R.string.profile_invalid_name)
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun confirmRemoveProfile(position: Int) {
|
||||
val ac = activity ?: return
|
||||
val profile = profiles[position]
|
||||
val profileName = profile.name ?: return
|
||||
AlertDialog.Builder(ac)
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(R.string.profile_remove_confirm)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val isCurrent = prefs.profile == profileName
|
||||
prefs.removeProfile(profileName)
|
||||
if (isCurrent) {
|
||||
prefs.load(ac, null)
|
||||
prefs.load(this, null)
|
||||
}
|
||||
refreshProfiles()
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isNotEmpty
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.PERMISSION_LOCATION
|
||||
import de.markusfisch.android.binaryeye.app.PERMISSION_WRITE
|
||||
import de.markusfisch.android.binaryeye.app.applyLocale
|
||||
import de.markusfisch.android.binaryeye.app.permissionGrantedCallback
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.view.initBars
|
||||
|
||||
abstract class ScreenActivity : AppCompatActivity() {
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
base?.applyLocale(prefs.customLocale)
|
||||
super.attachBaseContext(base)
|
||||
}
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_main)
|
||||
initBars()
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(
|
||||
requestCode,
|
||||
permissions,
|
||||
grantResults
|
||||
)
|
||||
when (requestCode) {
|
||||
PERMISSION_LOCATION, PERMISSION_WRITE -> {
|
||||
if (grantResults.isNotEmpty() &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
permissionGrantedCallback?.invoke()
|
||||
permissionGrantedCallback = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
onCreateOptionsMenu(menu, menuInflater)
|
||||
return menu.isNotEmpty() || super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
protected open fun onCreateOptionsMenu(
|
||||
menu: Menu,
|
||||
inflater: MenuInflater
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class SplashActivity : AppCompatActivity() {
|
||||
override fun onCreate(state: Bundle?) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
|
||||
@@ -9,10 +10,10 @@ class WelcomeActivity : AppCompatActivity() {
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_welcome)
|
||||
findViewById(R.id.expert).setOnClickListener {
|
||||
findViewById<View>(R.id.expert).setOnClickListener {
|
||||
finish()
|
||||
}
|
||||
findViewById(R.id.simple).setOnClickListener {
|
||||
findViewById<View>(R.id.simple).setOnClickListener {
|
||||
prefs.apply {
|
||||
showCropHandle = false
|
||||
zoomBySwiping = false
|
||||
|
||||
@@ -2,12 +2,12 @@ package de.markusfisch.android.binaryeye.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CursorAdapter
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.database.Database
|
||||
import java.text.DateFormat
|
||||
@@ -139,7 +139,11 @@ class ScansAdapter(context: Context, cursor: Cursor) :
|
||||
)
|
||||
}
|
||||
|
||||
private val formatWordBoundary =
|
||||
"(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[A-Za-z])(?=\\d)|(?<=\\d)(?=[A-Za-z])".toRegex()
|
||||
|
||||
fun String.prettifyFormatName() = replace("_", " ")
|
||||
.replace(formatWordBoundary, " ")
|
||||
|
||||
private fun formatDateTime(rfc: String): String {
|
||||
try {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentManager
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
fun FragmentManager.setFragment(fragment: Fragment) {
|
||||
getTransaction(fragment).commit()
|
||||
}
|
||||
|
||||
fun FragmentManager.addFragment(fragment: Fragment) {
|
||||
getTransaction(fragment).addToBackStack(null).commit()
|
||||
}
|
||||
|
||||
@SuppressLint("CommitTransaction")
|
||||
private fun FragmentManager.getTransaction(
|
||||
fragment: Fragment
|
||||
) = beginTransaction().replace(R.id.content_frame, fragment)
|
||||
@@ -4,8 +4,8 @@ import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.support.v4.app.ActivityCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
var permissionGrantedCallback: (() -> Any)? = null
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package de.markusfisch.android.binaryeye.bluetooth
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothSocket
|
||||
import android.support.v7.preference.ListPreference
|
||||
import androidx.preference.ListPreference
|
||||
import de.markusfisch.android.binaryeye.database.Scan
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
@@ -48,7 +48,8 @@ fun Scan.toBarcode(): Barcode<*> {
|
||||
ContentBarcode(
|
||||
content,
|
||||
format,
|
||||
errorCorrectionLevel.toErrorCorrectionInt()
|
||||
errorCorrectionLevel.toErrorCorrectionInt(),
|
||||
margin = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -108,7 +109,7 @@ class ContentBarcode<T>(
|
||||
content: T,
|
||||
format: BarcodeFormat,
|
||||
val ecLevel: Int = -1,
|
||||
val margin: Int = -1,
|
||||
val margin: Int = 0,
|
||||
colors: BarcodeColors = BarcodeColors.BLACK_ON_WHITE
|
||||
) : Barcode<T>(content, format, colors) {
|
||||
override fun toBitmap(size: Int) = ZxingCpp.encodeAsBitmap(
|
||||
@@ -186,18 +187,24 @@ private fun BitMatrix.inflate(
|
||||
|
||||
private fun BarcodeFormat.height(size: Int) = when (this) {
|
||||
// 1D barcodes don't need as much vertical space.
|
||||
BarcodeFormat.CODABAR,
|
||||
BarcodeFormat.CODE_39,
|
||||
BarcodeFormat.CODE_93,
|
||||
BarcodeFormat.CODE_128,
|
||||
BarcodeFormat.DATA_BAR,
|
||||
BarcodeFormat.DATA_BAR_EXPANDED,
|
||||
BarcodeFormat.DX_FILM_EDGE,
|
||||
BarcodeFormat.EAN_8,
|
||||
BarcodeFormat.EAN_13,
|
||||
BarcodeFormat.Codabar,
|
||||
BarcodeFormat.Code39,
|
||||
BarcodeFormat.Code39Ext,
|
||||
BarcodeFormat.Code32,
|
||||
BarcodeFormat.PZN,
|
||||
BarcodeFormat.Code93,
|
||||
BarcodeFormat.Code128,
|
||||
BarcodeFormat.DataBarOmni,
|
||||
BarcodeFormat.DataBarStk,
|
||||
BarcodeFormat.DataBarLtd,
|
||||
BarcodeFormat.DataBarExp,
|
||||
BarcodeFormat.DataBarExpStk,
|
||||
BarcodeFormat.DXFilmEdge,
|
||||
BarcodeFormat.EAN8,
|
||||
BarcodeFormat.EAN13,
|
||||
BarcodeFormat.ITF,
|
||||
BarcodeFormat.UPC_A,
|
||||
BarcodeFormat.UPC_E -> size / 3
|
||||
BarcodeFormat.UPCA,
|
||||
BarcodeFormat.UPCE -> size / 3
|
||||
|
||||
else -> size
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,11 @@ import android.os.PersistableBundle
|
||||
|
||||
fun Context.copyToClipboard(text: String, isSensitive: Boolean = false) {
|
||||
val service = getSystemService(Context.CLIPBOARD_SERVICE)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
@Suppress("DEPRECATION")
|
||||
(service as android.text.ClipboardManager).text = text
|
||||
} else {
|
||||
(service as android.content.ClipboardManager).setPrimaryClip(
|
||||
ClipData.newPlainText("plain text", text).apply {
|
||||
setSensitive(isSensitive)
|
||||
}
|
||||
)
|
||||
}
|
||||
(service as android.content.ClipboardManager).setPrimaryClip(
|
||||
ClipData.newPlainText("plain text", text).apply {
|
||||
setSensitive(isSensitive)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun ClipData.setSensitive(isSensitive: Boolean) {
|
||||
|
||||
@@ -5,7 +5,8 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.support.v4.content.FileProvider
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.net.toUri
|
||||
import de.markusfisch.android.binaryeye.BuildConfig
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.widget.toast
|
||||
@@ -54,12 +55,8 @@ fun Context.openUri(uri: Uri, silent: Boolean = false): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
fun String.parseAndNormalizeUri(): Uri = Uri.parse(this).let {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
it.normalizeScheme()
|
||||
} else {
|
||||
it
|
||||
}
|
||||
fun String.parseAndNormalizeUri(): Uri = toUri().let {
|
||||
it.normalizeScheme()
|
||||
}
|
||||
|
||||
fun Context.shareText(text: String, mimeType: String = "text/plain") {
|
||||
|
||||
@@ -3,15 +3,6 @@ package de.markusfisch.android.binaryeye.database
|
||||
import android.database.Cursor
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp
|
||||
|
||||
// Overwrite Kotlin's ".use" function for Cursor because Cursor cannot
|
||||
// be cast to Closeable below API level 16. This should be removed when
|
||||
// the minSDK is increased to at least JELLY_BEAN (16).
|
||||
inline fun <R> Cursor.use(block: (Cursor) -> R): R = try {
|
||||
block.invoke(this)
|
||||
} finally {
|
||||
close()
|
||||
}
|
||||
|
||||
fun Cursor.getInt(name: String): Int {
|
||||
val idx = getColumnIndex(name)
|
||||
return if (idx < 0) 0 else getInt(idx)
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.preference.Preferences
|
||||
import de.markusfisch.android.binaryeye.zxingcpp.migrateBarcodeFormatName
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
|
||||
|
||||
class Database {
|
||||
@@ -123,7 +124,9 @@ class Database {
|
||||
Scan(
|
||||
it.getString(SCANS_TEXT),
|
||||
it.getBlob(SCANS_RAW),
|
||||
BarcodeFormat.valueOf(it.getString(SCANS_FORMAT)),
|
||||
BarcodeFormat.valueOf(
|
||||
it.getString(SCANS_FORMAT).migrateBarcodeFormatName()
|
||||
),
|
||||
it.getString(SCANS_ERROR_CORRECTION_LEVEL),
|
||||
it.getString(SCANS_VERSION),
|
||||
it.getInt(SCANS_DATA_MASK),
|
||||
@@ -263,7 +266,7 @@ class Database {
|
||||
}
|
||||
|
||||
private class OpenHelper(context: Context) :
|
||||
SQLiteOpenHelper(context, FILE_NAME, null, 8) {
|
||||
SQLiteOpenHelper(context, FILE_NAME, null, 9) {
|
||||
override fun onCreate(db: SQLiteDatabase) {
|
||||
db.createScans()
|
||||
}
|
||||
@@ -294,6 +297,9 @@ class Database {
|
||||
if (oldVersion < 8) {
|
||||
db.addSymbolColumns()
|
||||
}
|
||||
if (oldVersion < 9) {
|
||||
db.migrateToNativeFormatNames()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,6 +397,43 @@ class Database {
|
||||
execSQL("UPDATE $SCANS SET $SCANS_GTIN_ISSUE_NUMBER = $SCANS_ISSUE_NUMBER")
|
||||
}
|
||||
|
||||
private fun SQLiteDatabase.migrateToNativeFormatNames() {
|
||||
val mappings = listOf(
|
||||
"NONE" to "None",
|
||||
"AZTEC" to "Aztec",
|
||||
"CODABAR" to "Codabar",
|
||||
"CODE_39" to "Code39",
|
||||
"CODE_39_EXT" to "Code39Ext",
|
||||
"CODE_32" to "Code32",
|
||||
"PZN" to "PZN",
|
||||
"CODE_93" to "Code93",
|
||||
"CODE_128" to "Code128",
|
||||
"DATA_BAR_OMNI" to "DataBarOmni",
|
||||
"DATA_BAR_STK" to "DataBarStk",
|
||||
"DATA_BAR_LTD" to "DataBarLtd",
|
||||
"DATA_BAR_EXPANDED" to "DataBarExp",
|
||||
"DATA_BAR_EXP_STK" to "DataBarExpStk",
|
||||
"DATA_MATRIX" to "DataMatrix",
|
||||
"DX_FILM_EDGE" to "DXFilmEdge",
|
||||
"EAN_8" to "EAN8",
|
||||
"EAN_13" to "EAN13",
|
||||
"ITF" to "ITF",
|
||||
"MAXICODE" to "MaxiCode",
|
||||
"PDF_417" to "PDF417",
|
||||
"QR_CODE" to "QRCode",
|
||||
"MICRO_QR_CODE" to "MicroQRCode",
|
||||
"RMQR_CODE" to "RMQRCode",
|
||||
"UPC_A" to "UPCA",
|
||||
"UPC_E" to "UPCE"
|
||||
)
|
||||
for ((oldName, newName) in mappings) {
|
||||
execSQL(
|
||||
"UPDATE $SCANS SET $SCANS_FORMAT = ? WHERE $SCANS_FORMAT = ?",
|
||||
arrayOf(newName, oldName)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SQLiteDatabase.migrateToVersionString() {
|
||||
execSQL("ALTER TABLE $SCANS ADD $SCANS_VERSION TEXT")
|
||||
execSQL("UPDATE $SCANS SET $SCANS_VERSION = $SCANS_VERSION_NUMBER")
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package de.markusfisch.android.binaryeye.database
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import de.markusfisch.android.binaryeye.zxingcpp.migrateBarcodeFormatName
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.BitMatrix
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.ContentType
|
||||
@@ -28,7 +27,7 @@ data class Scan(
|
||||
val dateTime: String = getDateTime(),
|
||||
var id: Long = 0L,
|
||||
val label: String? = null
|
||||
) : Parcelable {
|
||||
) {
|
||||
// Needs to be overwritten manually, as ByteArray is an array and
|
||||
// this isn't handled well by Kotlin.
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@@ -81,57 +80,6 @@ data class Scan(
|
||||
return result
|
||||
}
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
text = parcel.readString() ?: "",
|
||||
raw = parcel.readSizedByteArray(),
|
||||
format = BarcodeFormat.valueOf(parcel.readString() ?: ""),
|
||||
errorCorrectionLevel = parcel.readString(),
|
||||
version = parcel.readString(),
|
||||
dataMask = parcel.readInt(),
|
||||
symbol = parcel.readBitMatrix(),
|
||||
sequenceSize = parcel.readInt(),
|
||||
sequenceIndex = parcel.readInt(),
|
||||
sequenceId = parcel.readString() ?: "",
|
||||
country = parcel.readString(),
|
||||
addOn = parcel.readString(),
|
||||
price = parcel.readString(),
|
||||
issueNumber = parcel.readString(),
|
||||
dateTime = parcel.readString() ?: "",
|
||||
id = parcel.readLong(),
|
||||
label = parcel.readString()
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.apply {
|
||||
writeString(text)
|
||||
writeSizedByteArray(raw)
|
||||
writeString(format.name)
|
||||
writeString(errorCorrectionLevel)
|
||||
writeString(version)
|
||||
writeInt(dataMask)
|
||||
writeBitMatrix(symbol)
|
||||
writeInt(sequenceSize)
|
||||
writeInt(sequenceIndex)
|
||||
writeString(sequenceId)
|
||||
writeString(country)
|
||||
writeString(addOn)
|
||||
writeString(price)
|
||||
writeString(issueNumber)
|
||||
writeString(dateTime)
|
||||
writeLong(id)
|
||||
writeString(label)
|
||||
}
|
||||
}
|
||||
|
||||
override fun describeContents() = 0
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val CREATOR = object : Parcelable.Creator<Scan> {
|
||||
override fun createFromParcel(parcel: Parcel) = Scan(parcel)
|
||||
override fun newArray(size: Int) = arrayOfNulls<Scan>(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Result.toScan(): Scan {
|
||||
@@ -159,16 +107,62 @@ fun Result.toScan(): Scan {
|
||||
)
|
||||
}
|
||||
|
||||
fun Scan.toBundle() = Bundle().apply {
|
||||
putString(SCAN_TEXT, text)
|
||||
putByteArray(SCAN_RAW, raw)
|
||||
putString(SCAN_FORMAT, format.name)
|
||||
putString(SCAN_ERROR_CORRECTION_LEVEL, errorCorrectionLevel)
|
||||
putString(SCAN_VERSION, version)
|
||||
putInt(SCAN_DATA_MASK, dataMask)
|
||||
putInt(SCAN_SYMBOL_WIDTH, symbol?.width ?: 0)
|
||||
putInt(SCAN_SYMBOL_HEIGHT, symbol?.height ?: 0)
|
||||
putByteArray(SCAN_SYMBOL_DATA, symbol?.data)
|
||||
putInt(SCAN_SEQUENCE_SIZE, sequenceSize)
|
||||
putInt(SCAN_SEQUENCE_INDEX, sequenceIndex)
|
||||
putString(SCAN_SEQUENCE_ID, sequenceId)
|
||||
putString(SCAN_COUNTRY, country)
|
||||
putString(SCAN_ADD_ON, addOn)
|
||||
putString(SCAN_PRICE, price)
|
||||
putString(SCAN_ISSUE_NUMBER, issueNumber)
|
||||
putString(SCAN_DATE_TIME, dateTime)
|
||||
putLong(SCAN_ID, id)
|
||||
putString(SCAN_LABEL, label)
|
||||
}
|
||||
|
||||
fun Bundle.toScan(): Scan? {
|
||||
val formatName = getString(SCAN_FORMAT)?.migrateBarcodeFormatName()
|
||||
if (formatName.isNullOrEmpty()) {
|
||||
return null
|
||||
}
|
||||
return try {
|
||||
Scan(
|
||||
text = getString(SCAN_TEXT) ?: "",
|
||||
raw = getByteArray(SCAN_RAW),
|
||||
format = BarcodeFormat.valueOf(formatName),
|
||||
errorCorrectionLevel = getString(SCAN_ERROR_CORRECTION_LEVEL),
|
||||
version = getString(SCAN_VERSION),
|
||||
dataMask = getInt(SCAN_DATA_MASK, -1),
|
||||
symbol = getBitMatrix(),
|
||||
sequenceSize = getInt(SCAN_SEQUENCE_SIZE, -1),
|
||||
sequenceIndex = getInt(SCAN_SEQUENCE_INDEX, -1),
|
||||
sequenceId = getString(SCAN_SEQUENCE_ID) ?: "",
|
||||
country = getString(SCAN_COUNTRY),
|
||||
addOn = getString(SCAN_ADD_ON),
|
||||
price = getString(SCAN_PRICE),
|
||||
issueNumber = getString(SCAN_ISSUE_NUMBER),
|
||||
dateTime = getString(SCAN_DATE_TIME) ?: getDateTime(),
|
||||
id = getLong(SCAN_ID, 0L),
|
||||
label = getString(SCAN_LABEL)
|
||||
)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDateTime(
|
||||
time: Long = System.currentTimeMillis()
|
||||
) = DateFormat.format(
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
// Up to API level 17, 'k' was interpreted as 'H', which wasn't
|
||||
// implemented until API level 18.
|
||||
"yyyy-MM-dd kk:mm:ss"
|
||||
} else {
|
||||
"yyyy-MM-dd HH:mm:ss"
|
||||
},
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
time
|
||||
).toString() + String.format(
|
||||
Locale.getDefault(),
|
||||
@@ -176,39 +170,32 @@ private fun getDateTime(
|
||||
time % 1000
|
||||
)
|
||||
|
||||
private fun Parcel.writeSizedByteArray(array: ByteArray?) {
|
||||
val size = array?.size ?: 0
|
||||
writeInt(size)
|
||||
if (size > 0) {
|
||||
writeByteArray(array)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Parcel.readSizedByteArray(): ByteArray? {
|
||||
val size = readInt()
|
||||
return if (size > 0) {
|
||||
val array = ByteArray(size)
|
||||
readByteArray(array)
|
||||
array
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun Parcel.writeBitMatrix(bm: BitMatrix?) {
|
||||
writeInt(bm?.width ?: 0)
|
||||
bm?.let {
|
||||
writeInt(bm.height)
|
||||
writeSizedByteArray(bm.data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Parcel.readBitMatrix(): BitMatrix? {
|
||||
val width = readInt()
|
||||
if (width < 1) {
|
||||
private fun Bundle.getBitMatrix(): BitMatrix? {
|
||||
val width = getInt(SCAN_SYMBOL_WIDTH, 0)
|
||||
val height = getInt(SCAN_SYMBOL_HEIGHT, 0)
|
||||
val data = getByteArray(SCAN_SYMBOL_DATA)
|
||||
if (width < 1 || height < 1 || data == null) {
|
||||
return null
|
||||
}
|
||||
val height = readInt()
|
||||
val data = readSizedByteArray() ?: return null
|
||||
return BitMatrix(width, height, data)
|
||||
}
|
||||
|
||||
private const val SCAN_TEXT = "text"
|
||||
private const val SCAN_RAW = "raw"
|
||||
private const val SCAN_FORMAT = "format"
|
||||
private const val SCAN_ERROR_CORRECTION_LEVEL = "error_correction_level"
|
||||
private const val SCAN_VERSION = "version"
|
||||
private const val SCAN_DATA_MASK = "data_mask"
|
||||
private const val SCAN_SYMBOL_WIDTH = "symbol_width"
|
||||
private const val SCAN_SYMBOL_HEIGHT = "symbol_height"
|
||||
private const val SCAN_SYMBOL_DATA = "symbol_data"
|
||||
private const val SCAN_SEQUENCE_SIZE = "sequence_size"
|
||||
private const val SCAN_SEQUENCE_INDEX = "sequence_index"
|
||||
private const val SCAN_SEQUENCE_ID = "sequence_id"
|
||||
private const val SCAN_COUNTRY = "country"
|
||||
private const val SCAN_ADD_ON = "add_on"
|
||||
private const val SCAN_PRICE = "price"
|
||||
private const val SCAN_ISSUE_NUMBER = "issue_number"
|
||||
private const val SCAN_DATE_TIME = "date_time"
|
||||
private const val SCAN_ID = "id"
|
||||
private const val SCAN_LABEL = "label"
|
||||
|
||||
+74
-36
@@ -9,15 +9,17 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.RequiresApi
|
||||
import android.support.v14.preference.MultiSelectListPreference
|
||||
import android.support.v7.preference.ListPreference
|
||||
import android.support.v7.preference.Preference
|
||||
import android.support.v7.preference.PreferenceFragmentCompat
|
||||
import android.support.v7.preference.PreferenceGroup
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.MultiSelectListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceGroup
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.activity.AutomatedActionsActivity
|
||||
import de.markusfisch.android.binaryeye.activity.NetworkSuggestionsActivity
|
||||
import de.markusfisch.android.binaryeye.activity.ProfilesActivity
|
||||
import de.markusfisch.android.binaryeye.activity.SplashActivity
|
||||
import de.markusfisch.android.binaryeye.app.addFragment
|
||||
import de.markusfisch.android.binaryeye.app.hasBluetoothPermission
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.bluetooth.setBluetoothHosts
|
||||
@@ -36,7 +38,7 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
key: String?
|
||||
) {
|
||||
key ?: return
|
||||
val preference = findPreference(key) ?: return
|
||||
val preference = findPreference<Preference>(key) ?: return
|
||||
if (preference.key != PROFILE) {
|
||||
prefs.update()
|
||||
}
|
||||
@@ -76,8 +78,9 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
preferenceScreen = null
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||
preferenceScreen.sharedPreferences
|
||||
.registerOnSharedPreferenceChangeListener(changeListener)
|
||||
?.registerOnSharedPreferenceChangeListener(changeListener)
|
||||
setSummaries(preferenceScreen)
|
||||
setIcons()
|
||||
|
||||
wireProfiles()
|
||||
wireAutomatedActions()
|
||||
@@ -86,23 +89,21 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
|
||||
private fun wireProfiles() {
|
||||
findPreference(PROFILE).apply {
|
||||
findPreference<Preference>(PROFILE)?.apply {
|
||||
updateProfileSummary(this)
|
||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.supportFragmentManager?.addFragment(
|
||||
ProfilesFragment()
|
||||
)
|
||||
startActivity(Intent(activity, ProfilesActivity::class.java))
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun wireAutomatedActions() {
|
||||
findPreference(AUTOMATED_ACTIONS).apply {
|
||||
findPreference<Preference>(AUTOMATED_ACTIONS)?.apply {
|
||||
updateAutomatedActionsSummary(this)
|
||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
activity?.supportFragmentManager?.addFragment(
|
||||
AutomatedActionsFragment()
|
||||
startActivity(
|
||||
Intent(activity, AutomatedActionsActivity::class.java)
|
||||
)
|
||||
true
|
||||
}
|
||||
@@ -113,20 +114,20 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
if (prefs.sendScanBluetooth &&
|
||||
activity?.hasBluetoothPermission() == true
|
||||
) {
|
||||
setBluetoothHosts(
|
||||
findPreference("send_scan_bluetooth_host") as ListPreference
|
||||
)
|
||||
findPreference<ListPreference>("send_scan_bluetooth_host")?.let {
|
||||
setBluetoothHosts(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun wireClearNetworkPreferences() {
|
||||
findPreference("clear_network_suggestions").apply {
|
||||
findPreference<Preference>("clear_network_suggestions")?.apply {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
|
||||
// From R+ we can query past network suggestions and
|
||||
// make them editable.
|
||||
setOnPreferenceClickListener {
|
||||
activity?.supportFragmentManager?.addFragment(
|
||||
NetworkSuggestionsFragment()
|
||||
startActivity(
|
||||
Intent(activity, NetworkSuggestionsActivity::class.java)
|
||||
)
|
||||
true
|
||||
}
|
||||
@@ -135,10 +136,10 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
// Note that previous versions of this app allowed
|
||||
// adding network suggestions on Q as well, so we
|
||||
// need to keep this option.
|
||||
setOnPreferenceClickListener {
|
||||
context.askToClearNetworkSuggestions()
|
||||
true
|
||||
}
|
||||
setOnPreferenceClickListener {
|
||||
context?.askToClearNetworkSuggestions()
|
||||
true
|
||||
}
|
||||
} else {
|
||||
// There are no network suggestions below Q.
|
||||
isVisible = false
|
||||
@@ -176,10 +177,10 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
loadPreferences()
|
||||
}
|
||||
activity?.setTitle(R.string.preferences)
|
||||
findPreference(AUTOMATED_ACTIONS)?.let {
|
||||
findPreference<Preference>(AUTOMATED_ACTIONS)?.let {
|
||||
updateAutomatedActionsSummary(it)
|
||||
}
|
||||
findPreference(PROFILE)?.let {
|
||||
findPreference<Preference>(PROFILE)?.let {
|
||||
updateProfileSummary(it)
|
||||
}
|
||||
listView.setPaddingFromWindowInsets()
|
||||
@@ -190,12 +191,12 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
preferenceScreen.sharedPreferences
|
||||
.unregisterOnSharedPreferenceChangeListener(changeListener)
|
||||
?.unregisterOnSharedPreferenceChangeListener(changeListener)
|
||||
}
|
||||
|
||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||
if (preference is UrlPreference) {
|
||||
val fm = fragmentManager
|
||||
val fm = parentFragmentManager
|
||||
UrlDialogFragment.newInstance(preference.key).apply {
|
||||
setTargetFragment(this@PreferencesFragment, 0)
|
||||
show(fm, null)
|
||||
@@ -244,6 +245,45 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setIcons() {
|
||||
setIcon(PROFILE, R.drawable.ic_action_profile)
|
||||
setIcon("formats", R.drawable.ic_action_restrict_format)
|
||||
setIcon("show_crop_handle", R.drawable.ic_action_scan)
|
||||
setIcon("zoom_by_swiping", R.drawable.ic_action_search)
|
||||
setIcon("auto_rotate", R.drawable.ic_action_rotation_unlocked)
|
||||
setIcon("try_harder", R.drawable.ic_action_search)
|
||||
setIcon("bulk_mode", R.drawable.ic_action_bulk_mode)
|
||||
setIcon("bulk_mode_delay", R.drawable.ic_action_bulk_mode)
|
||||
setIcon("show_toast_in_bulk_mode", R.drawable.ic_action_bulk_mode)
|
||||
setIcon("vibrate", R.drawable.ic_action_info)
|
||||
setIcon("beep", R.drawable.ic_action_info)
|
||||
setIcon("beep_tone_name", R.drawable.ic_action_info)
|
||||
setIcon("use_history", R.drawable.ic_action_history)
|
||||
setIcon("ignore_duplicates_name", R.drawable.ic_action_remove)
|
||||
setIcon("copy_immediately", R.drawable.ic_action_copy)
|
||||
setIcon("send_scan_active", R.drawable.ic_action_share)
|
||||
setIcon("send_scan_url", R.drawable.ic_action_link)
|
||||
setIcon("send_scan_type", R.drawable.ic_action_share)
|
||||
setIcon("send_scan_bluetooth", R.drawable.ic_action_wifi)
|
||||
setIcon("send_scan_bluetooth_host", R.drawable.ic_action_wifi)
|
||||
setIcon("open_immediately", R.drawable.ic_action_open)
|
||||
setIcon("show_meta_data", R.drawable.ic_action_info)
|
||||
setIcon("show_hex_dump", R.drawable.ic_action_info)
|
||||
setIcon("show_checksum", R.drawable.ic_action_info)
|
||||
setIcon("show_recreation", R.drawable.ic_action_create)
|
||||
setIcon("close_automatically", R.drawable.ic_action_remove)
|
||||
setIcon("default_search_url", R.drawable.ic_action_search)
|
||||
setIcon("open_with_url", R.drawable.ic_action_link)
|
||||
setIcon(AUTOMATED_ACTIONS, R.drawable.ic_action_create)
|
||||
setIcon("clear_network_suggestions", R.drawable.ic_action_wifi)
|
||||
setIcon("brighten_screen", R.drawable.ic_action_bright)
|
||||
setIcon("custom_locale", R.drawable.ic_action_preferences)
|
||||
}
|
||||
|
||||
private fun setIcon(key: String, iconResId: Int) {
|
||||
findPreference<Preference>(key)?.setIcon(iconResId)
|
||||
}
|
||||
|
||||
private fun updateAutomatedActionsSummary(preference: Preference) {
|
||||
val count = prefs.automatedActions.size
|
||||
preference.summary = if (count == 0) {
|
||||
@@ -270,12 +310,10 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
|
||||
private fun Activity.restartApp() {
|
||||
val intent = Intent(this, SplashActivity::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
intent.addFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
)
|
||||
}
|
||||
intent.addFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
// Restart to begin with an unmodified Locale to follow system settings.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package de.markusfisch.android.binaryeye.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v7.preference.PreferenceDialogFragmentCompat
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.preference.PreferenceDialogFragmentCompat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.database.Scan
|
||||
@@ -15,10 +15,10 @@ class UrlDialogFragment : PreferenceDialogFragmentCompat() {
|
||||
private var urlView: TextView? = null
|
||||
private var testButton: TextView? = null
|
||||
|
||||
override fun onBindDialogView(view: View?) {
|
||||
override fun onBindDialogView(view: View) {
|
||||
super.onBindDialogView(view)
|
||||
urlView = view?.findViewById(R.id.url)
|
||||
testButton = view?.findViewById(R.id.test_url)
|
||||
urlView = view.findViewById(R.id.url)
|
||||
testButton = view.findViewById(R.id.test_url)
|
||||
testButton?.setOnClickListener {
|
||||
testUrl(testButton)
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class UrlDialogFragment : PreferenceDialogFragmentCompat() {
|
||||
Scan(
|
||||
"test",
|
||||
null,
|
||||
BarcodeFormat.NONE
|
||||
BarcodeFormat.None
|
||||
).sendAsync(url, prefs.sendScanType) { code, body ->
|
||||
textView.text = when {
|
||||
code != null -> "$code"
|
||||
|
||||
@@ -3,7 +3,7 @@ package de.markusfisch.android.binaryeye.graphics
|
||||
import android.content.Context
|
||||
import android.graphics.DashPathEffect
|
||||
import android.graphics.Paint
|
||||
import android.support.v4.content.ContextCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
fun Context.getDashedBorderPaint() = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
|
||||
@@ -5,26 +5,22 @@ import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.createBitmap
|
||||
|
||||
fun Resources.getBitmapFromDrawable(
|
||||
resId: Int
|
||||
): Bitmap = getBitmapFromDrawable(getDrawableCompat(resId))
|
||||
|
||||
fun Resources.getDrawableCompat(
|
||||
resId: Int
|
||||
): Drawable = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getDrawable(resId, null)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
getDrawable(resId)
|
||||
}
|
||||
): Bitmap = getBitmapFromDrawable(
|
||||
ResourcesCompat.getDrawable(this, resId, null) ?: throw Resources.NotFoundException(
|
||||
"Drawable resource ID #0x${resId.toString(16)}"
|
||||
)
|
||||
)
|
||||
|
||||
private fun getBitmapFromDrawable(drawable: Drawable): Bitmap {
|
||||
if (drawable is BitmapDrawable) {
|
||||
return drawable.bitmap
|
||||
}
|
||||
val bitmap = Bitmap.createBitmap(
|
||||
val bitmap = createBitmap(
|
||||
drawable.intrinsicWidth,
|
||||
drawable.intrinsicHeight,
|
||||
Bitmap.Config.ARGB_8888
|
||||
|
||||
@@ -2,12 +2,13 @@ package de.markusfisch.android.binaryeye.graphics
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import androidx.core.graphics.createBitmap
|
||||
|
||||
fun Bitmap.fixTransparency(): Bitmap {
|
||||
val result = analyzeTransparency()
|
||||
val cfg = config
|
||||
return if (cfg != null && result.hasTransparentPixels) {
|
||||
val copy = Bitmap.createBitmap(
|
||||
val copy = createBitmap(
|
||||
width,
|
||||
height,
|
||||
cfg
|
||||
|
||||
@@ -6,8 +6,8 @@ import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.support.annotation.MainThread
|
||||
import android.widget.EditText
|
||||
import androidx.annotation.MainThread
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.alertDialog
|
||||
import java.io.File
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.markusfisch.android.binaryeye.preference
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Point
|
||||
import androidx.core.content.edit
|
||||
import org.json.JSONObject
|
||||
|
||||
fun SharedPreferences.storeCropHandle(
|
||||
@@ -10,13 +11,15 @@ fun SharedPreferences.storeCropHandle(
|
||||
viewHeight: Int,
|
||||
cropHandle: Point
|
||||
) {
|
||||
edit().putString(
|
||||
cropHandleKey(name, viewWidth, viewHeight),
|
||||
JSONObject().apply {
|
||||
put("x", cropHandle.x)
|
||||
put("y", cropHandle.y)
|
||||
}.toString()
|
||||
).apply()
|
||||
edit {
|
||||
putString(
|
||||
cropHandleKey(name, viewWidth, viewHeight),
|
||||
JSONObject().apply {
|
||||
put("x", cropHandle.x)
|
||||
put("y", cropHandle.y)
|
||||
}.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun SharedPreferences.restoreCropHandle(
|
||||
|
||||
@@ -5,12 +5,12 @@ import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Point
|
||||
import android.media.ToneGenerator
|
||||
import android.os.Build
|
||||
import android.preference.PreferenceManager
|
||||
import android.support.annotation.RequiresApi
|
||||
import androidx.core.content.edit
|
||||
import de.markusfisch.android.binaryeye.automation.AutomatedAction
|
||||
import de.markusfisch.android.binaryeye.automation.AutomatedAction.Companion.fromJsonArray
|
||||
import de.markusfisch.android.binaryeye.automation.AutomatedAction.Companion.toJsonArray
|
||||
import de.markusfisch.android.binaryeye.zxingcpp.migrateBarcodeFormatName
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
|
||||
import org.json.JSONArray
|
||||
|
||||
@@ -22,31 +22,39 @@ class Preferences {
|
||||
|
||||
var profile: String? = null
|
||||
set(value) {
|
||||
defaultPreferences.edit().putString(PROFILE, value).apply()
|
||||
defaultPreferences.edit {
|
||||
putString(PROFILE, value)
|
||||
}
|
||||
field = value
|
||||
}
|
||||
var barcodeFormats = setOf(
|
||||
BarcodeFormat.AZTEC.name,
|
||||
BarcodeFormat.CODABAR.name,
|
||||
BarcodeFormat.CODE_39.name,
|
||||
BarcodeFormat.CODE_93.name,
|
||||
BarcodeFormat.CODE_128.name,
|
||||
BarcodeFormat.DATA_BAR.name,
|
||||
BarcodeFormat.DATA_BAR_EXPANDED.name,
|
||||
BarcodeFormat.DATA_MATRIX.name,
|
||||
BarcodeFormat.DX_FILM_EDGE.name,
|
||||
BarcodeFormat.EAN_8.name,
|
||||
BarcodeFormat.EAN_13.name,
|
||||
BarcodeFormat.Aztec.name,
|
||||
BarcodeFormat.Codabar.name,
|
||||
BarcodeFormat.Code39.name,
|
||||
BarcodeFormat.Code39Ext.name,
|
||||
BarcodeFormat.Code32.name,
|
||||
BarcodeFormat.PZN.name,
|
||||
BarcodeFormat.Code93.name,
|
||||
BarcodeFormat.Code128.name,
|
||||
BarcodeFormat.DataBar.name,
|
||||
BarcodeFormat.DataBarOmni.name,
|
||||
BarcodeFormat.DataBarStk.name,
|
||||
BarcodeFormat.DataBarLtd.name,
|
||||
BarcodeFormat.DataBarExp.name,
|
||||
BarcodeFormat.DataBarExpStk.name,
|
||||
BarcodeFormat.DataMatrix.name,
|
||||
BarcodeFormat.DXFilmEdge.name,
|
||||
BarcodeFormat.EAN8.name,
|
||||
BarcodeFormat.EAN13.name,
|
||||
BarcodeFormat.ITF.name,
|
||||
BarcodeFormat.MAXICODE.name,
|
||||
BarcodeFormat.PDF_417.name,
|
||||
BarcodeFormat.QR_CODE.name,
|
||||
BarcodeFormat.MICRO_QR_CODE.name,
|
||||
BarcodeFormat.RMQR_CODE.name,
|
||||
BarcodeFormat.UPC_A.name,
|
||||
BarcodeFormat.UPC_E.name,
|
||||
BarcodeFormat.MaxiCode.name,
|
||||
BarcodeFormat.PDF417.name,
|
||||
BarcodeFormat.QRCode.name,
|
||||
BarcodeFormat.MicroQRCode.name,
|
||||
BarcodeFormat.RMQRCode.name,
|
||||
BarcodeFormat.UPCA.name,
|
||||
BarcodeFormat.UPCE.name,
|
||||
)
|
||||
@RequiresApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
set(value) {
|
||||
apply(BARCODE_FORMATS, value)
|
||||
field = value
|
||||
@@ -270,10 +278,9 @@ class Preferences {
|
||||
}
|
||||
|
||||
fun saveProfiles() {
|
||||
defaultPreferences.edit().putString(
|
||||
PROFILES,
|
||||
JSONArray(profiles).toString()
|
||||
).apply()
|
||||
defaultPreferences.edit {
|
||||
putString(PROFILES, JSONArray(profiles).toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun loadProfiles() {
|
||||
@@ -286,14 +293,24 @@ class Preferences {
|
||||
}
|
||||
|
||||
fun update() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
preferences.getStringSet(BARCODE_FORMATS, barcodeFormats)?.let {
|
||||
barcodeFormats = addFormatsOnUpdate(
|
||||
it,
|
||||
BarcodeFormat.RMQR_CODE,
|
||||
BarcodeFormat.DX_FILM_EDGE
|
||||
)
|
||||
preferences.getStringSet(BARCODE_FORMATS, barcodeFormats)?.let {
|
||||
val migrated = migrateBarcodeFormats(it)
|
||||
if (migrated != it) {
|
||||
apply(BARCODE_FORMATS, migrated)
|
||||
}
|
||||
barcodeFormats = addFormatsOnUpdate(
|
||||
migrated,
|
||||
BarcodeFormat.Code39Ext,
|
||||
BarcodeFormat.Code32,
|
||||
BarcodeFormat.PZN,
|
||||
BarcodeFormat.DataBarOmni,
|
||||
BarcodeFormat.DataBarStk,
|
||||
BarcodeFormat.DataBarLtd,
|
||||
BarcodeFormat.DataBarExp,
|
||||
BarcodeFormat.DataBarExpStk,
|
||||
BarcodeFormat.RMQRCode,
|
||||
BarcodeFormat.DXFilmEdge
|
||||
)
|
||||
}
|
||||
|
||||
showCropHandle = preferences.getBoolean(
|
||||
@@ -322,7 +339,9 @@ class Preferences {
|
||||
// Map old setting to new one if it wasn't on default value.
|
||||
val ignoreConsecutiveDuplicates = "ignore_consecutive_duplicates"
|
||||
if (!preferences.getBoolean(ignoreConsecutiveDuplicates, true)) {
|
||||
preferences.edit().remove(ignoreConsecutiveDuplicates).apply()
|
||||
preferences.edit {
|
||||
remove(ignoreConsecutiveDuplicates)
|
||||
}
|
||||
ignoreDuplicatesName = "accept_duplicates"
|
||||
}
|
||||
|
||||
@@ -418,12 +437,20 @@ class Preferences {
|
||||
for (format in formats) {
|
||||
val name = "${format.name}_added"
|
||||
if (!preferences.getBoolean(name, false)) {
|
||||
preferences.edit().putBoolean(name, true).apply()
|
||||
preferences.edit {
|
||||
putBoolean(name, true)
|
||||
}
|
||||
add(format.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun migrateBarcodeFormats(formats: Set<String>): Set<String> {
|
||||
return formats.mapTo(mutableSetOf()) { format ->
|
||||
format.migrateBarcodeFormatName()
|
||||
}
|
||||
}
|
||||
|
||||
fun restoreCropHandle(
|
||||
name: String,
|
||||
viewWidth: Int,
|
||||
@@ -452,33 +479,41 @@ class Preferences {
|
||||
else -> IgnoreDuplicates.Never
|
||||
}
|
||||
|
||||
private fun put(label: String, value: Boolean) =
|
||||
preferences.edit().putBoolean(label, value)
|
||||
|
||||
private fun apply(label: String, value: Boolean) {
|
||||
put(label, value).apply()
|
||||
preferences.edit {
|
||||
putBoolean(label, value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun apply(label: String, value: String) {
|
||||
preferences.edit().putString(label, value).apply()
|
||||
preferences.edit {
|
||||
putString(label, value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun apply(label: String, value: Int) {
|
||||
preferences.edit().putInt(label, value).apply()
|
||||
preferences.edit {
|
||||
putInt(label, value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun apply(label: String, value: Float) {
|
||||
preferences.edit().putFloat(label, value).apply()
|
||||
preferences.edit {
|
||||
putFloat(label, value)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
private fun commit(label: String, value: String) {
|
||||
preferences.edit().putString(label, value).commit()
|
||||
preferences.edit(true) {
|
||||
putString(label, value)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
private fun apply(label: String, value: Set<String>) {
|
||||
preferences.edit().putStringSet(label, value).apply()
|
||||
preferences.edit {
|
||||
putStringSet(label, value)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package de.markusfisch.android.binaryeye.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v7.preference.DialogPreference
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.DialogPreference
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
class UrlPreference(
|
||||
context: Context?,
|
||||
context: Context,
|
||||
attrs: AttributeSet?
|
||||
) : DialogPreference(context, attrs) {
|
||||
private var url: String? = null
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.TileService
|
||||
import android.support.annotation.RequiresApi
|
||||
import androidx.annotation.RequiresApi
|
||||
import de.markusfisch.android.binaryeye.activity.CameraActivity
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
|
||||
@@ -2,16 +2,16 @@ package de.markusfisch.android.binaryeye.view
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.AbsListView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
val systemBarListViewScrollListener = object : AbsListView.OnScrollListener {
|
||||
@@ -43,7 +43,7 @@ val systemBarRecyclerViewScrollListener = object : RecyclerView.OnScrollListener
|
||||
layoutManager.findFirstCompletelyVisibleItemPosition() != 0
|
||||
val scrollable = scrolled ||
|
||||
layoutManager.findLastVisibleItemPosition() <
|
||||
recyclerView.adapter.itemCount - 1
|
||||
(recyclerView.adapter?.itemCount ?: 0) - 1
|
||||
colorSystemAndToolBars(recyclerView.context, scrolled, scrollable)
|
||||
}
|
||||
|
||||
@@ -62,23 +62,21 @@ private fun lastChildOutOfView(listView: AbsListView): Boolean {
|
||||
}
|
||||
|
||||
fun AppCompatActivity.initBars() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// Keeps the soft keyboard from repositioning the layout.
|
||||
window.setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|
||||
)
|
||||
window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
}
|
||||
// Keeps the soft keyboard from repositioning the layout.
|
||||
window.setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|
||||
)
|
||||
window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
colorSystemAndToolBars(this)
|
||||
setPaddingFromWindowInsets(
|
||||
findViewById(R.id.main),
|
||||
(findViewById(R.id.toolbar) as Toolbar).apply {
|
||||
setSupportActionBar(this)
|
||||
},
|
||||
findViewById(R.id.navbar)?.apply {
|
||||
findViewById<View>(R.id.navbar)?.apply {
|
||||
setBackgroundColor(translucentPrimaryColor)
|
||||
}
|
||||
)
|
||||
@@ -94,7 +92,6 @@ fun unlockStatusBarColor() {
|
||||
}
|
||||
|
||||
private var translucentPrimaryColor = 0
|
||||
private val actionBarBackground = ColorDrawable()
|
||||
fun colorSystemAndToolBars(
|
||||
context: Context,
|
||||
scrolled: Boolean = false,
|
||||
@@ -108,40 +105,29 @@ fun colorSystemAndToolBars(
|
||||
}
|
||||
val topColor = if (scrolled) translucentPrimaryColor else 0
|
||||
val activity = getAppCompatActivity(context) ?: return
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// System bars no longer have a background from SDK35+.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
val window = activity.window
|
||||
if (!statusBarColorLocked) {
|
||||
@Suppress("DEPRECATION")
|
||||
window.statusBarColor = topColor
|
||||
}
|
||||
// System bars no longer have a background from SDK35+.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
val window = activity.window
|
||||
if (!statusBarColorLocked) {
|
||||
@Suppress("DEPRECATION")
|
||||
window.navigationBarColor = if (scrolled || scrollable) {
|
||||
translucentPrimaryColor
|
||||
} else {
|
||||
0
|
||||
}
|
||||
window.statusBarColor = topColor
|
||||
}
|
||||
@Suppress("DEPRECATION")
|
||||
window.navigationBarColor = if (scrolled || scrollable) {
|
||||
translucentPrimaryColor
|
||||
} else {
|
||||
activity.findViewById(R.id.navbar)?.apply {
|
||||
visibility = if (scrolled || scrollable) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
0
|
||||
}
|
||||
} else {
|
||||
activity.findViewById<View>(R.id.navbar)?.apply {
|
||||
visibility = if (scrolled || scrollable) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
activity.supportActionBar?.setBackgroundDrawable(
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
// Avoid allocation on Honeycomb and better.
|
||||
actionBarBackground.color = topColor
|
||||
actionBarBackground
|
||||
} else {
|
||||
// ColorDrawable.setColor() doesn't exist pre Honeycomb.
|
||||
ColorDrawable(topColor)
|
||||
}
|
||||
)
|
||||
activity.supportActionBar?.setBackgroundDrawable(topColor.toDrawable())
|
||||
}
|
||||
|
||||
private fun getAppCompatActivity(context: Context): AppCompatActivity? {
|
||||
|
||||
@@ -2,12 +2,11 @@ package de.markusfisch.android.binaryeye.view
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
import android.support.annotation.RequiresApi
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.support.v4.view.WindowInsetsCompat
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.View
|
||||
import android.view.WindowInsets
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
|
||||
private var toolbarHeight = 0
|
||||
fun setPaddingFromWindowInsets(
|
||||
@@ -53,19 +52,15 @@ fun View.setPaddingFromWindowInsets() {
|
||||
// For the original post see here:
|
||||
// https://medium.com/androiddevelopers/windowinsets-listeners-to-layouts-8f9ccc8fa4d1
|
||||
fun View.doOnApplyWindowInsets(f: (View, Rect) -> Unit) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
f(this, insetsWithToolbar())
|
||||
} else {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
|
||||
f(v, insetsWithToolbar(insets))
|
||||
insets
|
||||
}
|
||||
// It's important to explicitly request the insets (again) in
|
||||
// case the view was created in Fragment.onCreateView() because
|
||||
// setOnApplyWindowInsetsListener() won't fire when the view
|
||||
// isn't attached.
|
||||
requestApplyInsetsWhenAttached()
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
|
||||
f(v, insetsWithToolbar(insets))
|
||||
insets
|
||||
}
|
||||
// It's important to explicitly request the insets (again) in
|
||||
// case the view was created in Fragment.onCreateView() because
|
||||
// setOnApplyWindowInsetsListener() won't fire when the view
|
||||
// isn't attached.
|
||||
requestApplyInsetsWhenAttached()
|
||||
}
|
||||
|
||||
private fun insetsWithToolbar(insets: WindowInsetsCompat? = null) = Rect(
|
||||
@@ -75,7 +70,6 @@ private fun insetsWithToolbar(insets: WindowInsetsCompat? = null) = Rect(
|
||||
insets?.systemWindowInsetBottom ?: 0
|
||||
)
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
private fun View.requestApplyInsetsWhenAttached() {
|
||||
if (isAttachedToWindow) {
|
||||
ViewCompat.requestApplyInsets(this)
|
||||
|
||||
@@ -9,14 +9,14 @@ import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.graphics.Region
|
||||
import android.os.Build
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.withSave
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.graphics.getBitmapFromDrawable
|
||||
import de.markusfisch.android.binaryeye.graphics.getDashedBorderPaint
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
@@ -34,7 +34,6 @@ class DetectorView : View {
|
||||
coordinatesLast = 0
|
||||
invalidate()
|
||||
}
|
||||
private val roiPaint = context.getDashedBorderPaint()
|
||||
private val dotPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
color = ContextCompat.getColor(context, R.color.dot)
|
||||
style = Paint.Style.FILL
|
||||
@@ -270,10 +269,8 @@ class DetectorView : View {
|
||||
if (minDist < 1) {
|
||||
return
|
||||
}
|
||||
// canvas.clipRect() doesn't work reliably below KITKAT.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
val radius = min(minDist / 2, cornerRadius).toFloat()
|
||||
save()
|
||||
val radius = min(minDist / 2, cornerRadius).toFloat()
|
||||
withSave {
|
||||
clipOutPathCompat(
|
||||
calculateRoundedRectPath(
|
||||
roi.left.toFloat(),
|
||||
@@ -285,9 +282,6 @@ class DetectorView : View {
|
||||
)
|
||||
)
|
||||
drawColor(shadeColor)
|
||||
restore()
|
||||
} else {
|
||||
drawRect(roi, roiPaint)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.markusfisch.android.binaryeye.zxingcpp
|
||||
|
||||
/**
|
||||
* Translate legacy barcode format names from ZXingC++ before 3.x
|
||||
* to current BarcodeFormat enum names.
|
||||
*/
|
||||
fun String.migrateBarcodeFormatName() = when (this) {
|
||||
"NONE" -> "None"
|
||||
"AZTEC" -> "Aztec"
|
||||
"CODABAR" -> "Codabar"
|
||||
"CODE_39" -> "Code39"
|
||||
"CODE_39_EXT" -> "Code39Ext"
|
||||
"CODE_32" -> "Code32"
|
||||
"PZN" -> "PZN"
|
||||
"CODE_93" -> "Code93"
|
||||
"CODE_128" -> "Code128"
|
||||
"DATA_BAR" -> "DataBar"
|
||||
"DATA_BAR_OMNI" -> "DataBarOmni"
|
||||
"DATA_BAR_STK" -> "DataBarStk"
|
||||
"DATA_BAR_LTD" -> "DataBarLtd"
|
||||
"DATA_BAR_EXPANDED" -> "DataBarExp"
|
||||
"DATA_BAR_EXP_STK" -> "DataBarExpStk"
|
||||
"DATA_MATRIX" -> "DataMatrix"
|
||||
"DX_FILM_EDGE" -> "DXFilmEdge"
|
||||
"EAN_8" -> "EAN8"
|
||||
"EAN_13" -> "EAN13"
|
||||
"ITF" -> "ITF"
|
||||
"MAXICODE" -> "MaxiCode"
|
||||
"PDF_417" -> "PDF417"
|
||||
"QR_CODE" -> "QRCode"
|
||||
"MICRO_QR_CODE" -> "MicroQRCode"
|
||||
"RMQR_CODE" -> "RMQRCode"
|
||||
"UPC_A" -> "UPCA"
|
||||
"UPC_E" -> "UPCE"
|
||||
else -> this
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<de.markusfisch.android.cameraview.widget.CameraView
|
||||
<merge
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<androidx.camera.view.PreviewView
|
||||
android:id="@+id/camera_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
android:layout_height="match_parent"
|
||||
app:scaleType="fillCenter"/>
|
||||
<de.markusfisch.android.binaryeye.widget.DetectorView
|
||||
android:id="@+id/detector_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -19,15 +22,13 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginRight="88dp"
|
||||
android:layout_marginEnd="88dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:padding="24dp"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/flash"
|
||||
android:contentDescription="@string/toggle_flash"
|
||||
android:src="@drawable/ic_action_flash"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</merge>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
@@ -8,17 +8,17 @@
|
||||
android:id="@+id/detector_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="@bool/fitsSystemWindows">
|
||||
<include layout="@layout/toolbar"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/scan"
|
||||
android:contentDescription="@string/scan_code"
|
||||
android:src="@drawable/ic_action_next"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
<include layout="@layout/navbar"/>
|
||||
</merge>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -22,11 +23,11 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:drawableTop="@drawable/logo"
|
||||
android:drawablePadding="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/welcome"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="@string/welcome"/>
|
||||
app:drawableTopCompat="@drawable/logo"/>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/WelcomeButton"
|
||||
@@ -54,4 +55,4 @@
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
android:clipToPadding="false"
|
||||
android:divider="@color/separator"
|
||||
android:dividerHeight="1px"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@@ -22,10 +22,10 @@
|
||||
android:gravity="center"
|
||||
android:padding="32dp"
|
||||
android:text="@string/automated_actions_empty"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/add"
|
||||
android:contentDescription="@string/automated_action_add"
|
||||
android:src="@drawable/ic_action_create"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@string/view_barcode"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/share"
|
||||
android:contentDescription="@string/share"
|
||||
android:src="@drawable/ic_action_share"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -77,14 +77,14 @@
|
||||
android:contentDescription="@string/view_barcode"/>
|
||||
</LinearLayout>
|
||||
</de.markusfisch.android.binaryeye.widget.ConfinedScrollView>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/open"
|
||||
android:contentDescription="@string/open_url"
|
||||
android:src="@drawable/ic_action_open"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -65,22 +65,21 @@
|
||||
android:id="@+id/colors"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:entries="@array/colors"/>
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:visibility="gone"
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/add_quiet_zone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_quiet_zone"/>
|
||||
</LinearLayout>
|
||||
</de.markusfisch.android.binaryeye.widget.ConfinedScrollView>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/encode"
|
||||
android:contentDescription="@string/encode"
|
||||
android:src="@drawable/ic_action_next"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
android:clipToPadding="false"
|
||||
android:divider="@color/separator"
|
||||
android:dividerHeight="1px"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:visibility="gone"
|
||||
android:id="@+id/use_history"
|
||||
android:layout_width="match_parent"
|
||||
@@ -22,12 +22,12 @@
|
||||
android:layout_alignParentTop="true"
|
||||
android:padding="16dp"
|
||||
android:text="@string/use_history"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/share"
|
||||
android:contentDescription="@string/share"
|
||||
android:src="@drawable/ic_action_share"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
<include layout="@layout/progress_view"/>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
android:clipToPadding="false"
|
||||
android:divider="@color/separator"
|
||||
android:dividerHeight="1px"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@@ -23,10 +23,10 @@
|
||||
android:gravity="center"
|
||||
android:padding="32dp"
|
||||
android:text="@string/clear_network_suggestions_nothing_to_remove"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/remove"
|
||||
android:contentDescription="@string/remove_suggestion"
|
||||
android:src="@drawable/ic_action_remove"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
android:clipToPadding="false"
|
||||
android:divider="@color/separator"
|
||||
android:dividerHeight="1px"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@@ -22,10 +22,10 @@
|
||||
android:gravity="center"
|
||||
android:padding="32dp"
|
||||
android:text="@string/profile_empty"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/add"
|
||||
android:contentDescription="@string/profile_add"
|
||||
android:src="@drawable/ic_action_create"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"/>
|
||||
<TextView
|
||||
@@ -18,9 +17,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:layout_toRightOf="@+id/time"
|
||||
android:layout_toEndOf="@+id/time"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"/>
|
||||
<TextView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<android.support.v7.widget.Toolbar
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="Overdraw"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
android:id="@+id/search"
|
||||
android:icon="@drawable/ic_action_search"
|
||||
android:title="@string/search_scan"
|
||||
material:actionViewClass="android.support.v7.widget.SearchView"
|
||||
material:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
material:showAsAction="collapseActionView|always"/>
|
||||
<item
|
||||
android:id="@+id/export_history"
|
||||
|
||||
@@ -141,7 +141,6 @@
|
||||
<string name="automated_actions_none">Tidak ada tindakan otomatis</string>
|
||||
<string name="automated_actions_empty">Belum ada tindakan otomatis</string>
|
||||
<plurals name="automated_actions_count">
|
||||
<item quantity="one">%d tindakan otomatis</item>
|
||||
<item quantity="other">%d tindakan otomatis</item>
|
||||
</plurals>
|
||||
<string name="automated_action_add">Tambah tindakan</string>
|
||||
|
||||
@@ -141,7 +141,6 @@
|
||||
<string name="automated_actions_none">自動アクションはありません</string>
|
||||
<string name="automated_actions_empty">まだ自動アクションがありません</string>
|
||||
<plurals name="automated_actions_count">
|
||||
<item quantity="one">%d 件の自動アクション</item>
|
||||
<item quantity="other">%d 件の自動アクション</item>
|
||||
</plurals>
|
||||
<string name="automated_action_add">アクションを追加</string>
|
||||
|
||||
@@ -141,7 +141,6 @@
|
||||
<string name="automated_actions_none">자동 작업 없음</string>
|
||||
<string name="automated_actions_empty">아직 자동 작업 없음</string>
|
||||
<plurals name="automated_actions_count">
|
||||
<item quantity="one">%d개의 자동 작업</item>
|
||||
<item quantity="other">%d개의 자동 작업</item>
|
||||
</plurals>
|
||||
<string name="automated_action_add">작업 추가</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="binary_data">(dados em binário)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%2$d caractere, %1$s</item>
|
||||
<item quantity="many">%2$d de characters, %1$s</item>
|
||||
<item quantity="other">%2$d caracteres, %1$s</item>
|
||||
</plurals>
|
||||
<string name="error_correction_level">Nível de correção de erro</string>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<resources>
|
||||
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@android:color/transparent</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="android:windowBackground">@drawable/background_window</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
<item name="actionModeBackground">@color/accent</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,12 +0,0 @@
|
||||
<resources>
|
||||
<style name="Button" parent="@android:style/Widget.Button">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:background">@drawable/button_raised</item>
|
||||
<item name="android:textColor">@color/button_text</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:paddingLeft">@dimen/button_padding</item>
|
||||
<item name="android:paddingRight">@dimen/button_padding</item>
|
||||
<item name="android:maxLines">1</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -141,7 +141,6 @@
|
||||
<string name="automated_actions_none">Không có hành động tự động</string>
|
||||
<string name="automated_actions_empty">Chưa có hành động tự động</string>
|
||||
<plurals name="automated_actions_count">
|
||||
<item quantity="one">%d hành động tự động</item>
|
||||
<item quantity="other">%d hành động tự động</item>
|
||||
</plurals>
|
||||
<string name="automated_action_add">Thêm hành động</string>
|
||||
|
||||
@@ -141,7 +141,6 @@
|
||||
<string name="automated_actions_none">没有自动操作</string>
|
||||
<string name="automated_actions_empty">尚无自动操作</string>
|
||||
<plurals name="automated_actions_count">
|
||||
<item quantity="one">%d 个自动操作</item>
|
||||
<item quantity="other">%d 个自动操作</item>
|
||||
</plurals>
|
||||
<string name="automated_action_add">添加操作</string>
|
||||
|
||||
@@ -141,7 +141,6 @@
|
||||
<string name="automated_actions_none">沒有自動操作</string>
|
||||
<string name="automated_actions_empty">尚無自動操作</string>
|
||||
<plurals name="automated_actions_count">
|
||||
<item quantity="one">%d 個自動操作</item>
|
||||
<item quantity="other">%d 個自動操作</item>
|
||||
</plurals>
|
||||
<string name="automated_action_add">新增操作</string>
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
<resources>
|
||||
<string-array name="barcode_formats_names">
|
||||
<item>AZTEC</item>
|
||||
<item>CODABAR</item>
|
||||
<item>Aztec</item>
|
||||
<item>Codabar</item>
|
||||
<item>CODE 39</item>
|
||||
<item>CODE 39 EXT</item>
|
||||
<item>CODE 32</item>
|
||||
<item>PZN</item>
|
||||
<item>CODE 93</item>
|
||||
<item>CODE 128</item>
|
||||
<item>DATA BAR</item>
|
||||
<item>DATA BAR OMNI</item>
|
||||
<item>DATA BAR STK</item>
|
||||
<item>DATA BAR LTD</item>
|
||||
<item>DATA BAR EXPANDED</item>
|
||||
<item>DATA BAR EXP STK</item>
|
||||
<item>DATA MATRIX</item>
|
||||
<item>DX FILM EDGE</item>
|
||||
<item>EAN 8</item>
|
||||
<item>EAN 13</item>
|
||||
<item>ITF</item>
|
||||
<item>MAXICODE</item>
|
||||
<item>MaxiCode</item>
|
||||
<item>PDF 417</item>
|
||||
<item>QR CODE</item>
|
||||
<item>MICRO QR CODE</item>
|
||||
@@ -21,24 +27,30 @@
|
||||
<item>UPC E</item>
|
||||
</string-array>
|
||||
<string-array name="barcode_formats_values">
|
||||
<item>AZTEC</item>
|
||||
<item>CODABAR</item>
|
||||
<item>CODE_39</item>
|
||||
<item>CODE_93</item>
|
||||
<item>CODE_128</item>
|
||||
<item>DATA_BAR</item>
|
||||
<item>DATA_BAR_EXPANDED</item>
|
||||
<item>DATA_MATRIX</item>
|
||||
<item>DX_FILM_EDGE</item>
|
||||
<item>EAN_8</item>
|
||||
<item>EAN_13</item>
|
||||
<item>Aztec</item>
|
||||
<item>Codabar</item>
|
||||
<item>Code39</item>
|
||||
<item>Code39Ext</item>
|
||||
<item>Code32</item>
|
||||
<item>PZN</item>
|
||||
<item>Code93</item>
|
||||
<item>Code128</item>
|
||||
<item>DataBarOmni</item>
|
||||
<item>DataBarStk</item>
|
||||
<item>DataBarLtd</item>
|
||||
<item>DataBarExp</item>
|
||||
<item>DataBarExpStk</item>
|
||||
<item>DataMatrix</item>
|
||||
<item>DXFilmEdge</item>
|
||||
<item>EAN8</item>
|
||||
<item>EAN13</item>
|
||||
<item>ITF</item>
|
||||
<item>MAXICODE</item>
|
||||
<item>PDF_417</item>
|
||||
<item>QR_CODE</item>
|
||||
<item>MICRO_QR_CODE</item>
|
||||
<item>RMQR_CODE</item>
|
||||
<item>UPC_A</item>
|
||||
<item>UPC_E</item>
|
||||
<item>MaxiCode</item>
|
||||
<item>PDF417</item>
|
||||
<item>QRCode</item>
|
||||
<item>MicroQRCode</item>
|
||||
<item>RMQRCode</item>
|
||||
<item>UPCA</item>
|
||||
<item>UPCE</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<resources>
|
||||
<string-array name="mqr_error_correction_levels">
|
||||
<item>@string/error_correction_level_l</item>
|
||||
<item>@string/error_correction_level_m</item>
|
||||
<item>@string/error_correction_level_q</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -0,0 +1,6 @@
|
||||
<resources>
|
||||
<string-array name="rmqr_error_correction_levels">
|
||||
<item>@string/error_correction_level_m</item>
|
||||
<item>@string/error_correction_level_h</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -6,7 +6,7 @@
|
||||
<item name="android:windowBackground">@drawable/background_window</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
<item name="actionModeBackground">@color/accent</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
</style>
|
||||
<style name="SplashTheme" parent="@style/AppTheme">
|
||||
<item name="android:windowBackground">@drawable/background_splash</item>
|
||||
@@ -17,8 +17,7 @@
|
||||
</style>
|
||||
<style name="Button" parent="@android:style/Widget.Button">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
<item name="android:layout_gravity">center_horizontal</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:background">@drawable/button_raised</item>
|
||||
<item name="android:textColor">@color/button_text</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:title="@string/preferences"
|
||||
android:key="preferences">
|
||||
<PreferenceCategory android:title="@string/profile_category">
|
||||
<Preference
|
||||
android:key="profile"
|
||||
android:title="@string/profile"
|
||||
android:summary="@string/profile_default"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/scan_category">
|
||||
<MultiSelectListPreference
|
||||
android:key="formats"
|
||||
android:title="@string/barcode_formats"
|
||||
android:entries="@array/barcode_formats_names"
|
||||
android:entryValues="@array/barcode_formats_values"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_crop_handle"
|
||||
android:title="@string/show_crop_handle"
|
||||
android:summary="@string/show_crop_handle_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="zoom_by_swiping"
|
||||
android:title="@string/zoom_by_swiping"
|
||||
android:summary="@string/zoom_by_swiping_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="auto_rotate"
|
||||
android:title="@string/auto_rotate"
|
||||
android:summary="@string/auto_rotate_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="try_harder"
|
||||
android:title="@string/try_harder"
|
||||
android:summary="@string/try_harder_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="bulk_mode"
|
||||
android:title="@string/bulk_mode"
|
||||
android:summary="@string/bulk_mode_summary"/>
|
||||
<ListPreference
|
||||
android:key="bulk_mode_delay"
|
||||
android:title="@string/bulk_mode_delay"
|
||||
android:entries="@array/bulk_mode_delays_names"
|
||||
android:entryValues="@array/bulk_mode_delays_values"
|
||||
android:defaultValue="500"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_toast_in_bulk_mode"
|
||||
android:title="@string/show_toast_in_bulk_mode"
|
||||
android:summary="@string/show_toast_in_bulk_mode_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="vibrate"
|
||||
android:title="@string/vibrate"
|
||||
android:summary="@string/vibrate_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="beep"
|
||||
android:title="@string/beep"
|
||||
android:summary="@string/beep_summary"/>
|
||||
<ListPreference
|
||||
android:key="beep_tone_name"
|
||||
android:title="@string/beep_tone"
|
||||
android:entries="@array/beep_tones_names"
|
||||
android:entryValues="@array/beep_tones_values"
|
||||
android:defaultValue="tone_prop_beep"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="use_history"
|
||||
android:title="@string/use_history"
|
||||
android:summary="@string/use_history_summary"/>
|
||||
<ListPreference
|
||||
android:key="ignore_duplicates_name"
|
||||
android:title="@string/ignore_duplicates"
|
||||
android:entries="@array/ignore_duplicates_names"
|
||||
android:entryValues="@array/ignore_duplicates_values"
|
||||
android:defaultValue="ignore_consecutive_duplicates"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="copy_immediately"
|
||||
android:title="@string/copy_immediately"
|
||||
android:summary="@string/copy_immediately_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/send_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="send_scan_active"
|
||||
android:title="@string/send_scan_active"
|
||||
android:summary="@string/send_scan_active_summary"/>
|
||||
<de.markusfisch.android.binaryeye.preference.UrlPreference
|
||||
android:key="send_scan_url"
|
||||
android:title="@string/send_scan_url"/>
|
||||
<ListPreference
|
||||
android:key="send_scan_type"
|
||||
android:title="@string/send_scan_type"
|
||||
android:entries="@array/send_type_names"
|
||||
android:entryValues="@array/send_type_values"
|
||||
android:defaultValue="0"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="send_scan_bluetooth"
|
||||
android:title="@string/send_scan_bluetooth"
|
||||
android:summary="@string/send_scan_bluetooth_summary"/>
|
||||
<ListPreference
|
||||
android:key="send_scan_bluetooth_host"
|
||||
android:title="@string/send_scan_bluetooth_host"
|
||||
android:entries="@array/bluetooth_host_names"
|
||||
android:entryValues="@array/bluetooth_host_values"
|
||||
android:defaultValue="@string/no_bluetooth_hosts_paired_value"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/content_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="open_immediately"
|
||||
android:title="@string/open_immediately"
|
||||
android:summary="@string/open_immediately_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_meta_data"
|
||||
android:title="@string/show_meta_data"
|
||||
android:summary="@string/show_meta_data_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_hex_dump"
|
||||
android:title="@string/show_hex_dump"
|
||||
android:summary="@string/show_hex_dump_summary"/>
|
||||
<ListPreference
|
||||
android:key="show_checksum"
|
||||
android:title="@string/show_checksum"
|
||||
android:entries="@array/checksum_names"
|
||||
android:entryValues="@array/checksum_values"
|
||||
android:defaultValue="@string/no_checksum"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_recreation"
|
||||
android:title="@string/show_recreation"
|
||||
android:summary="@string/show_recreation_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="close_automatically"
|
||||
android:title="@string/close_automatically"
|
||||
android:summary="@string/close_automatically_summary"/>
|
||||
<ListPreference
|
||||
android:key="default_search_url"
|
||||
android:title="@string/default_search_engine"
|
||||
android:entries="@array/search_engines_names"
|
||||
android:entryValues="@array/search_engines_values"
|
||||
android:defaultValue=""/>
|
||||
<de.markusfisch.android.binaryeye.preference.UrlPreference
|
||||
android:key="open_with_url"
|
||||
android:title="@string/open_with_url"/>
|
||||
<Preference
|
||||
android:key="automated_actions"
|
||||
android:title="@string/automated_actions"
|
||||
android:summary="@string/automated_actions_none"/>
|
||||
<Preference
|
||||
android:key="clear_network_suggestions"
|
||||
android:title="@string/clear_network_suggestions"
|
||||
android:summary="@string/clear_network_suggestions_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/generation_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="brighten_screen"
|
||||
android:title="@string/brighten_screen"
|
||||
android:summary="@string/brighten_screen_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/locale_category">
|
||||
<ListPreference
|
||||
android:key="custom_locale"
|
||||
android:title="@string/custom_locale"
|
||||
android:entries="@array/locale_names"
|
||||
android:entryValues="@array/locale_values"
|
||||
android:defaultValue="0"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -14,27 +14,27 @@
|
||||
android:title="@string/barcode_formats"
|
||||
android:entries="@array/barcode_formats_names"
|
||||
android:entryValues="@array/barcode_formats_values"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_crop_handle"
|
||||
android:title="@string/show_crop_handle"
|
||||
android:summary="@string/show_crop_handle_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="zoom_by_swiping"
|
||||
android:title="@string/zoom_by_swiping"
|
||||
android:summary="@string/zoom_by_swiping_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="auto_rotate"
|
||||
android:title="@string/auto_rotate"
|
||||
android:summary="@string/auto_rotate_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="try_harder"
|
||||
android:title="@string/try_harder"
|
||||
android:summary="@string/try_harder_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="bulk_mode"
|
||||
android:title="@string/bulk_mode"
|
||||
@@ -45,17 +45,17 @@
|
||||
android:entries="@array/bulk_mode_delays_names"
|
||||
android:entryValues="@array/bulk_mode_delays_values"
|
||||
android:defaultValue="500"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_toast_in_bulk_mode"
|
||||
android:title="@string/show_toast_in_bulk_mode"
|
||||
android:summary="@string/show_toast_in_bulk_mode_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="vibrate"
|
||||
android:title="@string/vibrate"
|
||||
android:summary="@string/vibrate_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="beep"
|
||||
android:title="@string/beep"
|
||||
@@ -66,7 +66,7 @@
|
||||
android:entries="@array/beep_tones_names"
|
||||
android:entryValues="@array/beep_tones_values"
|
||||
android:defaultValue="tone_prop_beep"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="use_history"
|
||||
android:title="@string/use_history"
|
||||
@@ -77,14 +77,14 @@
|
||||
android:entries="@array/ignore_duplicates_names"
|
||||
android:entryValues="@array/ignore_duplicates_values"
|
||||
android:defaultValue="ignore_consecutive_duplicates"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="copy_immediately"
|
||||
android:title="@string/copy_immediately"
|
||||
android:summary="@string/copy_immediately_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/send_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="send_scan_active"
|
||||
android:title="@string/send_scan_active"
|
||||
@@ -98,7 +98,7 @@
|
||||
android:entries="@array/send_type_names"
|
||||
android:entryValues="@array/send_type_values"
|
||||
android:defaultValue="0"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="send_scan_bluetooth"
|
||||
android:title="@string/send_scan_bluetooth"
|
||||
@@ -111,17 +111,17 @@
|
||||
android:defaultValue="@string/no_bluetooth_hosts_paired_value"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/content_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="open_immediately"
|
||||
android:title="@string/open_immediately"
|
||||
android:summary="@string/open_immediately_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_meta_data"
|
||||
android:title="@string/show_meta_data"
|
||||
android:summary="@string/show_meta_data_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_hex_dump"
|
||||
android:title="@string/show_hex_dump"
|
||||
@@ -132,12 +132,12 @@
|
||||
android:entries="@array/checksum_names"
|
||||
android:entryValues="@array/checksum_values"
|
||||
android:defaultValue="@string/no_checksum"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_recreation"
|
||||
android:title="@string/show_recreation"
|
||||
android:summary="@string/show_recreation_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="close_automatically"
|
||||
android:title="@string/close_automatically"
|
||||
@@ -161,7 +161,7 @@
|
||||
android:summary="@string/clear_network_suggestions_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/generation_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="brighten_screen"
|
||||
android:title="@string/brighten_screen"
|
||||
|
||||
@@ -9,27 +9,32 @@
|
||||
android:summary="@string/profile_default"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/scan_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<MultiSelectListPreference
|
||||
android:key="formats"
|
||||
android:title="@string/barcode_formats"
|
||||
android:entries="@array/barcode_formats_names"
|
||||
android:entryValues="@array/barcode_formats_values"/>
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_crop_handle"
|
||||
android:title="@string/show_crop_handle"
|
||||
android:summary="@string/show_crop_handle_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="zoom_by_swiping"
|
||||
android:title="@string/zoom_by_swiping"
|
||||
android:summary="@string/zoom_by_swiping_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="auto_rotate"
|
||||
android:title="@string/auto_rotate"
|
||||
android:summary="@string/auto_rotate_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="try_harder"
|
||||
android:title="@string/try_harder"
|
||||
android:summary="@string/try_harder_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="bulk_mode"
|
||||
android:title="@string/bulk_mode"
|
||||
@@ -40,17 +45,17 @@
|
||||
android:entries="@array/bulk_mode_delays_names"
|
||||
android:entryValues="@array/bulk_mode_delays_values"
|
||||
android:defaultValue="500"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_toast_in_bulk_mode"
|
||||
android:title="@string/show_toast_in_bulk_mode"
|
||||
android:summary="@string/show_toast_in_bulk_mode_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="vibrate"
|
||||
android:title="@string/vibrate"
|
||||
android:summary="@string/vibrate_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="beep"
|
||||
android:title="@string/beep"
|
||||
@@ -61,7 +66,7 @@
|
||||
android:entries="@array/beep_tones_names"
|
||||
android:entryValues="@array/beep_tones_values"
|
||||
android:defaultValue="tone_prop_beep"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="use_history"
|
||||
android:title="@string/use_history"
|
||||
@@ -72,14 +77,14 @@
|
||||
android:entries="@array/ignore_duplicates_names"
|
||||
android:entryValues="@array/ignore_duplicates_values"
|
||||
android:defaultValue="ignore_consecutive_duplicates"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="copy_immediately"
|
||||
android:title="@string/copy_immediately"
|
||||
android:summary="@string/copy_immediately_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/send_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="send_scan_active"
|
||||
android:title="@string/send_scan_active"
|
||||
@@ -93,7 +98,7 @@
|
||||
android:entries="@array/send_type_names"
|
||||
android:entryValues="@array/send_type_values"
|
||||
android:defaultValue="0"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="send_scan_bluetooth"
|
||||
android:title="@string/send_scan_bluetooth"
|
||||
@@ -106,17 +111,17 @@
|
||||
android:defaultValue="@string/no_bluetooth_hosts_paired_value"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/content_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="open_immediately"
|
||||
android:title="@string/open_immediately"
|
||||
android:summary="@string/open_immediately_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_meta_data"
|
||||
android:title="@string/show_meta_data"
|
||||
android:summary="@string/show_meta_data_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_hex_dump"
|
||||
android:title="@string/show_hex_dump"
|
||||
@@ -127,12 +132,12 @@
|
||||
android:entries="@array/checksum_names"
|
||||
android:entryValues="@array/checksum_values"
|
||||
android:defaultValue="@string/no_checksum"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="show_recreation"
|
||||
android:title="@string/show_recreation"
|
||||
android:summary="@string/show_recreation_summary"/>
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="close_automatically"
|
||||
android:title="@string/close_automatically"
|
||||
@@ -156,7 +161,7 @@
|
||||
android:summary="@string/clear_network_suggestions_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/generation_category">
|
||||
<android.support.v7.preference.SwitchPreferenceCompat
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="brighten_screen"
|
||||
android:title="@string/brighten_screen"
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:targetPackage="de.markusfisch.android.binaryeye"
|
||||
android:targetClass="de.markusfisch.android.binaryeye.activity.MainActivity">
|
||||
<extra android:name="encode" android:value="encode"/>
|
||||
</intent>
|
||||
android:targetClass="de.markusfisch.android.binaryeye.activity.EncodeActivity"/>
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:shortcutId="history"
|
||||
@@ -35,9 +33,7 @@
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:targetPackage="de.markusfisch.android.binaryeye"
|
||||
android:targetClass="de.markusfisch.android.binaryeye.activity.MainActivity">
|
||||
<extra android:name="history" android:value="history"/>
|
||||
</intent>
|
||||
android:targetClass="de.markusfisch.android.binaryeye.activity.HistoryActivity"/>
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:shortcutId="preferences"
|
||||
@@ -48,8 +44,6 @@
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:targetPackage="de.markusfisch.android.binaryeye"
|
||||
android:targetClass="de.markusfisch.android.binaryeye.activity.MainActivity">
|
||||
<extra android:name="preferences" android:value="preferences"/>
|
||||
</intent>
|
||||
android:targetClass="de.markusfisch.android.binaryeye.activity.PreferencesActivity"/>
|
||||
</shortcut>
|
||||
</shortcuts>
|
||||
|
||||
@@ -56,20 +56,20 @@ class BinaryEyeDeeplinkTest {
|
||||
fun createEncodeDeeplinkTests() {
|
||||
// Basic test
|
||||
assertEquals(
|
||||
"https://markusfisch.de/encode?format=QR_CODE&content=test",
|
||||
createEncodeDeeplink("QR_CODE", "test")
|
||||
"https://markusfisch.de/encode?format=QRCode&content=test",
|
||||
createEncodeDeeplink("QRCode", "test")
|
||||
)
|
||||
|
||||
// Test with special characters in content
|
||||
assertEquals(
|
||||
"https://markusfisch.de/encode?format=QR_CODE&content=test%20with%20spaces",
|
||||
createEncodeDeeplink("QR_CODE", "test with spaces")
|
||||
"https://markusfisch.de/encode?format=QRCode&content=test%20with%20spaces",
|
||||
createEncodeDeeplink("QRCode", "test with spaces")
|
||||
)
|
||||
|
||||
// Test with different barcode format
|
||||
assertEquals(
|
||||
"https://markusfisch.de/encode?format=CODE_128&content=123456",
|
||||
createEncodeDeeplink("CODE_128", "123456")
|
||||
"https://markusfisch.de/encode?format=Code128&content=123456",
|
||||
createEncodeDeeplink("Code128", "123456")
|
||||
)
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -1,9 +1,8 @@
|
||||
buildscript {
|
||||
ext {
|
||||
kotlin_version = '2.2.21'
|
||||
tools_version = '9.0.1'
|
||||
kotlin_version = '2.3.20'
|
||||
tools_version = '9.1.0'
|
||||
sdk_version = 36
|
||||
support_version = '25.3.1'
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
* Fix barcode regeneration
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
* Stability improvement
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
* Fix generating 1D barcodes
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
* Downgrade ZXingCpp for compatibilty
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
* Update ZXingCpp
|
||||
* Ask for confirmation before deleting a scan from the result screen
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
* Add icons to preferences screen
|
||||
* Update history listing on resume
|
||||
* Fix quiet zone for recreated barcodes
|
||||
* Fix automatic screen brightening
|
||||
* Migrate to CameraX
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Wed Jan 26 11:58:22 CET 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
networkTimeout=10000
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
Reference in New Issue
Block a user