diff --git a/.gitignore b/.gitignore
index 2f53f69b..6a84d08d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,3 +92,6 @@ atlassian-ide-plugin.xml
# Mongo Explorer plugin
.idea/mongoSettings.xml
+
+# Sentry
+/sentry.properties
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c872974f..6c815a8d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Change Log
+## 1.6
+* Add a setting to avoid duplicates in history
+* Add an option to manually save to history
+* Add an option to set a name to a history item
+* Bug fix: app shortcuts were not working
+* Bug fix: Wi-Fi QR code passwords were scanned wrong
+
## 1.5
* Add Chinese (Taiwan) translation
* Add a Quick Settings tile for the app
diff --git a/app/build.gradle b/app/build.gradle
index be90c9c2..3f646a82 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -12,8 +12,8 @@ android {
applicationId "com.example.barcodescanner"
minSdkVersion 21
targetSdkVersion 29
- versionCode 7
- versionName "1.5"
+ versionCode 8
+ versionName "1.6"
multiDexEnabled true
vectorDrawables.useSupportLibrary true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -24,6 +24,10 @@ android {
}
}
+ Properties properties = new Properties()
+ properties.load(project.rootProject.file("local.properties").newDataInputStream())
+
+ resValue "string", "sentryDSN", properties.getProperty("sentryDSN")
buildConfigField "boolean", "ERROR_REPORTS_ENABLED_BY_DEFAULT", "true"
}
@@ -76,7 +80,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// Android
- implementation 'androidx.core:core-ktx:1.3.1'
+ implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
diff --git a/app/src/amazon/res/xml/shortcuts.xml b/app/src/amazon/res/xml/shortcuts.xml
new file mode 100644
index 00000000..161045fa
--- /dev/null
+++ b/app/src/amazon/res/xml/shortcuts.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/aptoide/res/xml/shortcuts.xml b/app/src/aptoide/res/xml/shortcuts.xml
new file mode 100644
index 00000000..70aefae2
--- /dev/null
+++ b/app/src/aptoide/res/xml/shortcuts.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/googlePlay/res/xml/shortcuts.xml b/app/src/googlePlay/res/xml/shortcuts.xml
new file mode 100644
index 00000000..70aefae2
--- /dev/null
+++ b/app/src/googlePlay/res/xml/shortcuts.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f7cd1634..2c0bd085 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,12 +23,12 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
- android:name="com.example.barcodescanner.App"
+ android:name=".App"
>
toggleIsFavorite()
R.id.item_show_barcode_image -> navigateToBarcodeImageActivity()
+ R.id.item_save -> saveBarcode()
R.id.item_delete -> showDeleteBarcodeConfirmationDialog()
}
return@setOnMenuItemClickListener true
@@ -169,6 +181,8 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
}
private fun handleButtonsClicked() {
+ button_edit_name.setOnClickListener { showEditBarcodeNameDialog() }
+
button_search_on_rate_and_goods.setOnClickListener { searchBarcodeTextOnRateAndGoods() }
button_search_on_amazon.setOnClickListener { searchBarcodeTextOnAmazon() }
button_search_on_ebay.setOnClickListener { searchBarcodeTextOnEbay() }
@@ -213,14 +227,14 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
private fun toggleIsFavorite() {
- val newBarcode = originalBarcode.copy(isFavorite = originalBarcode.isFavorite.not())
+ val newBarcode = originalBarcode.copy(isFavorite = barcode.isFavorite.not())
barcodeDatabase.save(newBarcode)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
- originalBarcode.isFavorite = newBarcode.isFavorite
+ barcode.isFavorite = newBarcode.isFavorite
showBarcodeIsFavorite(newBarcode.isFavorite)
},
{}
@@ -228,6 +242,65 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
.addTo(disposable)
}
+ private fun updateBarcodeName(name: String) {
+ if (name.isBlank()) {
+ return
+ }
+
+ val newBarcode = originalBarcode.copy(
+ id = barcode.id,
+ name = name
+ )
+
+ barcodeDatabase.save(newBarcode)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ {
+ barcode.name = name
+ showBarcodeName(name)
+ },
+ ::showError
+ )
+ .addTo(disposable)
+ }
+
+ private fun saveBarcode() {
+ toolbar?.menu?.findItem(R.id.item_save)?.isVisible = false
+
+ barcodeDatabase.save(originalBarcode, settings.doNotSaveDuplicates)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ { id ->
+ barcode.id = id
+ button_edit_name.isVisible = true
+ toolbar?.menu?.findItem(R.id.item_delete)?.isVisible = true
+ },
+ { error ->
+ toolbar?.menu?.findItem(R.id.item_save)?.isVisible = true
+ showError(error)
+ }
+ )
+ .addTo(disposable)
+ }
+
+ private fun deleteBarcode() {
+ showLoading(true)
+
+ barcodeDatabase.delete(barcode.id)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ { finish() },
+ { error ->
+ showLoading(false)
+ showError(error)
+ }
+ )
+ .addTo(disposable)
+ }
+
private fun addToCalendar() {
val intent = Intent(Intent.ACTION_INSERT).apply {
data = CalendarContract.Events.CONTENT_URI
@@ -479,22 +552,6 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
SaveBarcodeAsImageActivity.start(this, originalBarcode)
}
- private fun deleteBarcode() {
- showLoading(true)
-
- barcodeDatabase.delete(barcode.id)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { finish() },
- { error ->
- showLoading(false)
- showError(error)
- }
- )
- .addTo(disposable)
- }
-
private fun showBarcode() {
showBarcodeMenuIfNeeded()
@@ -502,6 +559,7 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
showBarcodeImageIfNeeded()
showBarcodeDate()
showBarcodeFormat()
+ showBarcodeName()
showBarcodeText()
showBarcodeCountry()
}
@@ -512,6 +570,7 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
findItem(R.id.item_increase_brightness).isVisible = isCreated
findItem(R.id.item_add_to_favorites)?.isVisible = barcode.isInDb
findItem(R.id.item_show_barcode_image)?.isVisible = isCreated.not()
+ findItem(R.id.item_save)?.isVisible = barcode.isInDb.not()
findItem(R.id.item_delete)?.isVisible = barcode.isInDb
}
}
@@ -562,6 +621,15 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
toolbar.setTitle(format)
}
+ private fun showBarcodeName() {
+ showBarcodeName(barcode.name)
+ }
+
+ private fun showBarcodeName(name: String?) {
+ text_view_barcode_name.isVisible = name.isNullOrBlank().not()
+ text_view_barcode_name.text = name.orEmpty()
+ }
+
private fun showBarcodeText() {
text_view_barcode_text.text = if (isCreated) {
barcode.text
@@ -606,6 +674,7 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
private fun showOrHideButtons() {
button_search.isVisible = isCreated.not()
+ button_edit_name.isVisible = barcode.isInDb
if (isCreated) {
return
@@ -670,6 +739,11 @@ class BarcodeActivity : BaseActivity(), DeleteConfirmationDialogFragment.Listene
dialog.show(supportFragmentManager, "")
}
+ private fun showEditBarcodeNameDialog() {
+ val dialog = EditBarcodeNameDialogFragment.newInstance(barcode.name)
+ dialog.show(supportFragmentManager, "")
+ }
+
private fun showSearchEnginesDialog() {
val dialog = ChooseSearchEngineDialogFragment()
dialog.show(supportFragmentManager, "")
diff --git a/app/src/main/java/com/example/barcodescanner/feature/barcode/otp/OtpActivity.kt b/app/src/main/java/com/example/barcodescanner/feature/barcode/otp/OtpActivity.kt
index 88a429fb..536dd507 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/barcode/otp/OtpActivity.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/barcode/otp/OtpActivity.kt
@@ -12,6 +12,7 @@ import com.example.barcodescanner.extension.orZero
import com.example.barcodescanner.feature.BaseActivity
import com.example.barcodescanner.model.schema.OtpAuth
import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import kotlinx.android.synthetic.main.activity_barcode_otp.*
@@ -106,13 +107,13 @@ class OtpActivity : BaseActivity() {
val secondsPassed = currentTimeInSeconds % period
val secondsLeft = period - secondsPassed
-
Observable
.interval(1, TimeUnit.SECONDS)
.map { it + 1 }
.take(secondsLeft)
.map { secondsLeft - it }
.startWith(secondsLeft)
+ .observeOn(AndroidSchedulers.mainThread())
.doOnComplete { showOtp() }
.subscribe(::showTime)
.addTo(disposable)
diff --git a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ChooseSearchEngineDialogFragment.kt b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ChooseSearchEngineDialogFragment.kt
index d8ee82da..27a21a79 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ChooseSearchEngineDialogFragment.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ChooseSearchEngineDialogFragment.kt
@@ -3,6 +3,7 @@ package com.example.barcodescanner.feature.common.dialog
import android.app.Dialog
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
+import androidx.core.content.ContextCompat
import androidx.fragment.app.DialogFragment
import com.example.barcodescanner.R
import com.example.barcodescanner.model.SearchEngine
@@ -45,7 +46,7 @@ class ChooseSearchEngineDialogFragment : DialogFragment() {
.create()
dialog.setOnShowListener {
- dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(resources.getColor(R.color.red))
+ dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.red))
}
return dialog
diff --git a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ConfirmBarcodeDialogFragment.kt b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ConfirmBarcodeDialogFragment.kt
index e8a3a6e1..6c121a4a 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ConfirmBarcodeDialogFragment.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ConfirmBarcodeDialogFragment.kt
@@ -3,6 +3,7 @@ package com.example.barcodescanner.feature.common.dialog
import android.app.Dialog
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
+import androidx.core.content.ContextCompat
import androidx.fragment.app.DialogFragment
import com.example.barcodescanner.R
import com.example.barcodescanner.extension.toStringId
@@ -34,20 +35,20 @@ class ConfirmBarcodeDialogFragment : DialogFragment() {
val messageId = barcode.format.toStringId()
val dialog = AlertDialog.Builder(requireActivity(), R.style.DialogTheme)
- .setTitle(R.string.fragment_scan_barcode_from_camera_confirm_barcode_dialog_title)
+ .setTitle(R.string.dialog_confirm_barcode_title)
.setMessage(messageId)
.setCancelable(false)
- .setPositiveButton(R.string.fragment_scan_barcode_from_camera_confirm_barcode_dialog_positive_button) { _, _ ->
+ .setPositiveButton(R.string.dialog_confirm_barcode_positive_button) { _, _ ->
listener?.onBarcodeConfirmed(barcode)
}
- .setNegativeButton(R.string.fragment_scan_barcode_from_camera_confirm_barcode_dialog_negative_button) { _, _ ->
+ .setNegativeButton(R.string.dialog_confirm_barcode_negative_button) { _, _ ->
listener?.onBarcodeDeclined()
}
.create()
dialog.setOnShowListener {
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(resources.getColor(R.color.blue))
- dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(resources.getColor(R.color.red))
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.blue))
+ dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.red))
}
return dialog
diff --git a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/DeleteConfirmationDialogFragment.kt b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/DeleteConfirmationDialogFragment.kt
index 4352a048..35de86c6 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/DeleteConfirmationDialogFragment.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/DeleteConfirmationDialogFragment.kt
@@ -3,6 +3,7 @@ package com.example.barcodescanner.feature.common.dialog
import android.app.Dialog
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
+import androidx.core.content.ContextCompat
import androidx.fragment.app.DialogFragment
import com.example.barcodescanner.R
import com.example.barcodescanner.extension.orZero
@@ -37,8 +38,8 @@ class DeleteConfirmationDialogFragment : DialogFragment() {
.create()
dialog.setOnShowListener {
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(resources.getColor(R.color.red))
- dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(resources.getColor(R.color.blue))
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.red))
+ dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.blue))
}
return dialog
diff --git a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/EditBarcodeNameDialogFragment.kt b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/EditBarcodeNameDialogFragment.kt
new file mode 100644
index 00000000..68eff130
--- /dev/null
+++ b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/EditBarcodeNameDialogFragment.kt
@@ -0,0 +1,70 @@
+package com.example.barcodescanner.feature.common.dialog
+
+import android.app.Activity
+import android.app.Dialog
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.inputmethod.InputMethodManager
+import android.widget.EditText
+import androidx.appcompat.app.AlertDialog
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.DialogFragment
+import com.example.barcodescanner.R
+import kotlinx.android.synthetic.main.dialog_edit_barcode_name.view.*
+
+class EditBarcodeNameDialogFragment : DialogFragment() {
+
+ interface Listener {
+ fun onNameConfirmed(name: String)
+ }
+
+ companion object {
+ private const val NAME_KEY = "NAME_KEY"
+
+ fun newInstance(name: String?): EditBarcodeNameDialogFragment {
+ return EditBarcodeNameDialogFragment().apply {
+ arguments = Bundle().apply {
+ putString(NAME_KEY, name)
+ }
+ }
+ }
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val listener = requireActivity() as? Listener
+ val name = arguments?.getString(NAME_KEY).orEmpty()
+
+ val view = LayoutInflater
+ .from(requireContext())
+ .inflate(R.layout.dialog_edit_barcode_name, null, false)
+
+ val dialog = AlertDialog.Builder(requireActivity(), R.style.DialogTheme)
+ .setTitle(R.string.dialog_edit_barcode_name_title)
+ .setView(view)
+ .setPositiveButton(R.string.dialog_confirm_barcode_positive_button) { _, _ ->
+ val newName = view.edit_text_barcode_name.text.toString()
+ listener?.onNameConfirmed(newName)
+ }
+ .setNegativeButton(R.string.dialog_confirm_barcode_negative_button, null)
+ .create()
+
+ dialog.setOnShowListener {
+ initNameEditText(view.edit_text_barcode_name, name)
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.blue))
+ dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.red))
+ }
+
+ return dialog
+ }
+
+ private fun initNameEditText(editText: EditText, name: String) {
+ editText.apply {
+ setText(name)
+ setSelection(name.length)
+ requestFocus()
+ }
+
+ val manager = requireContext().getSystemService(Activity.INPUT_METHOD_SERVICE) as? InputMethodManager
+ manager?.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ErrorDialogFragment.kt b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ErrorDialogFragment.kt
index 68c40438..e58e596a 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ErrorDialogFragment.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/common/dialog/ErrorDialogFragment.kt
@@ -4,6 +4,7 @@ import android.app.Dialog
import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
+import androidx.core.content.ContextCompat
import androidx.fragment.app.DialogFragment
import com.example.barcodescanner.R
@@ -48,7 +49,7 @@ class ErrorDialogFragment : DialogFragment() {
.create()
dialog.setOnShowListener {
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(resources.getColor(R.color.blue))
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(requireContext(), R.color.blue))
}
return dialog
diff --git a/app/src/main/java/com/example/barcodescanner/feature/common/view/IconButton.kt b/app/src/main/java/com/example/barcodescanner/feature/common/view/IconButton.kt
index 9ad325ea..835e1e4a 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/common/view/IconButton.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/common/view/IconButton.kt
@@ -8,6 +8,7 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import androidx.appcompat.content.res.AppCompatResources
+import androidx.core.content.ContextCompat
import com.example.barcodescanner.R
import kotlinx.android.synthetic.main.layout_icon_button.view.*
@@ -41,7 +42,10 @@ class IconButton : FrameLayout {
}
private fun showIconBackgroundColor(attributes: TypedArray) {
- val color = attributes.getColor(R.styleable.IconButton_iconBackground, view.context.resources.getColor(R.color.green))
+ val color = attributes.getColor(
+ R.styleable.IconButton_iconBackground,
+ ContextCompat.getColor(view.context, R.color.green)
+ )
(view.layout_image.background.mutate() as GradientDrawable).setColor(color)
}
diff --git a/app/src/main/java/com/example/barcodescanner/feature/common/view/ResultPointsView.kt b/app/src/main/java/com/example/barcodescanner/feature/common/view/ResultPointsView.kt
new file mode 100644
index 00000000..7877d7f2
--- /dev/null
+++ b/app/src/main/java/com/example/barcodescanner/feature/common/view/ResultPointsView.kt
@@ -0,0 +1,88 @@
+package com.example.barcodescanner.feature.common.view
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.*
+import android.util.AttributeSet
+import android.util.TypedValue
+import android.view.View
+import androidx.core.content.ContextCompat
+import com.example.barcodescanner.R
+import com.google.zxing.Result
+
+class ResultPointsView : View {
+
+ private val pointsPaint = Paint().apply {
+ style = Paint.Style.STROKE
+ color = Color.BLUE
+ strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, Resources.getSystem().displayMetrics)
+ strokeCap = Paint.Cap.ROUND
+ }
+
+ private var resultPoints = floatArrayOf()
+ private var rect = RectF()
+
+
+ constructor(context: Context?) : this(context, null)
+ constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
+ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : this(context, attrs, defStyleAttr, 0)
+
+ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
+ context?.obtainStyledAttributes(attrs, R.styleable.ResultPointsView)?.apply {
+ pointsPaint.color = getColor(
+ R.styleable.ResultPointsView_resultPointColor,
+ ContextCompat.getColor(context, R.color.blue)
+ )
+
+ pointsPaint.strokeWidth = getDimension(
+ R.styleable.ResultPointsView_resultPointSize,
+ pointsPaint.strokeWidth
+ )
+
+ recycle()
+ }
+ }
+
+
+ override fun onDraw(canvas: Canvas) {
+ canvas.drawPoints(resultPoints, pointsPaint)
+
+// if (BuildConfig.DEBUG) {
+// canvas.drawRect(rect, pointsPaint)
+// }
+ }
+
+ fun showResult(result: Result, imageWidth: Int, imageHeight: Int, imageRotation: Int) {
+ val localMatrix = createMatrix(imageWidth.toFloat(), imageHeight.toFloat(), imageRotation)
+
+ resultPoints = result.resultPoints.flatMap { listOf(it.x, it.y) }.toFloatArray()
+ localMatrix.mapPoints(resultPoints)
+
+// if (BuildConfig.DEBUG) {
+// rect = RectF(0f, 0f, imageWidth.toFloat(), imageHeight.toFloat())
+// localMatrix.mapRect(rect)
+// }
+
+ postInvalidate()
+ }
+
+ private fun createMatrix(imageWidth: Float, imageHeight: Float, imageRotation: Int) = Matrix().apply {
+ preTranslate((width - imageWidth) / 2f, (height - imageHeight) / 2f)
+ preRotate(imageRotation.toFloat(), imageWidth / 2f, imageHeight / 2f)
+
+ val wScale: Float
+ val hScale: Float
+
+ if (imageRotation % 180 == 0) {
+ wScale = width.toFloat() / imageWidth
+ hScale = height.toFloat() / imageHeight
+ } else {
+ wScale = height.toFloat() / imageWidth
+ hScale = width.toFloat() / imageHeight
+
+ }
+
+ val scale = Math.max(wScale, hScale)
+ preScale(scale, scale, imageWidth / 2f, imageHeight / 2f)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/barcodescanner/feature/tabs/BottomTabsActivity.kt b/app/src/main/java/com/example/barcodescanner/feature/tabs/BottomTabsActivity.kt
index 37188bca..85d3185e 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/tabs/BottomTabsActivity.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/tabs/BottomTabsActivity.kt
@@ -3,6 +3,7 @@ package com.example.barcodescanner.feature.tabs
import android.os.Bundle
import android.view.MenuItem
import androidx.fragment.app.Fragment
+import com.example.barcodescanner.BuildConfig
import com.example.barcodescanner.R
import com.example.barcodescanner.extension.applySystemWindowInsets
import com.example.barcodescanner.feature.BaseActivity
@@ -16,8 +17,8 @@ import kotlinx.android.synthetic.main.activity_bottom_tabs.*
class BottomTabsActivity : BaseActivity(), BottomNavigationView.OnNavigationItemSelectedListener {
companion object {
- private const val ACTION_CREATE_BARCODE = "com.example.barcodescanner.CREATE_BARCODE"
- private const val ACTION_HISTORY = "com.example.barcodescanner.HISTORY"
+ private const val ACTION_CREATE_BARCODE = "${BuildConfig.APPLICATION_ID}.CREATE_BARCODE"
+ private const val ACTION_HISTORY = "${BuildConfig.APPLICATION_ID}.HISTORY"
}
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/app/src/main/java/com/example/barcodescanner/feature/tabs/create/CreateBarcodeActivity.kt b/app/src/main/java/com/example/barcodescanner/feature/tabs/create/CreateBarcodeActivity.kt
index ff42f27a..27733208 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/tabs/create/CreateBarcodeActivity.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/tabs/create/CreateBarcodeActivity.kt
@@ -8,6 +8,7 @@ import android.net.Uri
import android.os.Bundle
import android.provider.ContactsContract
import android.widget.Toast
+import androidx.core.content.ContextCompat
import com.example.barcodescanner.R
import com.example.barcodescanner.di.*
import com.example.barcodescanner.extension.applySystemWindowInsets
@@ -23,6 +24,7 @@ import com.example.barcodescanner.model.schema.App
import com.example.barcodescanner.model.schema.BarcodeSchema
import com.example.barcodescanner.model.schema.Schema
import com.example.barcodescanner.usecase.Logger
+import com.example.barcodescanner.usecase.save
import com.google.zxing.BarcodeFormat
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
@@ -79,7 +81,7 @@ class CreateBarcodeActivity : BaseActivity(), AppAdapter.Listener {
}
toolbar.menu?.findItem(R.id.item_create_barcode)?.apply {
- icon = getDrawable(iconId)
+ icon = ContextCompat.getDrawable(this@CreateBarcodeActivity, iconId)
isEnabled = enabled
}
}
@@ -313,7 +315,7 @@ class CreateBarcodeActivity : BaseActivity(), AppAdapter.Listener {
return
}
- barcodeDatabase.save(barcode)
+ barcodeDatabase.save(barcode, settings.doNotSaveDuplicates)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
diff --git a/app/src/main/java/com/example/barcodescanner/feature/tabs/history/BarcodeHistoryAdapter.kt b/app/src/main/java/com/example/barcodescanner/feature/tabs/history/BarcodeHistoryAdapter.kt
index d327ee2d..c8bbd129 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/tabs/history/BarcodeHistoryAdapter.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/tabs/history/BarcodeHistoryAdapter.kt
@@ -61,7 +61,7 @@ class BarcodeHistoryAdapter(private val listener: Listener) : PagedListAdapter(0, 350).toLongArray()
private val disposable = CompositeDisposable()
private var maxZoom: Int = 0
@@ -268,7 +269,7 @@ class ScanBarcodeFromCameraFragment : Fragment(), ConfirmBarcodeDialogFragment.L
}
private fun saveScannedBarcode(barcode: Barcode) {
- barcodeDatabase.save(barcode)
+ barcodeDatabase.save(barcode, settings.doNotSaveDuplicates)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
@@ -316,11 +317,11 @@ class ScanBarcodeFromCameraFragment : Fragment(), ConfirmBarcodeDialogFragment.L
}
private fun requestPermissions() {
- permissionsHelper.requestNotGrantedPermissions(requireActivity() as AppCompatActivity, permissions, PERMISSION_REQUEST_CODE)
+ permissionsHelper.requestNotGrantedPermissions(requireActivity() as AppCompatActivity, PERMISSIONS, PERMISSION_REQUEST_CODE)
}
private fun areAllPermissionsGranted(): Boolean {
- return permissionsHelper.areAllPermissionsGranted(requireActivity(), permissions)
+ return permissionsHelper.areAllPermissionsGranted(requireActivity(), PERMISSIONS)
}
private fun areAllPermissionsGranted(grantResults: IntArray): Boolean {
diff --git a/app/src/main/java/com/example/barcodescanner/feature/tabs/scan/file/ScanBarcodeFromFileActivity.kt b/app/src/main/java/com/example/barcodescanner/feature/tabs/scan/file/ScanBarcodeFromFileActivity.kt
index edaa52dd..7bd3f0f0 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/tabs/scan/file/ScanBarcodeFromFileActivity.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/tabs/scan/file/ScanBarcodeFromFileActivity.kt
@@ -18,6 +18,7 @@ import com.example.barcodescanner.extension.showError
import com.example.barcodescanner.feature.BaseActivity
import com.example.barcodescanner.feature.barcode.BarcodeActivity
import com.example.barcodescanner.model.Barcode
+import com.example.barcodescanner.usecase.save
import com.google.zxing.Result
import com.isseiaoki.simplecropview.CropImageView
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -225,7 +226,7 @@ class ScanBarcodeFromFileActivity : BaseActivity() {
showLoading(true)
- barcodeDatabase.save(barcode)
+ barcodeDatabase.save(barcode, settings.doNotSaveDuplicates)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
diff --git a/app/src/main/java/com/example/barcodescanner/feature/tabs/settings/SettingsFragment.kt b/app/src/main/java/com/example/barcodescanner/feature/tabs/settings/SettingsFragment.kt
index 30ccd98f..13a19039 100644
--- a/app/src/main/java/com/example/barcodescanner/feature/tabs/settings/SettingsFragment.kt
+++ b/app/src/main/java/com/example/barcodescanner/feature/tabs/settings/SettingsFragment.kt
@@ -71,6 +71,7 @@ class SettingsFragment : Fragment(), DeleteConfirmationDialogFragment.Listener {
button_confirm_scans_manually.setCheckedChangedListener { settings.confirmScansManually = it }
button_save_scanned_barcodes.setCheckedChangedListener { settings.saveScannedBarcodesToHistory = it }
button_save_created_barcodes.setCheckedChangedListener { settings.saveCreatedBarcodesToHistory = it }
+ button_do_not_save_duplicates.setCheckedChangedListener { settings.doNotSaveDuplicates = it }
button_enable_error_reports.setCheckedChangedListener { settings.areErrorReportsEnabled = it }
}
@@ -115,6 +116,7 @@ class SettingsFragment : Fragment(), DeleteConfirmationDialogFragment.Listener {
button_confirm_scans_manually.isChecked = confirmScansManually
button_save_scanned_barcodes.isChecked = saveScannedBarcodesToHistory
button_save_created_barcodes.isChecked = saveCreatedBarcodesToHistory
+ button_do_not_save_duplicates.isChecked = doNotSaveDuplicates
button_enable_error_reports.isChecked = areErrorReportsEnabled
}
}
diff --git a/app/src/main/java/com/example/barcodescanner/model/Barcode.kt b/app/src/main/java/com/example/barcodescanner/model/Barcode.kt
index daa73b37..90cb2d66 100644
--- a/app/src/main/java/com/example/barcodescanner/model/Barcode.kt
+++ b/app/src/main/java/com/example/barcodescanner/model/Barcode.kt
@@ -12,13 +12,14 @@ import java.io.Serializable
@TypeConverters(BarcodeDatabaseTypeConverter::class)
data class Barcode(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
+ val name: String? = null,
val text: String,
val formattedText: String,
val format: BarcodeFormat,
val schema: BarcodeSchema,
val date: Long,
val isGenerated: Boolean = false,
- var isFavorite: Boolean = false,
+ val isFavorite: Boolean = false,
val errorCorrectionLevel: String? = null,
val country: String? = null
) : Serializable
\ No newline at end of file
diff --git a/app/src/main/java/com/example/barcodescanner/model/ParsedBarcode.kt b/app/src/main/java/com/example/barcodescanner/model/ParsedBarcode.kt
index b3c4d208..46352dfa 100644
--- a/app/src/main/java/com/example/barcodescanner/model/ParsedBarcode.kt
+++ b/app/src/main/java/com/example/barcodescanner/model/ParsedBarcode.kt
@@ -4,13 +4,14 @@ import com.example.barcodescanner.model.schema.*
import com.google.zxing.BarcodeFormat
class ParsedBarcode(barcode: Barcode) {
- val id = barcode.id
+ var id = barcode.id
+ var name = barcode.name
val text = barcode.text
val formattedText = barcode.formattedText
val format = barcode.format
val schema = barcode.schema
val date = barcode.date
- val isFavorite = barcode.isFavorite
+ var isFavorite = barcode.isFavorite
val country = barcode.country
var firstName: String? = null
diff --git a/app/src/main/java/com/example/barcodescanner/model/schema/VCard.kt b/app/src/main/java/com/example/barcodescanner/model/schema/VCard.kt
index c04c8ab1..ac5b501b 100644
--- a/app/src/main/java/com/example/barcodescanner/model/schema/VCard.kt
+++ b/app/src/main/java/com/example/barcodescanner/model/schema/VCard.kt
@@ -1,5 +1,6 @@
package com.example.barcodescanner.model.schema
+import com.example.barcodescanner.extension.joinToStringNotNullOrBlank
import com.example.barcodescanner.extension.joinToStringNotNullOrBlankWithLineSeparator
import com.example.barcodescanner.extension.startsWithIgnoreCase
import ezvcard.Ezvcard
@@ -26,19 +27,21 @@ data class VCard(
val secondaryPhoneType: String? = null,
val tertiaryPhone: String? = null,
val tertiaryPhoneType: String? = null,
+ val address: String? = null,
val geoUri: String? = null,
val url: String? = null
) : Schema {
companion object {
private const val SCHEMA_PREFIX = "BEGIN:VCARD"
+ private const val ADDRESS_SEPARATOR = ","
fun parse(text: String): VCard? {
if (text.startsWithIgnoreCase(SCHEMA_PREFIX).not()) {
return null
}
- val vCard = Ezvcard.parse(text).first()
+ val vCard = Ezvcard.parse(text).first() ?: return null
val firstName = vCard.structuredName?.given
val lastName = vCard.structuredName?.family
val nickname = vCard.nickname?.values?.firstOrNull()
@@ -58,6 +61,7 @@ data class VCard(
var secondaryPhoneType: String? = null
var tertiaryPhone: String? = null
var tertiaryPhoneType: String? = null
+ var address: String? = null
vCard.emails?.getOrNull(0)?.apply {
email = value
@@ -85,6 +89,16 @@ data class VCard(
tertiaryPhoneType = types?.firstOrNull()?.value
}
+ vCard.addresses.firstOrNull()?.apply {
+ address = listOf(
+ country,
+ postalCode,
+ region,
+ locality,
+ streetAddress
+ ).joinToStringNotNullOrBlank(ADDRESS_SEPARATOR)
+ }
+
return VCard(
firstName,
lastName,
@@ -103,6 +117,7 @@ data class VCard(
secondaryPhoneType,
tertiaryPhone,
tertiaryPhoneType,
+ address,
geoUri,
url
)
@@ -123,6 +138,7 @@ data class VCard(
"${email.orEmpty()} ${emailType.orEmpty()}",
"${secondaryEmail.orEmpty()} ${secondaryEmailType.orEmpty()}",
"${tertiaryEmail.orEmpty()} ${tertiaryEmailType.orEmpty()}",
+ address,
geoUri,
url
).joinToStringNotNullOrBlankWithLineSeparator()
diff --git a/app/src/main/java/com/example/barcodescanner/model/schema/Wifi.kt b/app/src/main/java/com/example/barcodescanner/model/schema/Wifi.kt
index c7275e64..b1d274b4 100644
--- a/app/src/main/java/com/example/barcodescanner/model/schema/Wifi.kt
+++ b/app/src/main/java/com/example/barcodescanner/model/schema/Wifi.kt
@@ -1,6 +1,7 @@
package com.example.barcodescanner.model.schema
import com.example.barcodescanner.extension.*
+import java.util.*
class Wifi(
val encryption: String? = null,
@@ -14,6 +15,8 @@ class Wifi(
) : Schema {
companion object {
+ private val WIFI_REGEX = """^WIFI:((?:.+?:(?:[^\\;]|\\.)*;)+);?$""".toRegex()
+ private val PAIR_REGEX = """(.+?):((?:[^\\;]|\\.)*);""".toRegex()
private const val SCHEMA_PREFIX = "WIFI:"
private const val ENCRYPTION_PREFIX = "T:"
private const val NAME_PREFIX = "S:"
@@ -30,68 +33,23 @@ class Wifi(
return null
}
- var encryption: String? = null
- var name: String? = null
- var password: String? = null
- var isHidden: Boolean? = null
- var anonymousIdentity: String? = null
- var identity: String? = null
- var eapMethod: String? = null
- var phase2Method: String? = null
-
- text.removePrefixIgnoreCase(SCHEMA_PREFIX)
- .split(SEPARATOR)
- .forEach { part ->
- if (part.startsWithIgnoreCase(ENCRYPTION_PREFIX)) {
- encryption = part.removePrefixIgnoreCase(ENCRYPTION_PREFIX)
- return@forEach
- }
-
- if (part.startsWithIgnoreCase(NAME_PREFIX)) {
- name = part.removePrefixIgnoreCase(NAME_PREFIX)
- return@forEach
- }
-
- if (part.startsWithIgnoreCase(PASSWORD_PREFIX)) {
- password = part.removePrefixIgnoreCase(PASSWORD_PREFIX)
- return@forEach
- }
-
- if (part.startsWithIgnoreCase(IS_HIDDEN_PREFIX)) {
- isHidden = part.removePrefixIgnoreCase(IS_HIDDEN_PREFIX).toBoolean()
- return@forEach
- }
-
- if (part.startsWithIgnoreCase(ANONYMOUS_IDENTITY_PREFIX)) {
- anonymousIdentity = part.removePrefixIgnoreCase(ANONYMOUS_IDENTITY_PREFIX)
- return@forEach
- }
-
- if (part.startsWithIgnoreCase(IDENTITY_PREFIX)) {
- identity = part.removePrefixIgnoreCase(IDENTITY_PREFIX)
- return@forEach
- }
-
- if (part.startsWithIgnoreCase(EAP_PREFIX)) {
- eapMethod = part.removePrefixIgnoreCase(EAP_PREFIX)
- return@forEach
- }
-
- if (part.startsWithIgnoreCase(PHASE2_PREFIX)) {
- phase2Method = part.removePrefixIgnoreCase(PHASE2_PREFIX)
- return@forEach
- }
+ val keysAndValuesSubstring = WIFI_REGEX.matchEntire(text)?.groupValues?.get(1) ?: return null
+ val keysAndValues = PAIR_REGEX
+ .findAll(keysAndValuesSubstring)
+ .map { pair ->
+ "${pair.groupValues[1].toUpperCase(Locale.US)}:" to pair.groupValues[2]
}
+ .toMap()
return Wifi(
- encryption?.unescape(),
- name?.unescape(),
- password?.unescape(),
- isHidden,
- anonymousIdentity?.unescape(),
- identity?.unescape(),
- eapMethod,
- phase2Method
+ keysAndValues[ENCRYPTION_PREFIX]?.unescape(),
+ keysAndValues[NAME_PREFIX]?.unescape(),
+ keysAndValues[PASSWORD_PREFIX]?.unescape(),
+ keysAndValues[IS_HIDDEN_PREFIX].toBoolean(),
+ keysAndValues[ANONYMOUS_IDENTITY_PREFIX]?.unescape(),
+ keysAndValues[IDENTITY_PREFIX]?.unescape(),
+ keysAndValues[EAP_PREFIX],
+ keysAndValues[PHASE2_PREFIX]
)
}
}
@@ -99,7 +57,7 @@ class Wifi(
override val schema = BarcodeSchema.WIFI
override fun toFormattedText(): String {
- return listOf(name, password).joinToStringNotNullOrBlankWithLineSeparator()
+ return listOf(name, encryption, password).joinToStringNotNullOrBlankWithLineSeparator()
}
override fun toBarcodeText(): String {
diff --git a/app/src/main/java/com/example/barcodescanner/usecase/BarcodeDatabase.kt b/app/src/main/java/com/example/barcodescanner/usecase/BarcodeDatabase.kt
index a3e591d9..c89a5e88 100644
--- a/app/src/main/java/com/example/barcodescanner/usecase/BarcodeDatabase.kt
+++ b/app/src/main/java/com/example/barcodescanner/usecase/BarcodeDatabase.kt
@@ -3,6 +3,8 @@ package com.example.barcodescanner.usecase
import android.content.Context
import androidx.paging.DataSource
import androidx.room.*
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.barcodescanner.model.Barcode
import com.example.barcodescanner.model.ExportBarcode
import com.example.barcodescanner.model.schema.BarcodeSchema
@@ -35,7 +37,7 @@ class BarcodeDatabaseTypeConverter {
}
-@Database(entities = [Barcode::class], version = 1)
+@Database(entities = [Barcode::class], version = 2)
abstract class BarcodeDatabaseFactory : RoomDatabase() {
abstract fun getBarcodeDatabase(): BarcodeDatabase
}
@@ -50,6 +52,11 @@ interface BarcodeDatabase {
fun getInstance(context: Context): BarcodeDatabase {
return INSTANCE ?: Room
.databaseBuilder(context.applicationContext, BarcodeDatabaseFactory::class.java, "db")
+ .addMigrations(object : Migration(1, 2) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("ALTER TABLE codes ADD COLUMN name TEXT")
+ }
+ })
.build()
.getBarcodeDatabase().apply {
INSTANCE = this
@@ -58,14 +65,17 @@ interface BarcodeDatabase {
}
@Query("SELECT * FROM codes ORDER BY date DESC")
-
fun getAll(): DataSource.Factory
+
@Query("SELECT * FROM codes WHERE isFavorite = 1 ORDER BY date DESC")
fun getFavorites(): DataSource.Factory
@Query("SELECT date, format, text FROM codes ORDER BY date DESC")
fun getAllForExport(): Single>
+ @Query("SELECT * FROM codes WHERE format = :format AND text = :text LIMIT 1")
+ fun find(format: String, text: String): Single>
+
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun save(barcode: Barcode): Single
@@ -75,3 +85,22 @@ interface BarcodeDatabase {
@Query("DELETE FROM codes")
fun deleteAll(): Completable
}
+
+fun BarcodeDatabase.save(barcode: Barcode, doNotSaveDuplicates: Boolean): Single {
+ return if (doNotSaveDuplicates) {
+ saveIfNotPresent(barcode)
+ } else {
+ save(barcode)
+ }
+}
+
+fun BarcodeDatabase.saveIfNotPresent(barcode: Barcode): Single {
+ return find(barcode.format.name, barcode.text)
+ .flatMap { found ->
+ if (found.isEmpty()) {
+ save(barcode)
+ } else {
+ Single.just(found[0].id)
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/barcodescanner/usecase/BarcodeImageGenerator.kt b/app/src/main/java/com/example/barcodescanner/usecase/BarcodeImageGenerator.kt
index 0cc8806d..b9b125be 100644
--- a/app/src/main/java/com/example/barcodescanner/usecase/BarcodeImageGenerator.kt
+++ b/app/src/main/java/com/example/barcodescanner/usecase/BarcodeImageGenerator.kt
@@ -39,14 +39,18 @@ object BarcodeImageGenerator {
codeColor: Int = Color.BLACK,
backgroundColor: Int = Color.WHITE
): Bitmap {
- val matrix = encoder.encode(
- barcode.text,
- barcode.format,
- width,
- height,
- createHints(barcode.errorCorrectionLevel, margin)
- )
- return createBitmap(matrix, codeColor, backgroundColor)
+ try {
+ val matrix = encoder.encode(
+ barcode.text,
+ barcode.format,
+ width,
+ height,
+ createHints(barcode.errorCorrectionLevel, margin)
+ )
+ return createBitmap(matrix, codeColor, backgroundColor)
+ } catch (ex: Exception) {
+ throw Exception("Unable to generate barcode image, ${barcode.format}, ${barcode.text}", ex)
+ }
}
fun generateSvgAsync(barcode: Barcode, width: Int, height: Int, margin: Int = 0): Single {
diff --git a/app/src/main/java/com/example/barcodescanner/usecase/Settings.kt b/app/src/main/java/com/example/barcodescanner/usecase/Settings.kt
index 72ae06f1..ce2803d3 100644
--- a/app/src/main/java/com/example/barcodescanner/usecase/Settings.kt
+++ b/app/src/main/java/com/example/barcodescanner/usecase/Settings.kt
@@ -38,6 +38,7 @@ class Settings(private val context: Context) {
IS_BACK_CAMERA,
SAVE_SCANNED_BARCODES_TO_HISTORY,
SAVE_CREATED_BARCODES_TO_HISTORY,
+ DO_NOT_SAVE_DUPLICATES,
SEARCH_ENGINE,
ERROR_REPORTS,
}
@@ -112,6 +113,10 @@ class Settings(private val context: Context) {
get() = get(Key.SAVE_CREATED_BARCODES_TO_HISTORY, true)
set(value) = set(Key.SAVE_CREATED_BARCODES_TO_HISTORY, value)
+ var doNotSaveDuplicates: Boolean
+ get() = get(Key.DO_NOT_SAVE_DUPLICATES, false)
+ set(value) = set(Key.DO_NOT_SAVE_DUPLICATES, value)
+
var searchEngine: SearchEngine
get() = get(Key.SEARCH_ENGINE, SearchEngine.NONE)
set(value) = set(Key.SEARCH_ENGINE, value)
diff --git a/app/src/main/res/drawable/ic_edit.xml b/app/src/main/res/drawable/ic_edit.xml
new file mode 100644
index 00000000..5b56f6f2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_edit.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_save.xml b/app/src/main/res/drawable/ic_save.xml
new file mode 100644
index 00000000..731bd9fe
--- /dev/null
+++ b/app/src/main/res/drawable/ic_save.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_all_permissions.xml b/app/src/main/res/layout/activity_all_permissions.xml
index 56154299..15313d55 100644
--- a/app/src/main/res/layout/activity_all_permissions.xml
+++ b/app/src/main/res/layout/activity_all_permissions.xml
@@ -26,6 +26,52 @@
android:layout_height="wrap_content"
android:orientation="vertical"
>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_barcode.xml b/app/src/main/res/layout/activity_barcode.xml
index 03deb5f5..3d9f0c21 100644
--- a/app/src/main/res/layout/activity_barcode.xml
+++ b/app/src/main/res/layout/activity_barcode.xml
@@ -50,14 +50,42 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml
index 4e570282..f841eebf 100644
--- a/app/src/main/res/layout/fragment_settings.xml
+++ b/app/src/main/res/layout/fragment_settings.xml
@@ -154,6 +154,13 @@
android:layout_height="wrap_content"
app:text="@string/fragment_settings_save_created_barcodes_to_history"
/>
+
@@ -50,6 +50,7 @@
android:maxLines="1"
tools:text="Hello World!"
android:includeFontPadding="false"
+ android:ellipsize="end"
style="@style/DefaultTextViewStyle"
/>
-
@@ -24,21 +22,19 @@
android:layout_width="@dimen/icon_button_icon_size"
android:layout_height="@dimen/icon_button_icon_size"
android:layout_gravity="center_vertical"
- android:tint="@color/white"
+ app:tint="@color/white"
tools:src="@drawable/ic_copy"
/>
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_barcode.xml b/app/src/main/res/menu/menu_barcode.xml
index 5994c4d1..bf31cbdc 100644
--- a/app/src/main/res/menu/menu_barcode.xml
+++ b/app/src/main/res/menu/menu_barcode.xml
@@ -23,12 +23,22 @@
android:id="@+id/item_add_to_favorites"
android:title="@string/activity_barcode_add_to_favorites"
android:icon="@drawable/ic_favorite_unchecked"
+ android:visible="false"
app:showAsAction="ifRoom"
/>
+
@@ -36,6 +46,7 @@
android:id="@+id/item_delete"
android:title="@string/activity_barcode_delete"
android:icon="@drawable/ic_delete"
+ android:visible="false"
app:iconTint="@color/toolbar_menu_color"
app:showAsAction="ifRoom"
/>
diff --git a/app/src/main/res/menu/menu_scan_barcode_from_image.xml b/app/src/main/res/menu/menu_scan_barcode_from_image.xml
index 709d93ca..0be5f29e 100644
--- a/app/src/main/res/menu/menu_scan_barcode_from_image.xml
+++ b/app/src/main/res/menu/menu_scan_barcode_from_image.xml
@@ -8,20 +8,20 @@
android:title="@string/activity_scan_barcode_from_file_rotate_left"
android:icon="@drawable/ic_rotate_left"
app:iconTint="@color/toolbar_menu_color"
- app:showAsAction="always"
+ app:showAsAction="ifRoom"
/>
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 95e4bf55..7f8c8639 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -23,6 +23,16 @@
Verlauf löschen?
Löschen?
+
+ Bestätigen
+ OK
+ Abbrechen
+
+
+ Edit name
+ OK
+ Cancel
+
Scannen
Erstellen
@@ -33,9 +43,6 @@
Bild lesen
Blitz
Gespeichert
- Bestätigen
- OK
- Abbrechen
Scannen
diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml
index 34cc25ef..4db3bcbd 100644
--- a/app/src/main/res/values-night/styles.xml
+++ b/app/src/main/res/values-night/styles.xml
@@ -1,6 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index b5c12e75..78a2c35b 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -22,6 +22,16 @@
Excluir o histórico?
Excluir?
+
+ Confirmar
+ OK
+ Cancelar
+
+
+ Edit name
+ OK
+ Cancel
+
Escanear
Criar
@@ -32,9 +42,6 @@
Escanear a imagem
Flash
Salvado
- Confirmar
- OK
- Cancelar
Escanear
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index a41ecd8f..187552b0 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -22,6 +22,16 @@
Очистить историю?
Удалить?
+
+ Подтвердить
+ OK
+ Отмена
+
+
+ Изменить название
+ OK
+ Отмена
+
Сканер
Создать
@@ -32,9 +42,6 @@
Сканировать\nфайл
Фонарик
Сохранено
- Подтвердить
- OK
- Отмена
Сканировать
@@ -196,6 +203,8 @@
История
Сохранять отсканированные штрихкоды в историю
Сохранять созданные штрихкоды в историю
+ Не сохранять дубликаты
+ Не сохранять дубликаты в истории
Очистить историю
Расширенные настройки
Поисковые системы
@@ -236,12 +245,20 @@
Разрешения
+ Обычные
+ Вибрация
+ Используется для вибрирования при сканировании
+ Wi-Fi
+ Используется для подключения к Wi-Fi с помощью QR кода
+ Интернет
+ Используется для отправки отчетов об ошибках. Может быть отключено в настройках.
+ Запрашиваемые
Камера
- Нужно для сканирования QR и штрихкодов при помощи камеры
+ Используется для сканирования QR и штрихкодов при помощи камеры
Контакты
- Нужно для создания QR-кода контакта
+ Используется для создания QR-кодов контактов
Память
- Нужно для сохранения QR и штрихкодов
+ Используется для сохранения QR и штрихкодов
Поиск на Rate&Goods
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 9c94b944..1ab9ae3a 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -191,9 +191,9 @@
11 位數字
7 位數字
已儲存
- 取消
- OK
- 確認
+ 取消
+ OK
+ 確認
閃光燈
掃描圖片
關於
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 417ccfe3..8708e6d0 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -7,11 +7,15 @@
+
+
+
+
+
-
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 08a66e6b..c28e44af 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -56,7 +56,7 @@
#B2B2B2
#424242
#6B7D7D7D
- #FDD70A
+ #FDD70A
#00B1FF
#9EDBF7
#00BFC9
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 23c48af9..9c830b71 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -33,4 +33,6 @@
2dp
4dp
+ 20dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f80670fa..c11aedf9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -22,6 +22,16 @@
Delete history?
Delete?
+
+ Confirm
+ OK
+ Cancel
+
+
+ Edit name
+ OK
+ Cancel
+
Scan
Create
@@ -32,9 +42,6 @@
Scan image
Flash
Saved
- Confirm
- OK
- Cancel
Scan
@@ -217,6 +224,8 @@
History
Save scanned barcodes to history
Save created barcodes to history
+ Do not save duplicates
+ Avoid duplicates in history
Clear history
Advanced
Search Engines
@@ -257,6 +266,14 @@
Permissions
+ Normal
+ Vibrate
+ Used to vibrate on scan
+ Wi-Fi
+ Used to connect to Wi-Fi by scanning a QR code
+ Internet
+ Used to send error reports. This can be disabled in settings.
+ Runtime
Camera
Used to scan QR codes and barcodes from camera
Read contacts
diff --git a/build.gradle b/build.gradle
index a80b4c09..39cf4763 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.72'
+ ext.kotlin_version = '1.4.10'
repositories {
google()
jcenter()
@@ -9,9 +9,9 @@ buildscript {
maven { url "https://jitpack.io" }
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.0.1'
+ classpath 'com.android.tools.build:gradle:4.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'io.sentry:sentry-android-gradle-plugin:1.7.25'
+ classpath 'io.sentry:sentry-android-gradle-plugin:1.7.28'
}
}
diff --git a/fastlane/metadata/android/en-US/changelogs/8.txt b/fastlane/metadata/android/en-US/changelogs/8.txt
new file mode 100644
index 00000000..ac65efdd
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/8.txt
@@ -0,0 +1,5 @@
+* Add a setting to avoid duplicates in history
+* Add an option to manually save to history
+* Add an option to set a name to a history item
+* Bug fix: app shortcuts were not working
+* Bug fix: Wi-Fi QR code passwords were scanned wrong
\ No newline at end of file
diff --git a/fastlane/metadata/android/ru/changelogs/8.txt b/fastlane/metadata/android/ru/changelogs/8.txt
new file mode 100644
index 00000000..388added
--- /dev/null
+++ b/fastlane/metadata/android/ru/changelogs/8.txt
@@ -0,0 +1,4 @@
+* Добавлена настройка для сохранения дубликатов в истории
+* Добавлена возможность для выборочного сохранения в историю
+* Добавлена возможность задать название для отсканированного кода в истории
+* Исправление багов
\ No newline at end of file