Compare commits

...
102 Commits
Author SHA1 Message Date
Markus Fisch faeae9e904 Advance version number to 1.65.0 2025-03-11 23:23:55 +01:00
Markus Fisch 77b21a9e83 Add a welcome screen to choose a mode
To address these bad reviews when people don't understand that
they have to press this little green button.
2025-03-11 23:17:36 +01:00
Markus Fisch cbe7860a3d Add a deep link to encode a barcode 2025-03-11 22:58:45 +01:00
Markus Fisch fc29267d3d Update ZXing-C++ library 2025-03-11 22:58:10 +01:00
Markus Fisch 890506328b Fix show crop handle setting
This switch isn't part of the crop configuration, but controls if
the crop handle is actually visible or not.
2025-03-11 22:58:10 +01:00
Markus Fisch 04036b6cd6 Use apply scope function to initialize views
And remove all this repetition of names.
2025-03-11 22:58:10 +01:00
Markus Fisch 2602021c1c Remove unused import from PickActivity 2025-03-11 22:58:10 +01:00
Markus Fisch 17a0bdc0a9 Allow shrinking of image samples too
So they can fit in the crop window.
2025-03-11 22:58:10 +01:00
Markus Fisch d71a220eca Remember zoom level of barcodes in view
Solves #490.
2025-03-11 22:58:10 +01:00
Markus Fisch 0c2e711d79 Add a comment why Scan.text can be an empty string
So it's immediately clear why `Scan.text` can be empty.
2025-03-11 22:58:10 +01:00
Markus Fisch ca342a83d3 Configure ZXingCpp to return plain text only
And remove the HRI decoration because it's confusing people and
doesn't work well when the barcode is re-generated from this
content.

Alternatively, we could filter the HRI decoration for generation,
but that's probably overkill.

Solves #506.
2025-03-11 22:58:10 +01:00
Markus Fisch 3c44ff56eb Refactor SCAN_CONTENT to SCAN_TEXT
To match the refactoring of `Scan.text` in 5189fc.
2025-03-11 22:58:10 +01:00
bovirusandGitHub bcae64c0d0 Italian language update 2025-03-11 22:57:50 +01:00
Markus Fisch c2f673729b Advance version number to 1.64.2 2025-03-10 21:23:52 +01:00
Markus Fisch 2043e0f349 Use separate crop handle config for image scanning
These are two different use cases.
2025-03-10 21:11:41 +01:00
Markus Fisch b93eb5963e Use raw content for Barcode<*> when text is empty
So binary content is supported here, too.
2025-03-10 11:01:15 +01:00
Markus Fisch 5189fc9c5a Refactor Scan.content to Scan.text
Because `text` is more specific, and the term `content` is often
used for generics.
2025-03-10 10:54:44 +01:00
Markus Fisch 2d311ff92a Fix initializing dataMask
And show this item for QR Codes only.
2025-03-10 19:50:19 +01:00
solokotandGitHub 14bb08003d Update Russian translation 2025-03-10 10:31:50 +01:00
Markus Fisch 42f9887030 Advance version number to 1.64.1 2025-03-09 22:39:37 +01:00
Markus Fisch a59d241b50 Handle empty input for recreation 2025-03-09 22:35:28 +01:00
Markus Fisch 9f31160c7b Add missing symbol fields to initial db creation 2025-03-09 22:14:06 +01:00
Markus Fisch 2eb4e51c17 Advance version number to 1.64.0 2025-03-09 19:43:00 +01:00
Markus Fisch 53a554e7a2 Add a menu item to find a specific barcode
The searched barcode needs to include the given term.

Solves #516.
2025-03-09 19:09:19 +01:00
Markus Fisch 7f6887716a Use Barcode for recreation too
And move `Barcode` into its own file.

So a given `BitMatrix` can be used for `BarcodeFragment` (and sharing
and exporting) as well.
2025-03-09 14:19:27 +01:00
Markus Fisch 5ef93802ce Make margin optional for BarcodeFragment
Just like `ecLevel` and `colors`.
2025-03-09 12:57:23 +01:00
Markus Fisch c1eff08bb9 Remove unnecessary semicolons
Too much context change.
2025-03-09 12:56:48 +01:00
Markus Fisch 8798d44ec7 Fix showing QR Code data mask
The first data mask is 0.
2025-03-09 12:55:55 +01:00
Markus Fisch d4e31ff97e Update ZXing-C++ library
To fix data mask initialization.
2025-03-09 12:55:28 +01:00
solokotandGitHub ae8b08a85a Update Russian translation 2025-03-09 12:10:10 +01:00
Markus Fisch 09430d776e Replace margin with add quiet zone switch
Giving a margin in pixels doesn't scale with (the size) of the
barcode.
2025-03-08 22:18:04 +01:00
Markus Fisch ef88c3179d Use detected barcode matrix for recreation
If it is provided by ZXing-C++. Currently, this is only supported
for some 2D barcodes. But it's probably only really useful for them
because there's padding and and other stuff that 1D barcodes don't
have.

This may solve #507.
2025-03-08 21:57:13 +01:00
Markus Fisch c732ec726b Show data mask of QR Codes 2025-03-08 21:54:54 +01:00
Markus Fisch 801c768df4 Update ZXing-C++ library 2025-03-08 21:53:19 +01:00
Markus Fisch 552a2f6d57 Only color status bar in context mode before SDK35
Has no effect from SDK35 on anyway.
2025-03-04 21:31:55 +01:00
Markus Fisch 7fa8810197 Make getIdOfScanByContent() private
Because it can be.
2025-03-04 21:27:12 +01:00
Markus Fisch 254af25bbb Update database functions to non-nullable Cursors
Because `SQLiteDatabase.rawQuery` returns a non-nullable `Cursor` now.
2025-03-07 16:55:58 +01:00
Markus Fisch a27656c174 Add a translucent nav bar background on SDK35+
Because the system doesn't draw one anymore.
2025-03-05 15:24:44 +01:00
Markus Fisch 2ca55ebccc Fix setting window insets on SDK35+
The bottom padding from the navigation bar needs to be set, too.
2025-03-04 19:47:41 +01:00
Markus Fisch ec1d40942d Optimize vector drawables with avocado 2025-03-04 00:21:30 +01:00
Markus Fisch 7852e5ce9d Use color literal in vector drawable
Because resource references will not work correctly in images
generated for API < 21.
2025-03-04 00:20:31 +01:00
Markus Fisch f36a81d4a0 Update Kotlin version 2025-03-04 12:50:50 +01:00
Markus Fisch d86ea4073c Remove unused quantity for Brazilian Portuguese
Following the corresponding lint warning.
2025-03-04 12:50:37 +01:00
Markus Fisch a69530621d Add autoVerify for URL intent filter 2025-03-04 12:50:28 +01:00
Markus Fisch 3c0f29a768 Add targetApi notation for quick settings tile
Since this is only available from Android N+.
2025-03-04 00:09:12 +01:00
Markus Fisch ccf5157fa7 Mark autofocus as optional
As it isn't strictly required.
2025-03-04 00:08:58 +01:00
Markus Fisch c1ebb1c154 Specify an explicit locale for String.format()
To silent the corresponding lint warning.

Doesn't really matter here probably.
2025-03-04 00:07:59 +01:00
Markus Fisch a4778bcc02 Replace removeFirst with removeAt
Because `java.util.List#removeFirst` requires SDK35, and resolved
to a Kotlin stdlib extension function before.
2025-03-04 00:04:04 +01:00
Markus Fisch 24d2c6d8d6 Only color system bars before SDK35
And ignore deprecation warning in this branch.

System bars no longer have a background from SDK35+.
2025-03-03 23:59:14 +01:00
Markus Fisch 0f3a07f602 Name SDK that requires a change explicitly
Instead of using greater than, because this way we can search
for VANILLA_ICE_CREAM changes.
2025-03-04 12:34:33 +01:00
Markus Fisch 751d8932f8 Immediately replace toasts
Instead of showing them in sequence.

Because in this app, only the last message is important.

Speeds up continuous scanning. Especially when the scanned code is
also forwarded and the server result is displayed in the next toast
(see #523).
2025-03-03 23:47:16 +01:00
Markus Fisch 9c2d063c24 Update tools version 2025-03-03 20:55:16 +01:00
Markus Fisch 0f9bbf5b2f Extend toolbar under status bar on SDK35+
Because SDK 35 is edge-to-edge by default, and doesn't color the
status or navigation bar anymore.
2025-02-18 21:34:27 +01:00
Markus Fisch 530280981e Fix image rotation calculation 2025-02-18 21:30:46 +01:00
Markus Fisch ddfbb305c7 Check Bitmap.getConfig() for null before use 2025-02-18 21:27:30 +01:00
Markus Fisch 8d1a29922b Update to SDK 35 2025-02-18 21:26:52 +01:00
Markus Fisch c710f7c6ab Move Toolate link below the reference section
Reference-style links should be derefenced after the content.

Also add a proper header for the matter.
2025-02-14 20:40:33 +01:00
Yurt PageandGitHub 111c587eef Add link to Toolate in CONTRIBUTING 2025-02-14 20:39:35 +01:00
Markus Fisch 264e494487 Update tools version and gradle wrapper 2025-01-23 19:59:08 +01:00
Markus Fisch 8135b2a3dc Update build tools 2024-12-19 22:23:45 +01:00
kraloandGitHub dce62b70d3 Update README to explain non-clickable binaryeye:// url 2024-12-05 21:56:06 +01:00
Markus Fisch 533812c638 Revert removing http deep linking intent filter
This is required for "http(s)://markusfisch.de/BinaryEye?ret=".

This reverts commit 12554e63e2.
2024-12-05 19:52:56 +01:00
Markus Fisch 5dc5bed281 Fix indent in Portuguese (Brazil) translation 2024-12-01 17:58:36 +01:00
Too Late (bot)andGitHub 2a13561962 Update Portuguese (Brazil) translation 2024-12-01 17:57:46 +01:00
Markus Fisch 1476f41cda Advance version number to 1.63.13 2024-11-24 19:37:04 +01:00
Markus Fisch 0da1ffbe02 Use JavaVersion.VERSION_1_8 for compatibility
Instead of just the version literal. Using the literal breaks
when the host has a higher Java version installed.
2024-11-19 20:08:34 +01:00
Markus Fisch 980679b6a3 Avoid UTF-8 conversion for binary input data
Otherwise the data is modified and doesn't match the desired input.

Still, it's probably better to introduce another CheckBox to explicity
control charset conversion.
2024-11-17 16:50:02 +01:00
Markus Fisch 28cbb55299 Use early returns when handling escape sequences
Improves readability.
2024-11-17 16:47:23 +01:00
Markus Fisch 1a4e7d100a Improve readability of expanding escape sequences 2024-11-17 16:46:23 +01:00
Markus Fisch 265e43b439 Fix argument order for assertEquals()
In EscapeTest.
2024-11-17 16:44:56 +01:00
NathanandGitHub 03a58c3412 Update French translation 2024-11-13 21:37:17 +01:00
Markus Fisch 327cad48f0 Update coroutines library 2024-11-06 21:50:30 +01:00
Markus Fisch 8e64fe2f56 Update Kotlin version 2024-11-06 21:50:14 +01:00
Markus Fisch 368d4dbb66 Fix typo in german translation 2024-10-18 19:39:38 +02:00
Manuel CovasandGitHub c8c3c094db Fix chronological order of scans taken less than 1 second apart 2024-10-17 16:36:24 +02:00
Wiktor PerskawiecandGitHub aa4aefe35f Fix typos in README and PRIVACY 2024-10-17 16:34:34 +02:00
AhmedandGitHub 536b3d77c1 Update arabian zero plural translation 2024-10-02 16:14:54 +02:00
Markus Fisch bbf2a80981 Add missing plurals for arabic
To silence lint from complaining that these are missing.
2024-10-02 15:39:33 +02:00
AhmedandGitHub ae99214d6c Update plurals in arabic translation 2024-10-02 15:36:54 +02:00
AhmedandGitHub 73b5a0969c Add arabic translation 2024-10-02 12:42:07 +02:00
Markus Fisch bf5dc96ac9 Advance version number to 1.63.12 2024-09-26 21:30:48 +02:00
Markus Fisch 301d9c2513 Fix argument list of recreation in onClickListener 2024-09-26 21:24:49 +02:00
Markus Fisch 0a11611b8f Advance version number to 1.63.11 2024-09-21 20:20:24 +02:00
Markus Fisch 249e310e43 Simplify asking for a size when sharing/exporting 2024-09-20 12:10:06 +02:00
Sergiy StuparandGitHub 6279c5731a Update Ukrainian translation 2024-09-20 12:09:46 +02:00
bovirusandGitHub df98637951 Update Italian language 2024-09-18 12:09:08 +02:00
solokotandGitHub 08b3558e46 Update Russian translation 2024-09-18 12:08:45 +02:00
Markus Fisch 648ef6fdf8 Update Kotlin coroutines library 2024-09-17 22:38:04 +02:00
Markus Fisch 807f075a51 Update Kotlin version 2024-09-17 22:37:08 +02:00
Markus Fisch 27789beeed Simplify ellipsis regex 2024-09-17 22:31:42 +02:00
Markus Fisch 97bee27827 Replace View casts for generic denotation 2024-09-17 22:29:02 +02:00
Markus Fisch 3fee49301e Only ask for barcode size when exporting/sharing
Because this parameter is just relevant when exporting/sharing
a raster image format.
2024-09-17 22:28:37 +02:00
Markus Fisch 8a6073291b Improve size slider for barcode generation
Reduce size options to popular powers of two.

And add the option to generate a barcode in the smallest
possible size of one pixel per module.
2024-09-17 20:54:07 +02:00
Markus Fisch 47151de4a4 Fix indent in Portuguese (Brazil) translation 2024-09-06 16:19:41 +02:00
Too Late (bot)andGitHub 248c4edca1 Update Portuguese (Brazil) translation 2024-09-06 16:18:21 +02:00
Markus Fisch 2c7386d536 Fix indent in Chinese translation 2024-08-17 18:12:32 +02:00
Too Late (bot)andGitHub e19cad4c87 Update Chinese translation 2024-08-17 18:09:47 +02:00
ZahnstocherandGitHub 585e0f3372 Update parcel tracking URL 2024-07-25 12:04:37 +02:00
Markus Fisch 2b7f611774 Fix showing tooltip on action FAB 2024-07-24 20:21:50 +02:00
Markus Fisch 05b2a0d9c9 Support hyphens in the second level domain
To correctly recognize URLs as WebAction.
2024-07-24 20:08:57 +02:00
Markus Fisch e7287eb088 Update tools version and gradle wrapper 2024-07-24 19:41:43 +02:00
NathanandGitHub 4b45ad3fe7 Update French translation
Added translations for checksum calculation (1.63.8) and screen brightening (1.63.10) features.
2024-07-13 19:58:04 +02:00
89 changed files with 1828 additions and 591 deletions
+40
View File
@@ -1,5 +1,45 @@
# Change Log
## 1.65.0
* Add a welcome screen to choose a mode
* Add a deep link to encode a barcode
* Remember zoom level of generated barcodes
* Remove Human Readable Interpretation (HRI) decoration
* Update Italian translation
## 1.64.2
* Separate crop window settings for image scanning
* Fix initializing dataMask
* Update Russian translation
## 1.64.1
* Handle empty input for recreation
* Fix setting up database
## 1.64.0
* Find barcode by content
* Immediately replace toasts
* Use detected barcode for recreation
* Show data mask of QR Codes
* Fix deep linking
* Replace margin with quiet zone switch when generating barcodes
* Update Russian translation
* Update Portuguese (Brazil) translation
## 1.63.13
* Fix UTF-8 conversion of binary escape sequences when creating barcodes
* Fix scan order for intervals under one second
* Add arabic translation
* Update French translation
## 1.63.12
* Fix magnifying barcode recreation
## 1.63.11
* Update parcel tracking URL
* Update multiple translations
* Only ask for barcode size when exporting/sharing
## 1.63.10
* Use maximum brightness when showing a generated barcode
* Allow file input from share menu
+5
View File
@@ -16,5 +16,10 @@ to squash when merging into master:
Then write a [good commit message][commit_messages] to keep the history
meaningful and useful. One feature, one commit.
## Translations
For translations use [Toolate][toolate].
[android_best_practices]: https://developer.android.com/distribute/best-practices/develop/
[commit_messages]: https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines
[toolate]: https://toolate.othing.xyz/projects/binaryeye/
+5
View File
@@ -28,6 +28,11 @@ testscan:
-c android.intent.category.BROWSABLE \
-d 'binaryeye://scan/?ret=http%3A%2F%2Fmarkusfisch.de%2F%3Fresult%3D{RESULT}'
testencode:
adb shell am start -a android.intent.action.VIEW \
-c android.intent.category.BROWSABLE \
-d 'binaryeye://encode?content=Test\&format=QRCode'
testurl:
adb shell am start -a android.intent.action.VIEW \
-c android.intent.category.BROWSABLE \
+1 -1
View File
@@ -15,7 +15,7 @@ Before Android Q, this feature requires using
[WifiManager.getConfiguredNetworks][getConfiguredNetworks]
which requires `ACCESS_FINE_LOCATION`.
On Android Q an better, this permission is not requested nor required.
On Android Q and better, this permission is not requested nor required.
### [BLUETOOTH][BLUETOOTH], [BLUETOOTH_ADMIN][BLUETOOTH_ADMIN] and [BLUETOOTH_CONNECT][BLUETOOTH_CONNECT]
+14 -3
View File
@@ -2,7 +2,7 @@
Yet another barcode scanner for Android. As if there weren't [enough][play].
This one is free, without any ads and open source.
This one is free, without any ads, and open source.
Works in portrait and landscape orientation, can read inverted codes,
comes in Material Design and can also generate barcodes.
@@ -88,9 +88,11 @@ ZXing can generate the following barcode formats:
### Deep Links
You can invoke Binary Eye with a web URI intent from anything that can
open URIs. There are two options:
open URIs.
1. [binaryeye://scan](binaryeye://scan)
#### Decoding
1. [binaryeye://scan](binaryeye://scan) (note: GitHub does not render this as clickable link)
2. [http(s)://markusfisch.de/BinaryEye](http://markusfisch.de/BinaryEye)
If you want to get the scanned contents, you can add a `ret` query
@@ -104,6 +106,15 @@ Supported symbols are:
* `RESULT_BYTES` - raw result as a hex string
* `FORMAT` - barcode format
#### Encoding
1. [binaryeye://encode](binaryeye://encode)
You can use the URL arguments `content` and `format` to automatically
preset this data. For example:
[binaryeye://encode?content=Test&format=QRCODE](binaryeye://encode?content=Test&format=QRCODE)
### SCAN Intent
You can also use Binary Eye from other apps by using the
+10 -7
View File
@@ -9,8 +9,8 @@ android {
minSdk 9
targetSdk sdk_version
versionCode 138
versionName '1.63.10'
versionCode 145
versionName '1.65.0'
}
signingConfigs {
@@ -58,17 +58,20 @@ android {
}
}
// Required since Gradle 8.
compileOptions {
// Required for Gradle 8.
sourceCompatibility = 17
targetCompatibility = 17
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
// Kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0"
// Support
implementation "com.android.support:appcompat-v7:$support_version"
@@ -79,7 +82,7 @@ dependencies {
// External
implementation 'com.github.markusfisch:CameraView:1.10.0'
implementation 'com.github.markusfisch:ScalingImageView:1.4.1'
implementation 'com.github.markusfisch:zxing-cpp:v2.2.0.5'
implementation 'com.github.markusfisch:zxing-cpp:v2.3.0.3'
// Testing
testImplementation 'junit:junit:4.13.2'
+24 -3
View File
@@ -19,7 +19,8 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-feature android:name="android.hardware.camera.autofocus"
android:required="false" />
<uses-sdk tools:overrideLibrary="android.support.v14.preference"/>
<queries>
<intent>
@@ -75,6 +76,15 @@
<data android:host="details" android:scheme="market"
android:pathSuffix="id=com.xiaomi.scanner"/>
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="markusfisch.de"/>
<data android:pathPrefix="/BinaryEye"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -99,14 +109,25 @@
</intent-filter>
</activity>
<activity
android:name=".activity.MainActivity"
android:name=".activity.WelcomeActivity"
android:exported="true"/>
<activity
android:name=".activity.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="binaryeye" android:host="encode"/>
</intent-filter>
</activity>
<service
android:name=".service.ScanTileService"
android:icon="@drawable/ic_action_scan"
android:label="@string/scan_code"
android:exported="true"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
tools:targetApi="n">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
@@ -46,8 +46,8 @@ object OpenOrSearchAction : IAction {
).toMutableList()
// Remove the "Always ask" entry. The arrays search_engines_*
// are used in the preferences too.
names.removeFirst()
urls.removeFirst()
names.removeAt(0)
urls.removeAt(0)
if (prefs.openWithUrl.isNotEmpty()) {
names.add(prefs.openWithUrl)
urls.add(prefs.openWithUrl)
@@ -7,7 +7,7 @@ import de.markusfisch.android.binaryeye.content.openUrl
object WebAction : IAction {
private val colloquialRegex =
"^(URL:[ ]*)*(http[s]*://)*[A-Za-z0-9]{3,}\\.[A-Za-z]{2,}[^ \t\r\n]*$".toRegex()
"^(URL:[ ]*)*(http[s]*://)*[A-Za-z0-9-]{3,}\\.[A-Za-z]{2,}[^ \t\r\n]*$".toRegex()
override val iconResId: Int = R.drawable.ic_action_open
override val titleResId: Int = R.string.open_url
@@ -1,5 +1,6 @@
package de.markusfisch.android.binaryeye.activity
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
@@ -13,11 +14,11 @@ import android.os.Build
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.widget.EditText
import android.widget.SeekBar
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.adapter.prettifyFormatName
@@ -42,7 +43,7 @@ import de.markusfisch.android.binaryeye.net.sendAsync
import de.markusfisch.android.binaryeye.net.urlEncode
import de.markusfisch.android.binaryeye.preference.Preferences
import de.markusfisch.android.binaryeye.view.errorFeedback
import de.markusfisch.android.binaryeye.view.initSystemBars
import de.markusfisch.android.binaryeye.view.initBars
import de.markusfisch.android.binaryeye.view.scanFeedback
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
import de.markusfisch.android.binaryeye.widget.DetectorView
@@ -53,12 +54,14 @@ import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
import de.markusfisch.android.zxingcpp.ZxingCpp.Binarizer
import de.markusfisch.android.zxingcpp.ZxingCpp.ReaderOptions
import de.markusfisch.android.zxingcpp.ZxingCpp.Result
import de.markusfisch.android.zxingcpp.ZxingCpp.TextMode
import java.io.FileInputStream
import java.util.Scanner
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
class CameraActivity : AppCompatActivity() {
private val frameRoi = Rect()
private val matrix = Matrix()
@@ -77,6 +80,7 @@ class CameraActivity : AppCompatActivity() {
private var frontFacing = false
private var bulkMode = prefs.bulkMode
private var restrictFormat: String? = null
private var searchTerm: String? = null
private var ignoreNext: String? = null
private var fallbackBuffer: IntArray? = null
private var requestCameraPermission = true
@@ -125,8 +129,7 @@ class CameraActivity : AppCompatActivity() {
// custom locale.
setTitle(R.string.scan_code)
initSystemBars(this)
setSupportActionBar(findViewById(R.id.toolbar) as Toolbar)
initBars()
cameraView = findViewById(R.id.camera_view) as CameraView
detectorView = findViewById(R.id.detector_view) as DetectorView
@@ -148,14 +151,18 @@ class CameraActivity : AppCompatActivity() {
super.onDestroy()
fallbackBuffer = null
saveZoom()
detectorView.saveCropHandlePos()
detectorView.storeCropHandlePos(CAMERA_CROP_HANDLE)
releaseToneGenerators()
}
override fun onResume() {
super.onResume()
if (firstStart()) {
startActivity(Intent(this, WelcomeActivity::class.java))
return
}
System.gc()
updateHints()
updateHintsAndTitle()
if (prefs.bulkMode && bulkMode != prefs.bulkMode) {
bulkMode = prefs.bulkMode
invalidateOptionsMenu()
@@ -171,18 +178,43 @@ class CameraActivity : AppCompatActivity() {
requestCameraPermission = false
}
private fun updateHints() {
private fun Context.firstStart(): Boolean {
val welcomeShownName = "welcome_shown"
if (prefs.preferences.getBoolean(welcomeShownName, false)) {
android.util.Log.d("mfdbg", "mfdbg: already welcome shown")
return false
}
prefs.preferences.edit().putBoolean(welcomeShownName, true).apply()
val packageInfo = packageManager.getPackageInfo(packageName, 0)
val installedSince = System.currentTimeMillis() - packageInfo.firstInstallTime
android.util.Log.d("mfdbg", "mfdbg: installed since is $installedSince")
return installedSince < 86400000
}
private fun updateHintsAndTitle() {
val restriction = restrictFormat
formatsToRead = if (restriction != null) {
title = getString(
R.string.scan_format,
prettifyFormatName(restriction)
)
setOf(restriction)
} else {
setTitle(R.string.scan_code)
prefs.barcodeFormats
}.toFormatSet()
updateTitle()
}
private fun updateTitle() {
if (searchTerm != null || restrictFormat != null) {
title = getString(
R.string.scan_format,
prettifyFormatName(
listOfNotNull(
restrictFormat,
searchTerm
).joinToString(",")
)
)
} else {
setTitle(R.string.scan_code)
}
}
private fun setReturnTarget(intent: Intent?) {
@@ -227,6 +259,7 @@ class CameraActivity : AppCompatActivity() {
frontFacing = savedState.getBoolean(FRONT_FACING)
bulkMode = savedState.getBoolean(BULK_MODE)
restrictFormat = savedState.getString(RESTRICT_FORMAT)
searchTerm = savedState.getString(SEARCH_TERM)
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -235,6 +268,7 @@ class CameraActivity : AppCompatActivity() {
outState.putBoolean(FRONT_FACING, frontFacing)
outState.putBoolean(BULK_MODE, bulkMode)
outState.putString(RESTRICT_FORMAT, restrictFormat)
outState.putString(SEARCH_TERM, searchTerm)
super.onSaveInstanceState(outState)
}
@@ -295,6 +329,11 @@ class CameraActivity : AppCompatActivity() {
true
}
R.id.find_code -> {
askForCode()
true
}
R.id.preferences -> {
startActivity(MainActivity.getPreferencesIntent(this))
true
@@ -334,12 +373,36 @@ class CameraActivity : AppCompatActivity() {
setTitle(R.string.restrict_format)
setItems(names.toTypedArray()) { _, which ->
restrictFormat = formats[which]
updateHints()
updateHintsAndTitle()
}
show()
}
}
// Dialogs do not have a parent view.
@SuppressLint("InflateParams")
private fun askForCode() {
val view = layoutInflater.inflate(R.layout.dialog_find_code, null)
val editText = view.findViewById<EditText>(R.id.term)
searchTerm.let {
editText.setText(it)
}
AlertDialog.Builder(this)
.setView(view)
.setPositiveButton(android.R.string.ok) { _, _ ->
searchTerm = editText.text.toString()
if (searchTerm?.isEmpty() == true) {
searchTerm = null
}
updateTitle()
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
searchTerm = null
updateTitle()
}
.show()
}
private fun openReadme() {
val intent = Intent(
Intent.ACTION_VIEW,
@@ -478,7 +541,8 @@ class CameraActivity : AppCompatActivity() {
tryInvert = true,
tryDownscale = true,
returnCodabarStartEnd = true,
maxNumberOfSymbols = 1
maxNumberOfSymbols = 1,
textMode = TextMode.PLAIN
)
var useLocalAverage = false
camera.setPreviewCallback { frameData, _ ->
@@ -503,7 +567,11 @@ class CameraActivity : AppCompatActivity() {
}
)?.let { results ->
val result = results.first()
if (result.text != ignoreNext) {
val text = result.text
val term = searchTerm
if (text != ignoreNext &&
(term == null || text.contains(term))
) {
postResult(result)
decoding = false
}
@@ -574,7 +642,7 @@ class CameraActivity : AppCompatActivity() {
updateFrameRoiAndMappingMatrix()
}
detectorView.setPaddingFromWindowInsets()
detectorView.restoreCropHandlePos()
detectorView.restoreCropHandlePos(CAMERA_CROP_HANDLE)
}
private fun updateFrameRoiAndMappingMatrix() {
@@ -674,12 +742,15 @@ class CameraActivity : AppCompatActivity() {
}
companion object {
const val CAMERA_CROP_HANDLE = "camera_crop_handle"
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 FRONT_FACING = "front_facing"
private const val BULK_MODE = "bulk_mode"
private const val RESTRICT_FORMAT = "restrict_format"
private const val SEARCH_TERM = "search_term"
}
}
@@ -701,7 +772,7 @@ fun Activity.showResult(
if (prefs.sendScanActive && prefs.sendScanUrl.isNotEmpty()) {
if (prefs.sendScanType == "4") {
openUrl(
prefs.sendScanUrl + scan.content.urlEncode()
prefs.sendScanUrl + scan.text.urlEncode()
)
return
}
@@ -3,11 +3,11 @@ 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 android.support.v7.widget.Toolbar
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.PERMISSION_LOCATION
import de.markusfisch.android.binaryeye.app.PERMISSION_WRITE
@@ -21,8 +21,7 @@ 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.view.colorSystemAndToolBars
import de.markusfisch.android.binaryeye.view.initSystemBars
import de.markusfisch.android.binaryeye.view.recordToolbarHeight
import de.markusfisch.android.binaryeye.view.initBars
class MainActivity : AppCompatActivity() {
override fun onRequestPermissionsResult(
@@ -59,10 +58,7 @@ class MainActivity : AppCompatActivity() {
super.onCreate(state)
setContentView(R.layout.activity_main)
initSystemBars(this)
val toolbar = findViewById(R.id.toolbar) as Toolbar
recordToolbarHeight(toolbar)
setSupportActionBar(toolbar)
initBars()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportFragmentManager.addOnBackStackChangedListener {
@@ -85,6 +81,15 @@ class MainActivity : AppCompatActivity() {
return when {
intent.hasExtra(PREFERENCES) -> PreferencesFragment()
intent.hasExtra(HISTORY) -> HistoryFragment()
intent.dataString?.startsWith("binaryeye://encode") == true -> {
val uri = Uri.parse(intent.dataString)
EncodeFragment.newInstance(
uri.getQueryParameter("content"),
uri.getQueryParameter("format")
)
}
intent.hasExtra(ENCODE) -> EncodeFragment.newInstance(
intent.getStringExtra(ENCODE)
)
@@ -10,7 +10,6 @@ import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.Menu
import android.view.MenuItem
import de.markusfisch.android.binaryeye.R
@@ -22,8 +21,7 @@ import de.markusfisch.android.binaryeye.graphics.loadImageUri
import de.markusfisch.android.binaryeye.graphics.mapPosition
import de.markusfisch.android.binaryeye.media.releaseToneGenerators
import de.markusfisch.android.binaryeye.view.colorSystemAndToolBars
import de.markusfisch.android.binaryeye.view.initSystemBars
import de.markusfisch.android.binaryeye.view.recordToolbarHeight
import de.markusfisch.android.binaryeye.view.initBars
import de.markusfisch.android.binaryeye.view.scanFeedback
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
import de.markusfisch.android.binaryeye.widget.CropImageView
@@ -75,10 +73,7 @@ class PickActivity : AppCompatActivity() {
// locale.
setTitle(R.string.pick_code_to_scan)
initSystemBars(this)
val toolbar = findViewById(R.id.toolbar) as Toolbar
recordToolbarHeight(toolbar)
setSupportActionBar(toolbar)
initBars()
supportFragmentManager.addOnBackStackChangedListener {
colorSystemAndToolBars(this@PickActivity)
@@ -91,20 +86,28 @@ class PickActivity : AppCompatActivity() {
return
}
cropImageView = findViewById(R.id.image) as CropImageView
cropImageView.restrictTranslation = false
cropImageView.freeRotation = prefs.freeRotation
cropImageView.setImageBitmap(bitmap)
cropImageView.onScan = {
scanWithinBounds(bitmap)
cropImageView = (findViewById(R.id.image) as CropImageView).apply {
restrictTranslation = false
freeRotation = prefs.freeRotation
setImageBitmap(bitmap)
onScan = {
scanWithinBounds(bitmap)
}
runAfterLayout = {
minWidth = min(
minWidth / 2f,
max(bitmap.width, bitmap.height).toFloat()
)
}
}
detectorView = findViewById(R.id.detector_view) as DetectorView
detectorView.onRoiChanged = {
scanWithinBounds(bitmap)
detectorView = (findViewById(R.id.detector_view) as DetectorView).apply {
onRoiChanged = {
scanWithinBounds(bitmap)
}
setPaddingFromWindowInsets()
restoreCropHandlePos(PICKER_CROP_HANDLE)
}
detectorView.setPaddingFromWindowInsets()
detectorView.restoreCropHandlePos()
findViewById(R.id.scan).setOnClickListener {
showResult()
@@ -200,7 +203,7 @@ class PickActivity : AppCompatActivity() {
override fun onDestroy() {
super.onDestroy()
detectorView.saveCropHandlePos()
detectorView.storeCropHandlePos(PICKER_CROP_HANDLE)
parentJob.cancel()
releaseToneGenerators()
}
@@ -242,7 +245,7 @@ class PickActivity : AppCompatActivity() {
}
private fun rotateClockwise() {
cropImageView.imageRotation = cropImageView.imageRotation + 90 % 360
cropImageView.imageRotation = (cropImageView.imageRotation + 90) % 360
}
private fun loadSentImage(intent: Intent): Bitmap? {
@@ -264,6 +267,10 @@ class PickActivity : AppCompatActivity() {
applicationContext.toast(R.string.no_barcode_found)
}
}
companion object {
private const val PICKER_CROP_HANDLE = "picker_crop_handle"
}
}
private fun getNormalizedRoi(imageRect: RectF, roi: Rect): RectF {
@@ -0,0 +1,30 @@
package de.markusfisch.android.binaryeye.activity
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.prefs
class WelcomeActivity : AppCompatActivity() {
override fun onCreate(state: Bundle?) {
super.onCreate(state)
setContentView(R.layout.activity_welcome)
findViewById(R.id.expert).setOnClickListener {
finish()
}
findViewById(R.id.simple).setOnClickListener {
prefs.apply {
showCropHandle = false
zoomBySwiping = false
beep = true
copyImmediately = true
openImmediately = true
showMetaData = false
showHexDump = false
expandEscapeSequences = false
brightenScreen = true
}
finish()
}
}
}
@@ -20,7 +20,7 @@ class ScansAdapter(context: Context, cursor: Cursor) :
private val idIndex = cursor.getColumnIndex(Database.SCANS_ID)
private val timeIndex = cursor.getColumnIndex(Database.SCANS_DATETIME)
private val nameIndex = cursor.getColumnIndex(Database.SCANS_NAME)
private val contentIndex = cursor.getColumnIndex(Database.SCANS_CONTENT)
private val textIndex = cursor.getColumnIndex(Database.SCANS_TEXT)
private val formatIndex = cursor.getColumnIndex(Database.SCANS_FORMAT)
private val selections = mutableMapOf<Long, Int>()
private val selectedColor = ContextCompat.getColor(
@@ -74,7 +74,7 @@ class ScansAdapter(context: Context, cursor: Cursor) :
fun getContent(
position: Int
) = (getItem(position) as Cursor?)?.getString(contentIndex)
) = (getItem(position) as Cursor?)?.getString(textIndex)
override fun newView(
context: Context,
@@ -92,7 +92,7 @@ class ScansAdapter(context: Context, cursor: Cursor) :
getViewHolder(view).apply {
timeView.text = formatDateTime(cursor.getString(timeIndex))
val name = cursor.getString(nameIndex)
val content = cursor.getString(contentIndex)
val text = cursor.getString(textIndex)
var icon = 0
contentView.text = when {
name?.isNotEmpty() == true -> {
@@ -100,11 +100,11 @@ class ScansAdapter(context: Context, cursor: Cursor) :
name
}
content.isNullOrEmpty() -> context.getString(
text.isNullOrEmpty() -> context.getString(
R.string.binary_data
)
else -> content
else -> text
}
contentView.setCompoundDrawablesWithIntrinsicBounds(
icon, 0, 0, 0
@@ -24,7 +24,7 @@ fun Scan.sendBluetoothAsync(
connect(host, true)
}
val sent = if (connected) {
send(content, host, true)
send(text, host, true)
} else {
false
}
@@ -0,0 +1,179 @@
package de.markusfisch.android.binaryeye.content
import android.graphics.Bitmap
import de.markusfisch.android.binaryeye.database.Scan
import de.markusfisch.android.binaryeye.graphics.COLOR_BLACK
import de.markusfisch.android.binaryeye.graphics.COLOR_WHITE
import de.markusfisch.android.zxingcpp.ZxingCpp
import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
import de.markusfisch.android.zxingcpp.ZxingCpp.BitMatrix
import de.markusfisch.android.zxingcpp.ZxingCpp.toBitmap
import de.markusfisch.android.zxingcpp.ZxingCpp.toSvg
import de.markusfisch.android.zxingcpp.ZxingCpp.toText
import java.util.Arrays
enum class BarcodeColors {
BLACK_ON_WHITE,
WHITE_ON_BLACK,
BLACK_ON_TRANSPARENT,
WHITE_ON_TRANSPARENT;
fun foregroundColor(): Int = when (this) {
BLACK_ON_WHITE,
BLACK_ON_TRANSPARENT -> COLOR_BLACK
WHITE_ON_BLACK,
WHITE_ON_TRANSPARENT -> COLOR_WHITE
}
fun backgroundColor(): Int = when (this) {
BLACK_ON_WHITE -> COLOR_WHITE
WHITE_ON_BLACK -> COLOR_BLACK
BLACK_ON_TRANSPARENT,
WHITE_ON_TRANSPARENT -> 0
}
}
fun Scan.toBarcode(): Barcode<*> {
val content = text.ifEmpty {
raw
}
return if (symbol != null) {
BitMatrixBarcode(
symbol,
content,
format
)
} else {
ContentBarcode(
content,
format,
errorCorrectionLevel.toErrorCorrectionInt()
)
}
}
fun String?.toErrorCorrectionInt() = when (this) {
"L" -> 0
"M" -> 4
"Q" -> 6
"H" -> 8
else -> -1
}
abstract class Barcode<T>(
val content: T,
val format: BarcodeFormat,
val colors: BarcodeColors
) {
private var _bitmap: Bitmap? = null
fun bitmap(): Bitmap {
val b = _bitmap ?: bitmap(512)
_bitmap = b
return b
}
fun bitmap(size: Int): Bitmap {
return toBitmap(size)
}
protected abstract fun toBitmap(size: Int): Bitmap
private var _svg: String? = null
fun svg(): String {
val s = _svg ?: toSvg()
_svg = s
return s
}
protected abstract fun toSvg(): String
private var _text: String? = null
fun text(): String {
val t = _text ?: toText()
_text = t
return t
}
protected abstract fun toText(): String
}
class ContentBarcode<T>(
content: T,
format: BarcodeFormat,
val ecLevel: Int = -1,
val margin: Int = -1,
colors: BarcodeColors = BarcodeColors.BLACK_ON_WHITE
) : Barcode<T>(content, format, colors) {
override fun toBitmap(size: Int) = ZxingCpp.encodeAsBitmap(
content, format, size, size, margin, ecLevel,
setColor = colors.foregroundColor(),
unsetColor = colors.backgroundColor()
)
override fun toSvg() = ZxingCpp.encodeAsSvg(
content, format, margin, ecLevel
)
override fun toText() = ZxingCpp.encodeAsText(
content, format, margin, ecLevel,
inverted = colors == BarcodeColors.BLACK_ON_WHITE
)
}
class BitMatrixBarcode<T>(
val bitMatrix: BitMatrix,
content: T,
format: BarcodeFormat,
colors: BarcodeColors = BarcodeColors.BLACK_ON_WHITE
) : Barcode<T>(content, format, colors) {
override fun toBitmap(size: Int) = bitMatrix.inflate(size).toBitmap(
setColor = colors.foregroundColor(),
unsetColor = colors.backgroundColor()
)
override fun toSvg() = bitMatrix.inflate().toSvg()
override fun toText() = bitMatrix.inflate().toText(
inverted = colors == BarcodeColors.BLACK_ON_WHITE
)
}
private fun BitMatrix.inflate(
size: Int = 0,
quietZone: Boolean = true
): BitMatrix {
val extraModules = if (quietZone) 2 else 0
val codeWidth = width + extraModules
val codeHeight = height + extraModules
var scale = size / codeWidth
if (scale < 1) {
if (size > 0 && !quietZone) {
return this
}
scale = 1
}
val outWidth = codeWidth * scale
val outHeight = codeHeight * scale
val scaled = BitMatrix(
outWidth,
outHeight,
ByteArray(outWidth * outHeight)
)
Arrays.fill(scaled.data, 1)
val padding = extraModules / 2
val left = padding * scale
val top = padding * scale
val right = outWidth - left
val bottom = outHeight - top
for (y in top until bottom) {
var dst = y * outWidth + left
val offset = (y - top) / scale * width
for (x in left until right) {
scaled.data[dst++] = data[
offset + (x - left) / scale
]
}
}
return scaled
}
@@ -33,7 +33,7 @@ private fun exportCsv(
Database.SCANS_DATETIME,
Database.SCANS_FORMAT,
Database.SCANS_NAME,
Database.SCANS_CONTENT,
Database.SCANS_TEXT,
Database.SCANS_ERROR_CORRECTION_LEVEL,
Database.SCANS_VERSION,
Database.SCANS_SEQUENCE_SIZE,
@@ -47,7 +47,7 @@ private fun exportCsv(
val indices = columns.map {
cursor.getColumnIndex(it)
}
val contentIndex = cursor.getColumnIndex(Database.SCANS_CONTENT)
val contentIndex = cursor.getColumnIndex(Database.SCANS_TEXT)
val rawIndex = cursor.getColumnIndex(Database.SCANS_RAW)
outputStream.write(
columns.joinToString(
@@ -1,6 +1,7 @@
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
@@ -30,3 +31,18 @@ fun Cursor.getBlob(name: String): ByteArray? {
val idx = getColumnIndex(name)
return if (idx < 0) null else getBlob(idx)
}
fun Cursor.getBitMatrix(
widthName: String,
heightName: String,
dataName: String
): ZxingCpp.BitMatrix? {
val width = getInt(widthName)
val height = getInt(heightName)
val data = getBlob(dataName)
return if (width > 0 && height > 0 && data != null) {
ZxingCpp.BitMatrix(width, height, data)
} else {
null
}
}
@@ -16,12 +16,12 @@ class Database {
db = OpenHelper(context).writableDatabase
}
fun getScans(query: String? = null): Cursor? = db.rawQuery(
fun getScans(query: String? = null): Cursor = db.rawQuery(
"""SELECT
$SCANS_ID,
$SCANS_DATETIME,
$SCANS_NAME,
$SCANS_CONTENT,
$SCANS_TEXT,
$SCANS_FORMAT
FROM $SCANS
${getWhereClause(query)}
@@ -29,12 +29,12 @@ class Database {
""".trimMargin(), getWhereArguments(query)
)
fun getScansDetailed(query: String? = null): Cursor? = db.rawQuery(
fun getScansDetailed(query: String? = null): Cursor = db.rawQuery(
"""SELECT
$SCANS_ID,
$SCANS_DATETIME,
$SCANS_NAME,
$SCANS_CONTENT,
$SCANS_TEXT,
$SCANS_RAW,
$SCANS_FORMAT,
$SCANS_ERROR_CORRECTION_LEVEL,
@@ -56,7 +56,7 @@ class Database {
query: String?,
prefix: String = "WHERE"
) = if (query?.isNotEmpty() == true) {
"""$prefix $SCANS_CONTENT LIKE ?
"""$prefix $SCANS_TEXT LIKE ?
OR $SCANS_NAME LIKE ?"""
} else {
""
@@ -71,12 +71,12 @@ class Database {
null
}
fun getScansDetailed(ids: LongArray): Cursor? = db.rawQuery(
fun getScansDetailed(ids: LongArray): Cursor = db.rawQuery(
"""SELECT
$SCANS_ID,
$SCANS_DATETIME,
$SCANS_NAME,
$SCANS_CONTENT,
$SCANS_TEXT,
$SCANS_RAW,
$SCANS_FORMAT,
$SCANS_ERROR_CORRECTION_LEVEL,
@@ -99,11 +99,15 @@ class Database {
$SCANS_ID,
$SCANS_DATETIME,
$SCANS_NAME,
$SCANS_CONTENT,
$SCANS_TEXT,
$SCANS_RAW,
$SCANS_FORMAT,
$SCANS_ERROR_CORRECTION_LEVEL,
$SCANS_VERSION,
$SCANS_DATA_MASK,
$SCANS_SYMBOL_WIDTH,
$SCANS_SYMBOL_HEIGHT,
$SCANS_SYMBOL_DATA,
$SCANS_SEQUENCE_SIZE,
$SCANS_SEQUENCE_INDEX,
$SCANS_SEQUENCE_ID,
@@ -114,14 +118,20 @@ class Database {
FROM $SCANS
WHERE $SCANS_ID = ?
""".trimMargin(), arrayOf("$id")
)?.use {
).use {
if (it.moveToFirst()) {
Scan(
it.getString(SCANS_CONTENT),
it.getString(SCANS_TEXT),
it.getBlob(SCANS_RAW),
BarcodeFormat.valueOf(it.getString(SCANS_FORMAT)),
it.getString(SCANS_ERROR_CORRECTION_LEVEL),
it.getString(SCANS_VERSION),
it.getInt(SCANS_DATA_MASK),
it.getBitMatrix(
SCANS_SYMBOL_WIDTH,
SCANS_SYMBOL_HEIGHT,
SCANS_SYMBOL_DATA
),
it.getInt(SCANS_SEQUENCE_SIZE),
it.getInt(SCANS_SEQUENCE_INDEX),
it.getString(SCANS_SEQUENCE_ID),
@@ -142,7 +152,7 @@ class Database {
when (prefs.ignoreDuplicates()) {
Preferences.Companion.IgnoreDuplicates.Consecutive -> {
val id = getIdOfLastScan(
scan.content,
scan.text,
scan.raw,
scan.format
)
@@ -152,7 +162,7 @@ class Database {
}
Preferences.Companion.IgnoreDuplicates.Any -> {
val id = getIdOfScanByContent(scan.content, scan.format)
val id = getIdOfScanByContent(scan.text, scan.format)
if (id > 0L) {
return id
}
@@ -165,7 +175,7 @@ class Database {
null,
ContentValues().apply {
put(SCANS_DATETIME, scan.dateTime)
put(SCANS_CONTENT, scan.content)
put(SCANS_TEXT, scan.text)
if (scan.raw != null) {
put(SCANS_RAW, scan.raw)
}
@@ -174,6 +184,12 @@ class Database {
put(SCANS_ERROR_CORRECTION_LEVEL, it)
}
put(SCANS_VERSION, scan.version)
put(SCANS_DATA_MASK, scan.dataMask)
if (scan.symbol != null) {
put(SCANS_SYMBOL_WIDTH, scan.symbol.width)
put(SCANS_SYMBOL_HEIGHT, scan.symbol.height)
put(SCANS_SYMBOL_DATA, scan.symbol.data)
}
put(SCANS_SEQUENCE_SIZE, scan.sequenceSize)
put(SCANS_SEQUENCE_INDEX, scan.sequenceIndex)
put(SCANS_SEQUENCE_ID, scan.sequenceId)
@@ -192,17 +208,17 @@ class Database {
): Long = db.rawQuery(
"""SELECT
$SCANS_ID,
$SCANS_CONTENT,
$SCANS_TEXT,
$SCANS_RAW,
$SCANS_FORMAT
FROM $SCANS
ORDER BY $SCANS_ID DESC
LIMIT 1
""".trimMargin(), null
)?.use {
).use {
if (it.count > 0 &&
it.moveToFirst() &&
it.getString(SCANS_CONTENT) == content &&
it.getString(SCANS_TEXT) == content &&
(raw == null || it.getBlob(SCANS_RAW)
?.contentEquals(raw) == true) &&
it.getString(SCANS_FORMAT) == format.name
@@ -211,26 +227,26 @@ class Database {
} else {
0L
}
} ?: 0L
}
fun getIdOfScanByContent(
private fun getIdOfScanByContent(
content: String,
format: BarcodeFormat
): Long = db.rawQuery(
"""SELECT
$SCANS_ID
FROM $SCANS
WHERE $SCANS_CONTENT = ?
WHERE $SCANS_TEXT = ?
AND $SCANS_FORMAT = ?
LIMIT 1
""".trimMargin(), arrayOf(content, format.name)
)?.use {
).use {
if (it.moveToFirst()) {
it.getLong(SCANS_ID)
} else {
0L
}
} ?: 0L
}
fun removeScan(id: Long) {
db.delete(SCANS, "$SCANS_ID = ?", arrayOf("$id"))
@@ -247,7 +263,7 @@ class Database {
}
private class OpenHelper(context: Context) :
SQLiteOpenHelper(context, FILE_NAME, null, 6) {
SQLiteOpenHelper(context, FILE_NAME, null, 8) {
override fun onCreate(db: SQLiteDatabase) {
db.createScans()
}
@@ -272,6 +288,12 @@ class Database {
if (oldVersion < 6) {
db.migrateToVersionString()
}
if (oldVersion < 7) {
db.addDataMaskColumn()
}
if (oldVersion < 8) {
db.addSymbolColumns()
}
}
}
@@ -281,12 +303,16 @@ class Database {
const val SCANS_ID = "_id"
const val SCANS_DATETIME = "_datetime"
const val SCANS_NAME = "name"
const val SCANS_CONTENT = "content"
const val SCANS_TEXT = "content"
const val SCANS_RAW = "raw"
const val SCANS_FORMAT = "format"
const val SCANS_ERROR_CORRECTION_LEVEL = "error_correction_level"
const val SCANS_VERSION_NUMBER = "version_number"
const val SCANS_VERSION = "version"
const val SCANS_DATA_MASK = "data_mask"
const val SCANS_SYMBOL_WIDTH = "symbol_width"
const val SCANS_SYMBOL_HEIGHT = "symbol_height"
const val SCANS_SYMBOL_DATA = "symbol_data"
const val SCANS_ISSUE_NUMBER = "issue_number"
const val SCANS_ORIENTATION = "orientation"
const val SCANS_OTHER_META_DATA = "other_meta_data"
@@ -309,11 +335,15 @@ class Database {
$SCANS_ID INTEGER PRIMARY KEY AUTOINCREMENT,
$SCANS_DATETIME DATETIME NOT NULL,
$SCANS_NAME TEXT,
$SCANS_CONTENT TEXT NOT NULL,
$SCANS_TEXT TEXT NOT NULL,
$SCANS_RAW BLOB,
$SCANS_FORMAT TEXT NOT NULL,
$SCANS_ERROR_CORRECTION_LEVEL TEXT,
$SCANS_VERSION TEXT,
$SCANS_DATA_MASK INTEGER,
$SCANS_SYMBOL_WIDTH INTEGER,
$SCANS_SYMBOL_HEIGHT INTEGER,
$SCANS_SYMBOL_DATA BLOB,
$SCANS_SEQUENCE_SIZE INTEGER,
$SCANS_SEQUENCE_INDEX INTEGER,
$SCANS_SEQUENCE_ID TEXT,
@@ -341,7 +371,7 @@ class Database {
}
private fun SQLiteDatabase.addNameColumn() {
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_NAME TEXT".trimMargin())
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_NAME TEXT")
}
private fun SQLiteDatabase.migrateToZxingCpp() {
@@ -365,5 +395,16 @@ class Database {
execSQL("ALTER TABLE $SCANS ADD $SCANS_VERSION TEXT")
execSQL("UPDATE $SCANS SET $SCANS_VERSION = $SCANS_VERSION_NUMBER")
}
private fun SQLiteDatabase.addDataMaskColumn() {
execSQL("ALTER TABLE $SCANS ADD $SCANS_DATA_MASK INTEGER")
execSQL("UPDATE $SCANS SET $SCANS_DATA_MASK = -1")
}
private fun SQLiteDatabase.addSymbolColumns() {
execSQL("ALTER TABLE $SCANS ADD $SCANS_SYMBOL_WIDTH INTEGER")
execSQL("ALTER TABLE $SCANS ADD $SCANS_SYMBOL_HEIGHT INTEGER")
execSQL("ALTER TABLE $SCANS ADD $SCANS_SYMBOL_DATA BLOB")
}
}
}
@@ -25,7 +25,7 @@ fun Cursor.exportJson(): String? {
Database.SCANS_DATETIME,
Database.SCANS_FORMAT,
Database.SCANS_NAME,
Database.SCANS_CONTENT,
Database.SCANS_TEXT,
Database.SCANS_ERROR_CORRECTION_LEVEL,
Database.SCANS_VERSION,
Database.SCANS_SEQUENCE_SIZE,
@@ -39,7 +39,7 @@ fun Cursor.exportJson(): String? {
val indices = columns.map {
Pair(getColumnIndex(it), it)
}
val contentIndex = getColumnIndex(Database.SCANS_CONTENT)
val contentIndex = getColumnIndex(Database.SCANS_TEXT)
val rawIndex = getColumnIndex(Database.SCANS_RAW)
val root = JSONArray()
do {
@@ -1,21 +1,23 @@
package de.markusfisch.android.binaryeye.database
import android.graphics.Bitmap
import android.os.Build
import android.os.Parcel
import android.os.Parcelable
import android.text.format.DateFormat
import de.markusfisch.android.zxingcpp.ZxingCpp
import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
import de.markusfisch.android.zxingcpp.ZxingCpp.BitMatrix
import de.markusfisch.android.zxingcpp.ZxingCpp.ContentType
import de.markusfisch.android.zxingcpp.ZxingCpp.Result
import java.util.Locale
data class Scan(
val content: String,
val text: String,
val raw: ByteArray?,
val format: BarcodeFormat,
val errorCorrectionLevel: String? = null,
val version: String? = null,
val dataMask: Int = -1,
val symbol: BitMatrix? = null,
val sequenceSize: Int = -1,
val sequenceIndex: Int = -1,
val sequenceId: String = "",
@@ -41,12 +43,13 @@ data class Scan(
return id == other.id &&
dateTime == other.dateTime &&
content == other.content &&
text == other.text &&
((raw == null && other.raw == null) ||
(raw != null && other.raw != null && raw.contentEquals(other.raw))) &&
format == other.format &&
errorCorrectionLevel == other.errorCorrectionLevel &&
version == other.version &&
dataMask == other.dataMask &&
sequenceSize == other.sequenceSize &&
sequenceIndex == other.sequenceIndex &&
sequenceId == other.sequenceId &&
@@ -61,11 +64,12 @@ data class Scan(
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + dateTime.hashCode()
result = 31 * result + content.hashCode()
result = 31 * result + text.hashCode()
result = 31 * result + (raw?.contentHashCode() ?: 0)
result = 31 * result + format.hashCode()
result = 31 * result + (errorCorrectionLevel?.hashCode() ?: 0)
result = 31 * result + version.hashCode()
result = 31 * result + dataMask
result = 31 * result + sequenceSize
result = 31 * result + sequenceIndex
result = 31 * result + sequenceId.hashCode()
@@ -77,11 +81,13 @@ data class Scan(
}
private constructor(parcel: Parcel) : this(
content = parcel.readString() ?: "",
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() ?: "",
@@ -96,11 +102,13 @@ data class Scan(
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.apply {
writeString(content)
writeString(text)
writeSizedByteArray(raw)
writeString(format.name)
writeString(errorCorrectionLevel)
writeString(version)
writeInt(dataMask)
writeBitMatrix(symbol)
writeInt(sequenceSize)
writeInt(sequenceIndex)
writeString(sequenceId)
@@ -132,12 +140,14 @@ fun Result.toScan(): Scan {
ContentType.ISO15434,
ContentType.TEXT -> text
else -> ""
else -> "" // Show as binary.
},
rawBytes,
format,
ecLevel,
version,
dataMask,
symbol,
sequenceSize,
sequenceIndex,
sequenceId,
@@ -148,37 +158,6 @@ fun Result.toScan(): Scan {
)
}
data class Recreation(
val format: BarcodeFormat,
val ecLevel: Int,
val size: Int,
val margin: Int
) {
fun <T> encode(content: T): Bitmap? = try {
ZxingCpp.encodeAsBitmap(
content, format, size, size, margin, ecLevel
)
} catch (_: RuntimeException) {
null
}
}
fun Scan.toRecreation(
size: Int = 128,
margin: Int = -1
) = Recreation(
format,
when (errorCorrectionLevel) {
"L" -> 0
"M" -> 4
"Q" -> 6
"H" -> 8
else -> -1
},
size,
margin
)
private fun getDateTime(
time: Long = System.currentTimeMillis()
) = DateFormat.format(
@@ -190,7 +169,11 @@ private fun getDateTime(
"yyyy-MM-dd HH:mm:ss"
},
time
).toString()
).toString() + String.format(
Locale.getDefault(),
":%03d",
time % 1000
)
private fun Parcel.writeSizedByteArray(array: ByteArray?) {
val size = array?.size ?: 0
@@ -210,3 +193,21 @@ private fun Parcel.readSizedByteArray(): ByteArray? {
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) {
return null
}
val height = readInt()
val data = readSizedByteArray() ?: return null
return BitMatrix(width, height, data)
}
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Matrix
import android.os.Build
import android.os.Bundle
import android.support.v4.app.Fragment
@@ -14,16 +15,21 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.TextView
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.db
import de.markusfisch.android.binaryeye.app.hasWritePermission
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.content.Barcode
import de.markusfisch.android.binaryeye.content.BarcodeColors
import de.markusfisch.android.binaryeye.content.BitMatrixBarcode
import de.markusfisch.android.binaryeye.content.ContentBarcode
import de.markusfisch.android.binaryeye.content.copyToClipboard
import de.markusfisch.android.binaryeye.content.shareFile
import de.markusfisch.android.binaryeye.content.shareText
import de.markusfisch.android.binaryeye.database.toScan
import de.markusfisch.android.binaryeye.graphics.COLOR_BLACK
import de.markusfisch.android.binaryeye.graphics.COLOR_WHITE
import de.markusfisch.android.binaryeye.io.addSuffixIfNotGiven
import de.markusfisch.android.binaryeye.io.toSaveResult
import de.markusfisch.android.binaryeye.io.writeExternalFile
@@ -45,6 +51,7 @@ import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
import java.util.Locale
import kotlin.math.max
import kotlin.math.min
class BarcodeFragment : Fragment() {
@@ -55,11 +62,12 @@ class BarcodeFragment : Fragment() {
private val parentJob = Job()
private val scope = CoroutineScope(Dispatchers.IO + parentJob)
private lateinit var imageView: ConfinedScalingImageView
private lateinit var barcode: Barcode<*>
private lateinit var addToHistoryItem: MenuItem
private lateinit var brightenScreenItem: MenuItem
private var currentBrightness = -1f;
private var currentBrightness = -1f
override fun onCreate(state: Bundle?) {
super.onCreate(state)
@@ -80,6 +88,9 @@ class BarcodeFragment : Fragment() {
false
)
// Make `imageView` available for `onPause()`.
imageView = view.findViewById(R.id.barcode)
val bitmap: Bitmap
try {
barcode = arguments?.toBarcode() ?: throw IllegalArgumentException(
@@ -99,15 +110,20 @@ class BarcodeFragment : Fragment() {
return null
}
val imageView = view.findViewById<ConfinedScalingImageView>(
R.id.barcode
)
imageView.setImageBitmap(bitmap)
imageView.post {
// Make sure to invoke this after ScalingImageView.onLayout().
imageView.runAfterLayout = {
val scale = prefs.previewScale
if (scale > 0) {
imageView.setScale(
scale,
bitmap.width / 2f,
bitmap.height / 2f
)
}
imageView.minWidth = min(
imageView.minWidth / 2f,
barcode.size.toFloat()
max(bitmap.width, bitmap.height).toFloat()
)
}
@@ -119,28 +135,47 @@ class BarcodeFragment : Fragment() {
}
}
(view.findViewById(R.id.inset_layout) as View).setPaddingFromWindowInsets()
imageView.doOnApplyWindowInsets { v, insets ->
(v as ConfinedScalingImageView).insets.set(insets)
view.findViewById<View>(R.id.inset_layout).setPaddingFromWindowInsets()
imageView.doOnApplyWindowInsets { _, insets ->
imageView.insets.set(insets)
}
return view
}
private fun Bundle.toBarcode() = Barcode(
getString(CONTENT_TEXT) ?: getByteArray(CONTENT_RAW) ?: throw IllegalArgumentException(
"content cannot be null"
),
BarcodeFormat.valueOf(
private fun Bundle.toBarcode(): Barcode<*> {
val content =
getString(CONTENT_TEXT) ?: getByteArray(CONTENT_RAW) ?: throw IllegalArgumentException(
"content cannot be null"
)
val barcodeFormat = BarcodeFormat.valueOf(
getString(FORMAT) ?: throw IllegalArgumentException(
"format cannot be null"
)
),
getInt(SIZE),
getInt(MARGIN),
getInt(EC_LEVEL),
Colors.entries[getInt(COLORS)]
)
)
val colors = BarcodeColors.entries[getInt(COLORS)]
val data = getByteArray(BIT_MATRIX_DATA)
return if (data != null) {
BitMatrixBarcode(
ZxingCpp.BitMatrix(
getInt(BIT_MATRIX_WIDTH),
getInt(BIT_MATRIX_HEIGHT),
data
),
content,
barcodeFormat,
colors
)
} else {
ContentBarcode(
content,
barcodeFormat,
getInt(EC_LEVEL),
getInt(MARGIN),
colors
)
}
}
override fun onResume() {
super.onResume()
@@ -157,6 +192,9 @@ class BarcodeFragment : Fragment() {
if (currentBrightness > -1f) {
restoreScreenBrightness()
}
if (imageView.isInBounds()) {
prefs.previewScale = imageView.getScale()
}
}
override fun onDestroyView() {
@@ -173,7 +211,10 @@ class BarcodeFragment : Fragment() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.add_to_history -> {
readAndAddToHistory(barcode.bitmap(), barcode.format)
readAndAddToHistory(
barcode.bitmap(),
barcode.format
)
addToHistoryItem.isVisible = false
context.toast(R.string.added_to_history)
true
@@ -188,8 +229,15 @@ class BarcodeFragment : Fragment() {
}
R.id.export_to_file -> {
context.pickFileType(R.string.export_as) {
askForFileNameAndSave(it)
context.pickFileType(R.string.export_as) { fileType ->
when (fileType) {
FileType.PNG,
FileType.JPG -> askForSize { size ->
askForFileNameAndSave(fileType, size)
}
else -> askForFileNameAndSave(fileType, 0)
}
}
true
}
@@ -224,11 +272,13 @@ class BarcodeFragment : Fragment() {
// Dialogs do not have a parent view.
@SuppressLint("InflateParams")
private fun askForFileNameAndSave(fileType: FileType) {
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 { askForFileNameAndSave(fileType) }
!ac.hasWritePermission {
askForFileNameAndSave(fileType, bitmapSize)
}
) {
return
}
@@ -246,28 +296,28 @@ class BarcodeFragment : Fragment() {
addSuffixIfNotGiven(fileName, ".png"),
MIME_PNG
) {
barcode.bitmap().saveAsPng(it)
barcode.bitmap(bitmapSize).saveAsPng(it)
}
FileType.JPG -> saveAs(
addSuffixIfNotGiven(fileName, ".jpg"),
MIME_JPG
) {
barcode.bitmap().saveAsJpg(it)
barcode.bitmap(bitmapSize).saveAsJpg(it)
}
FileType.SVG -> saveAs(
addSuffixIfNotGiven(fileName, ".svg"),
MIME_SVG
) { outputStream ->
outputStream.write(barcode.svg().toByteArray())
) {
it.write(barcode.svg().toByteArray())
}
FileType.TXT -> saveAs(
addSuffixIfNotGiven(fileName, ".txt"),
MIME_TXT
) { outputStream ->
outputStream.write(barcode.text().toByteArray())
) {
it.write(barcode.text().toByteArray())
}
}
}
@@ -276,6 +326,52 @@ class BarcodeFragment : Fragment() {
.show()
}
// 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 sizeView = view.findViewById<TextView>(R.id.size_display)
val sizeBarView = view.findViewById<SeekBar>(R.id.size_bar)
sizeBarView.initSizeBar(sizeView)
AlertDialog.Builder(ac)
.setView(view)
.setPositiveButton(android.R.string.ok) { _, _ ->
write(getSize(sizeBarView.progress))
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
}
.show()
}
private fun SeekBar.initSizeBar(sizeView: TextView) {
sizeView.updateSize(progress)
setOnSeekBarChangeListener(
object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(
seekBar: SeekBar,
progressValue: Int,
fromUser: Boolean
) {
sizeView.updateSize(progressValue)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
}
)
}
private fun TextView.updateSize(power: Int) {
val size = getSize(power)
text = if (size > 0) {
getString(R.string.size_width_by_height, size, size)
} else {
getString(R.string.size_no_magnification)
}
}
private fun saveAs(
fileName: String,
mimeType: String,
@@ -292,8 +388,14 @@ class BarcodeFragment : Fragment() {
private fun Context.shareAs(fileType: FileType) {
when (fileType) {
FileType.PNG -> share(barcode.bitmap(), MIME_PNG, "png")
FileType.JPG -> share(barcode.bitmap(), MIME_JPG, "jpg")
FileType.PNG -> askForSize {
share(barcode.bitmap(it), MIME_PNG, "png")
}
FileType.JPG -> askForSize {
share(barcode.bitmap(it), MIME_JPG, "jpg")
}
FileType.SVG -> shareText(barcode.svg(), MIME_SVG)
FileType.TXT -> shareText(barcode.text())
}
@@ -332,48 +434,90 @@ class BarcodeFragment : Fragment() {
private fun brightenScreen() {
activity?.let {
currentBrightness = it.getScreenBrightness()
it.setScreenBrightness(1f);
it.setScreenBrightness(1f)
brightenScreenItem.isChecked = true
}
}
private fun restoreScreenBrightness() {
if (currentBrightness > -1f) {
activity?.setScreenBrightness(currentBrightness);
activity?.setScreenBrightness(currentBrightness)
currentBrightness = -1f
brightenScreenItem.isChecked = false
}
}
companion object {
private const val BIT_MATRIX_WIDTH = "bit_matrix_width"
private const val BIT_MATRIX_HEIGHT = "bit_matrix_height"
private const val BIT_MATRIX_DATA = "bit_matrix_data"
private const val CONTENT_TEXT = "content_text"
private const val CONTENT_RAW = "content_raw"
private const val FORMAT = "format"
private const val SIZE = "size"
private const val MARGIN = "margin"
private const val EC_LEVEL = "ec_level"
private const val MARGIN = "margin"
private const val COLORS = "colors"
private const val MIME_PNG = "image/png"
private const val MIME_JPG = "image/jpeg"
private const val MIME_SVG = "image/svg+xmg"
private const val MIME_TXT = "text/plain"
fun <T> newInstance(
content: T,
format: BarcodeFormat,
size: Int,
margin: Int,
ecLevel: Int = -1,
fun newInstance(
barcode: Barcode<*>,
colors: Int = 0
): Fragment {
val args = Bundle()
when (barcode) {
is ContentBarcode -> args.putEcLevelMargin(
barcode.ecLevel,
barcode.margin
)
is BitMatrixBarcode -> {
args.putInt(BIT_MATRIX_WIDTH, barcode.bitMatrix.width)
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
}
fun <T> newInstance(
content: T,
format: BarcodeFormat,
ecLevel: Int = -1,
margin: Int = -1,
colors: Int = 0
): Fragment {
val args = Bundle()
args.putContentFormatColors(content, format, colors)
args.putEcLevelMargin(ecLevel, margin)
val fragment = BarcodeFragment()
fragment.arguments = args
return fragment
}
private fun <T> Bundle.putContentFormatColors(
content: T,
format: BarcodeFormat,
colors: Int
) {
when (content) {
is String -> {
args.putString(CONTENT_TEXT, content)
putString(CONTENT_TEXT, content)
}
is ByteArray -> {
args.putByteArray(CONTENT_RAW, content)
putByteArray(CONTENT_RAW, content)
}
else -> {
@@ -382,77 +526,32 @@ class BarcodeFragment : Fragment() {
)
}
}
args.putString(FORMAT, format.name)
args.putInt(SIZE, size)
args.putInt(MARGIN, margin)
args.putInt(EC_LEVEL, ecLevel)
args.putInt(COLORS, colors)
val fragment = BarcodeFragment()
fragment.arguments = args
return fragment
putString(FORMAT, format.name)
putInt(COLORS, colors)
}
private fun Bundle.putEcLevelMargin(
ecLevel: Int,
margin: Int
) {
putInt(EC_LEVEL, ecLevel)
putInt(MARGIN, margin)
}
}
}
private data class Barcode<T>(
val content: T,
val format: BarcodeFormat,
val size: Int,
val margin: Int,
val ecLevel: Int,
val colors: Colors
) {
private var _bitmap: Bitmap? = null
fun bitmap(): Bitmap {
val b = _bitmap ?: ZxingCpp.encodeAsBitmap(
content, format, size, size, margin, ecLevel,
setColor = colors.foregroundColor(),
unsetColor = colors.backgroundColor()
)
_bitmap = b
return b
}
private var _svg: String? = null
fun svg(): String {
val s = _svg ?: ZxingCpp.encodeAsSvg(
content, format, margin, ecLevel
)
_svg = s
return s
}
private var _text: String? = null
fun text(): String {
val t = _text ?: ZxingCpp.encodeAsText(
content, format, margin, ecLevel,
inverted = colors == Colors.BLACK_ON_WHITE
)
_text = t
return t
private fun ImageView.setScale(scale: Float, x: Float, y: Float) {
imageMatrix = Matrix().apply {
setTranslate(-x, -y)
postScale(scale, scale)
postTranslate(x, y)
}
}
private enum class Colors {
BLACK_ON_WHITE,
WHITE_ON_BLACK,
BLACK_ON_TRANSPARENT,
WHITE_ON_TRANSPARENT;
fun foregroundColor(): Int = when (this) {
BLACK_ON_WHITE,
BLACK_ON_TRANSPARENT -> COLOR_BLACK
WHITE_ON_BLACK,
WHITE_ON_TRANSPARENT -> COLOR_WHITE
}
fun backgroundColor(): Int = when (this) {
BLACK_ON_WHITE -> COLOR_WHITE
WHITE_ON_BLACK -> COLOR_BLACK
BLACK_ON_TRANSPARENT,
WHITE_ON_TRANSPARENT -> 0
}
private fun ImageView.getScale(): Float {
val values = FloatArray(9)
imageMatrix.getValues(values)
return values[Matrix.MSCALE_X]
}
private fun Bitmap.saveAsPng(outputStream: OutputStream, quality: Int = 90) =
@@ -468,6 +567,11 @@ private fun encodeFileName(name: String): String = fileNameCharacters
.trim('_')
.lowercase(Locale.getDefault())
private fun getSize(step: Int) = when (step) {
0 -> 0
else -> 128 shl (step - 1)
}
private fun readAndAddToHistory(
bitmap: Bitmap,
format: BarcodeFormat
@@ -24,7 +24,6 @@ import android.widget.TableRow
import android.widget.TextView
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.ActionRegistry
import de.markusfisch.android.binaryeye.actions.IAction
import de.markusfisch.android.binaryeye.actions.wifi.WifiAction
import de.markusfisch.android.binaryeye.actions.wifi.WifiConnector
import de.markusfisch.android.binaryeye.activity.MainActivity
@@ -34,19 +33,21 @@ import de.markusfisch.android.binaryeye.app.db
import de.markusfisch.android.binaryeye.app.hasLocationPermission
import de.markusfisch.android.binaryeye.app.hasWritePermission
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.content.ContentBarcode
import de.markusfisch.android.binaryeye.content.copyToClipboard
import de.markusfisch.android.binaryeye.content.shareAsFile
import de.markusfisch.android.binaryeye.content.shareText
import de.markusfisch.android.binaryeye.content.toBarcode
import de.markusfisch.android.binaryeye.content.toErrorCorrectionInt
import de.markusfisch.android.binaryeye.content.toHexString
import de.markusfisch.android.binaryeye.content.wipeLastShareFile
import de.markusfisch.android.binaryeye.database.Recreation
import de.markusfisch.android.binaryeye.database.Scan
import de.markusfisch.android.binaryeye.database.toRecreation
import de.markusfisch.android.binaryeye.io.askForFileName
import de.markusfisch.android.binaryeye.io.toSaveResult
import de.markusfisch.android.binaryeye.io.writeExternalFile
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
import de.markusfisch.android.binaryeye.widget.toast
import de.markusfisch.android.zxingcpp.ZxingCpp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -65,6 +66,7 @@ class DecodeFragment : Fragment() {
private lateinit var recreationView: ImageView
private lateinit var labelView: EditText
private lateinit var fab: FloatingActionButton
private lateinit var scan: Scan
private lateinit var format: String
private val parentJob = Job()
@@ -79,8 +81,8 @@ class DecodeFragment : Fragment() {
private var isBinary = false
private var originalBytes: ByteArray = ByteArray(0)
private var id = 0L
private var recreation: Recreation? = null
private var label: String? = null
private var recreationSize = 0
override fun onCreate(state: Bundle?) {
super.onCreate(state)
@@ -103,18 +105,18 @@ class DecodeFragment : Fragment() {
closeAutomatically = prefs.closeAutomatically &&
activity?.intent?.hasExtra(MainActivity.DECODED) == true
val scan = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
scan = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
arguments?.getParcelable(SCAN, Scan::class.java)
} else {
@Suppress("DEPRECATION")
arguments?.getParcelable(SCAN) as Scan?
} ?: throw IllegalArgumentException("DecodeFragment needs a Scan")
val originalContent = scan.content
isBinary = scan.content.isEmpty()
originalBytes = scan.raw ?: originalContent.toByteArray()
isBinary = scan.text.isEmpty()
originalBytes = scan.raw ?: scan.text.toByteArray()
format = scan.format.name
id = scan.id
recreationSize = (200f * dp).roundToInt()
contentView = view.findViewById(R.id.content)
formatView = view.findViewById(R.id.format)
@@ -126,18 +128,13 @@ class DecodeFragment : Fragment() {
labelView = view.findViewById(R.id.label)
fab = view.findViewById(R.id.open)
initContentAndFab(originalContent)
initContentAndFab()
if (prefs.showMetaData) {
metaView.fillMetaView(scan)
} else {
metaView.visibility = View.GONE
}
if (prefs.showRecreation) {
recreation = scan.toRecreation(
(200f * dp).roundToInt()
)
}
if (id > 0) {
scan.label?.let {
labelView.setText(it)
@@ -147,10 +144,10 @@ class DecodeFragment : Fragment() {
labelView.visibility = View.GONE
}
updateViewsAndFab(originalContent, originalBytes)
updateViewsAndFab(scan.text, originalBytes)
(view.findViewById(R.id.inset_layout) as View).setPaddingFromWindowInsets()
(view.findViewById(R.id.scroll_view) as View).setPaddingFromWindowInsets()
view.findViewById<View>(R.id.inset_layout).setPaddingFromWindowInsets()
view.findViewById<View>(R.id.scroll_view).setPaddingFromWindowInsets()
return view
}
@@ -172,7 +169,7 @@ class DecodeFragment : Fragment() {
wipeLastShareFile()
}
private fun initContentAndFab(originalContent: String) {
private fun initContentAndFab() {
if (isBinary) {
contentView.setText(String(originalBytes).foldNonAlNum())
contentView.isEnabled = false
@@ -181,7 +178,7 @@ class DecodeFragment : Fragment() {
askForFileNameAndSave(originalBytes)
}
} else {
contentView.setText(originalContent)
contentView.setText(scan.text)
contentView.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
updateViewsAndFab(s?.toString() ?: "")
@@ -202,10 +199,11 @@ class DecodeFragment : Fragment() {
) = Unit
})
fab.setOnClickListener {
executeAction(content)
executeAction(this.content)
}
if (prefs.openImmediately) {
executeAction(content)
executeAction(this.content)
backOrFinish()
}
}
}
@@ -222,12 +220,9 @@ class DecodeFragment : Fragment() {
action = ActionRegistry.getAction(bytes)
}
if (prevAction !== action) {
updateFab(action)
fab.setImageResource(action.iconResId)
}
}
private fun updateFab(action: IAction) {
fab.setImageResource(action.iconResId)
// Run this for the initial action too.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
fab.setOnLongClickListener { v ->
v.context.toast(action.titleResId)
@@ -249,25 +244,53 @@ class DecodeFragment : Fragment() {
v.text = hexDump(bytes)
}
recreationView.showIf(prefs.showRecreation) { v ->
val r = recreation ?: return@showIf
val content = if (isBinary) bytes else text
v.setImageBitmap(r.encode(content))
v.setOnClickListener {
fragmentManager?.addFragment(
BarcodeFragment.newInstance(
content,
r.format,
r.size,
r.margin,
r.ecLevel
)
val unmodified: Boolean
val content = if (isBinary) {
if (bytes.isEmpty()) {
clearRecreation()
return@showIf
}
unmodified = bytes.contentEquals(originalBytes)
bytes
} else {
if (text.isEmpty()) {
clearRecreation()
return@showIf
}
unmodified = text == scan.text
text
}
val barcode = if (unmodified) {
scan.toBarcode()
} else {
ContentBarcode(
content,
scan.format,
scan.errorCorrectionLevel.toErrorCorrectionInt()
)
}
try {
v.setImageBitmap(barcode.bitmap(recreationSize))
v.setOnClickListener {
fragmentManager?.addFragment(
BarcodeFragment.newInstance(barcode)
)
}
} catch (e: RuntimeException) {
clearRecreation()
}
}
dataView.fillDataView(text, bytes)
stampView.setTrackingLink(bytes, format)
}
private fun clearRecreation() {
recreationView.apply {
setImageBitmap(null)
setOnClickListener(null)
}
}
private fun TableLayout.fillDataView(text: String, bytes: ByteArray) {
val items = LinkedHashMap<Int, CharSequence?>()
when (prefs.showChecksum) {
@@ -324,6 +347,15 @@ class DecodeFragment : Fragment() {
)
)
}
if (scan.format == ZxingCpp.BarcodeFormat.QR_CODE &&
scan.dataMask > -1
) {
items.putAll(
linkedMapOf(
R.string.qr_data_mask to scan.dataMask.toString()
)
)
}
fill(items)
}
@@ -523,7 +555,7 @@ private inline fun <T : View> T.showIf(
}
private val nonAlNum = "[^a-zA-Z0-9]".toRegex()
private val multipleDots = "[…]+".toRegex()
private val multipleDots = "+".toRegex()
private fun String.foldNonAlNum() = replace(nonAlNum, "")
.replace(multipleDots, "")
@@ -619,7 +651,7 @@ private fun generateDpTrackingLink(bytes: ByteArray, format: String): String? {
"%X",
crc4(hexString.toByteArray(Charsets.ISO_8859_1))
)
return "<a href=\"https://www.deutschepost.de/de/s/sendungsverfolgung/verfolgen.html?piececode=$trackingNumber\">Deutsche Post: $trackingNumber</a>"
return "<a href=\"https://www.deutschepost.de/de/s/sendungsverfolgung.html?piececode=$trackingNumber\">Deutsche Post: $trackingNumber</a>"
}
// CRC-4 with polynomial x^4 + x + 1.
@@ -3,9 +3,9 @@ package de.markusfisch.android.binaryeye.fragment
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Build
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
@@ -16,7 +16,6 @@ import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.CheckBox
import android.widget.EditText
import android.widget.SeekBar
import android.widget.Spinner
import android.widget.TextView
import de.markusfisch.android.binaryeye.R
@@ -29,7 +28,6 @@ import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
import de.markusfisch.android.binaryeye.widget.toast
import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
import java.io.InputStream
import kotlin.math.max
import kotlin.math.min
class EncodeFragment : Fragment() {
@@ -38,11 +36,7 @@ class EncodeFragment : Fragment() {
private lateinit var ecSpinner: Spinner
private lateinit var colorsLabel: TextView
private lateinit var colorsSpinner: Spinner
private lateinit var sizeView: TextView
private lateinit var sizeBarView: SeekBar
private lateinit var marginLayout: View
private lateinit var marginView: TextView
private lateinit var marginBarView: SeekBar
private lateinit var addQuietZoneSwitch: SwitchCompat
private lateinit var contentView: EditText
private lateinit var unescapeCheckBox: CheckBox
@@ -145,12 +139,13 @@ class EncodeFragment : Fragment() {
colorsLabel, colorsSpinner
)
when (format) {
BarcodeFormat.AZTEC -> setMarginBar(4, 4)
BarcodeFormat.DATA_MATRIX -> setMarginBar(1, 1)
BarcodeFormat.QR_CODE -> setMarginBar(4, 4)
BarcodeFormat.PDF_417 -> setMarginBar(0, 30)
BarcodeFormat.AZTEC,
BarcodeFormat.DATA_MATRIX,
BarcodeFormat.QR_CODE,
BarcodeFormat.PDF_417 -> true
else -> false
}.setVisibilityFor(marginLayout)
}.setVisibilityFor(addQuietZoneSwitch)
}
override fun onNothingSelected(parentView: AdapterView<*>?) {}
@@ -177,15 +172,7 @@ class EncodeFragment : Fragment() {
colorsLabel = view.findViewById(R.id.colors_label)
colorsSpinner = view.findViewById(R.id.colors)
sizeView = view.findViewById(R.id.size_display)
sizeBarView = view.findViewById(R.id.size_bar)
initSizeBar()
marginLayout = view.findViewById(R.id.margin)
marginView = view.findViewById(R.id.margin_display)
marginBarView = view.findViewById(R.id.margin_bar)
initMarginBar()
addQuietZoneSwitch = view.findViewById(R.id.add_quiet_zone)
contentView = view.findViewById(R.id.content)
unescapeCheckBox = view.findViewById(R.id.unescape)
@@ -215,8 +202,8 @@ class EncodeFragment : Fragment() {
it.context.encode()
}
(view.findViewById(R.id.inset_layout) as View).setPaddingFromWindowInsets()
(view.findViewById(R.id.scroll_view) as View).setPaddingFromWindowInsets()
view.findViewById<View>(R.id.inset_layout).setPaddingFromWindowInsets()
view.findViewById<View>(R.id.scroll_view).setPaddingFromWindowInsets()
return view
}
@@ -248,7 +235,6 @@ class EncodeFragment : Fragment() {
super.onPause()
prefs.indexOfLastSelectedFormat = formatView.selectedItemPosition
prefs.expandEscapeSequences = unescapeCheckBox.isChecked
prefs.lastMargin = marginBarView.progress
}
private fun Context.encode() {
@@ -259,16 +245,17 @@ class EncodeFragment : Fragment() {
BarcodeFragment.newInstance(
content,
format,
getSize(sizeBarView.progress),
format.getErrorCorrectionLevel(ecSpinner.selectedItemPosition),
when (format) {
BarcodeFormat.AZTEC,
BarcodeFormat.DATA_MATRIX,
BarcodeFormat.QR_CODE,
BarcodeFormat.PDF_417 -> marginBarView.progress
BarcodeFormat.PDF_417 -> if (
addQuietZoneSwitch.isChecked
) 1 else 0
else -> -1
},
format.getErrorCorrectionLevel(ecSpinner.selectedItemPosition),
if (format.canBeInverted()) {
colorsSpinner.selectedItemPosition
} else 0
@@ -281,90 +268,27 @@ class EncodeFragment : Fragment() {
return bytes
}
var text = contentView.text.toString()
if (unescapeCheckBox.isChecked) {
try {
text = text.unescape()
} catch (e: IllegalArgumentException) {
toast(e.message ?: "Invalid escape sequence")
return null
}
// Return a ByteArray if there were escape sequences for
// non-printable characters (like `\0`). This means the content
// will be encoded in binary mode, what would be wrong for
// "something\nlike\tthüs".
if (text.any { it.code < 32 && it.code !in setOf(9, 10, 13) }) {
return text.toByteArray()
}
}
if (text.isEmpty()) {
toast(R.string.error_no_content)
return null
}
return text
}
private fun initSizeBar() {
updateSize(sizeBarView.progress)
sizeBarView.setOnSeekBarChangeListener(
object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(
seekBar: SeekBar,
progressValue: Int,
fromUser: Boolean
) {
updateSize(progressValue)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
})
}
private fun updateSize(power: Int) {
val size = getSize(power)
sizeView.text = getString(R.string.size_width_by_height, size, size)
}
private fun initMarginBar() {
updateMargin(marginBarView.progress)
marginBarView.setOnSeekBarChangeListener(
object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(
seekBar: SeekBar,
progressValue: Int,
fromUser: Boolean
) {
if (progressValue >= minMargin) {
updateMargin(progressValue)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
})
}
private fun updateMargin(margin: Int) {
marginView.text = getString(R.string.margin_size, margin)
}
private fun setMarginBar(minimum: Int, value: Int): Boolean {
minMargin = minimum
marginBarView.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
min = minimum
}
progress = max(
minimum, if (prefs.lastMargin > -1) {
prefs.lastMargin
} else {
value
}
)
if (!unescapeCheckBox.isChecked) {
return text
}
try {
text = text.unescape()
} catch (e: IllegalArgumentException) {
toast(e.message ?: "Invalid escape sequence")
return null
}
// Return a ByteArray if there were escape sequences for
// non-printable characters.
return if (text.any { it.code < 32 && it.code !in setOf(9, 10, 13) }) {
// Do not expand UTF-8 sequences in binary data.
text.toByteArray(Charsets.ISO_8859_1)
} else {
text
}
return true
}
private fun setEncodeByteArray() {
@@ -456,8 +380,6 @@ private fun Spinner.setEntries(resId: Int) = ArrayAdapter.createFromResource(
adapter = aa
}
private fun getSize(power: Int) = 128 * (power + 1)
private fun InputStream.readBytesMax(max: Int): ByteArray {
var offset = 0
var remaining = min(available(), max)
@@ -70,9 +70,13 @@ class HistoryFragment : Fragment() {
R.menu.fragment_history_edit,
menu
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
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
) {
lockStatusBarColor()
val ac = activity ?: return false
@Suppress("DEPRECATION")
ac.window.statusBarColor = ContextCompat.getColor(
ac,
R.color.accent_dark
@@ -163,7 +167,7 @@ class HistoryFragment : Fragment() {
useHistorySwitch = view.findViewById(
R.id.use_history
) as SwitchCompat
)
initHistorySwitch(useHistorySwitch)
listView = view.findViewById(R.id.scans)
@@ -192,7 +196,7 @@ class HistoryFragment : Fragment() {
progressView = view.findViewById(R.id.progress_view)
(view.findViewById(R.id.inset_layout) as View).setPaddingFromWindowInsets()
view.findViewById<View>(R.id.inset_layout).setPaddingFromWindowInsets()
listView.setPaddingFromWindowInsets()
update()
@@ -297,7 +301,7 @@ class HistoryFragment : Fragment() {
val cursor = db.getScans(filter)
withContext(Dispatchers.Main) {
val ac = activity ?: return@withContext
val hasScans = cursor != null && cursor.count > 0
val hasScans = cursor.count > 0
if (filter == null) {
if (!hasScans) {
listView.emptyView = useHistorySwitch
@@ -310,7 +314,7 @@ class HistoryFragment : Fragment() {
} else {
View.GONE
}
cursor?.let { cursor ->
cursor.let { cursor ->
// Close previous cursor.
scansAdapter?.also { it.changeCursor(null) }
scansAdapter = ScansAdapter(ac, cursor)
@@ -442,12 +446,12 @@ class HistoryFragment : Fragment() {
} ?: return@useVisibility
val message = when (delimiter) {
"db" -> ac.exportDatabase(name)
else -> db.getScansDetailed(filter)?.use {
else -> db.getScansDetailed(filter).use {
when (delimiter) {
"json" -> ac.exportJson(name, it)
else -> ac.exportCsv(name, it, delimiter)
}
} ?: false
}
}.toSaveResult()
withContext(Dispatchers.Main) {
ac.toast(message)
@@ -475,14 +479,14 @@ class HistoryFragment : Fragment() {
db.getScansDetailed(selectedIds.toLongArray())
} else {
db.getScansDetailed(filter)
}?.use { cursor ->
}.use { cursor ->
val details = format.split(":")
when (details[0]) {
"text" -> Pair(cursor.exportText(details[1]), "txt")
"csv" -> Pair(cursor.exportCsv(details[1]), "csv")
else -> Pair(cursor.exportJson(), "json")
}
}?.let { (text, ext) ->
}.let { (text, ext) ->
text?.let {
withContext(Dispatchers.Main) {
if (asFile) {
@@ -502,7 +506,7 @@ class HistoryFragment : Fragment() {
private fun Cursor.exportText(separator: String): String {
val sb = StringBuilder()
val contentIndex = getColumnIndex(Database.SCANS_CONTENT)
val contentIndex = getColumnIndex(Database.SCANS_TEXT)
if (contentIndex > -1 && moveToFirst()) {
do {
val content = getString(contentIndex)
@@ -51,7 +51,7 @@ class NetworkSuggestionsFragment : Fragment() {
listView.emptyView = view.findViewById(R.id.no_suggestions)
listView.adapter = suggestionArrayAdapter
listView.setOnScrollListener(systemBarListViewScrollListener)
(view.findViewById(R.id.inset_layout) as View).setPaddingFromWindowInsets()
view.findViewById<View>(R.id.inset_layout).setPaddingFromWindowInsets()
listView.setPaddingFromWindowInsets()
view.findViewById<View>(R.id.remove).setOnClickListener {
@@ -5,11 +5,12 @@ import android.graphics.Canvas
fun Bitmap.fixTransparency(): Bitmap {
val result = analyzeTransparency()
return if (result.hasTransparentPixels) {
val cfg = config
return if (cfg != null && result.hasTransparentPixels) {
val copy = Bitmap.createBitmap(
width,
height,
config
cfg
)
Canvas(copy).apply {
drawColor(result.backgroundColor)
@@ -53,7 +53,7 @@ private fun Scan.send(url: String, type: String): Response {
}
else -> request(
url + content.urlEncode()
url + text.urlEncode()
)
}
}
@@ -67,7 +67,7 @@ private fun Scan.asJson() = JSONObject().apply {
}
private fun Scan.getMap(): Map<String, String> = mapOf(
"content" to content,
"content" to text,
"raw" to raw?.toHexString(),
"format" to format.name,
"errorCorrectionLevel" to errorCorrectionLevel,
@@ -0,0 +1,41 @@
package de.markusfisch.android.binaryeye.preference
import android.content.SharedPreferences
import org.json.JSONObject
data class CropHandle(
val x: Int = -2, // -2 means set default roi.
val y: Int = -2,
val orientation: Int = 0
)
fun SharedPreferences.storeCropHandle(
name: String,
cropHandle: CropHandle
) {
edit().putString(
name,
JSONObject().apply {
put("x", cropHandle.x)
put("y", cropHandle.y)
put("orientation", cropHandle.orientation)
}.toString()
).apply()
}
fun SharedPreferences.restoreCropHandle(
name: String,
default: CropHandle = CropHandle()
): CropHandle {
val s = getString(name, null) ?: return default
return try {
val json = JSONObject(s)
CropHandle(
json.getInt("x"),
json.getInt("y"),
json.getInt("orientation")
)
} catch (e: Exception) {
return default
}
}
@@ -7,8 +7,10 @@ import android.media.ToneGenerator
import android.os.Build
import android.preference.PreferenceManager
import android.support.annotation.RequiresApi
import de.markusfisch.android.binaryeye.activity.CameraActivity
import de.markusfisch.android.zxingcpp.ZxingCpp.BarcodeFormat
class Preferences {
lateinit var preferences: SharedPreferences
@@ -38,21 +40,6 @@ class Preferences {
apply(BARCODE_FORMATS, value)
field = value
}
var cropHandleX = -2 // -2 means set default roi.
set(value) {
apply(CROP_HANDLE_X, value)
field = value
}
var cropHandleY = -2
set(value) {
apply(CROP_HANDLE_Y, value)
field = value
}
var cropHandleOrientation = 0
set(value) {
apply(CROP_HANDLE_ORIENTATION, value)
field = value
}
var showCropHandle = true
set(value) {
apply(SHOW_CROP_HANDLE, value)
@@ -200,11 +187,6 @@ class Preferences {
apply(INDEX_OF_LAST_SELECTED_EC_LEVEL, value)
field = value
}
var lastMargin: Int = -1
set(value) {
apply(LAST_MARGIN, value)
field = value
}
var freeRotation = false
set(value) {
apply(FREE_ROTATION, value)
@@ -220,6 +202,11 @@ class Preferences {
apply(BRIGHTEN_SCREEN, value)
field = value
}
var previewScale = 0f
set(value) {
apply(PREVIEW_SCALE, value)
field = value
}
fun init(context: Context) {
preferences = PreferenceManager.getDefaultSharedPreferences(context)
@@ -237,12 +224,8 @@ class Preferences {
}
}
cropHandleX = preferences.getInt(CROP_HANDLE_X, cropHandleX)
cropHandleY = preferences.getInt(CROP_HANDLE_Y, cropHandleY)
cropHandleOrientation = preferences.getInt(
CROP_HANDLE_ORIENTATION,
cropHandleOrientation
)
migrateCropHandle()
showCropHandle = preferences.getBoolean(
SHOW_CROP_HANDLE,
showCropHandle
@@ -331,10 +314,6 @@ class Preferences {
INDEX_OF_LAST_SELECTED_EC_LEVEL,
indexOfLastSelectedEcLevel
)
lastMargin = preferences.getInt(
LAST_MARGIN,
lastMargin
)
freeRotation = preferences.getBoolean(FREE_ROTATION, freeRotation)
expandEscapeSequences = preferences.getBoolean(
EXPAND_ESCAPE_SEQUENCES,
@@ -344,6 +323,10 @@ class Preferences {
BRIGHTEN_SCREEN,
brightenScreen
)
previewScale = preferences.getFloat(
PREVIEW_SCALE,
previewScale
)
}
private fun addFormatsOnUpdate(
@@ -359,6 +342,31 @@ class Preferences {
}
}
private fun migrateCropHandle() {
val cropHandleXName = "crop_handle_x"
val def = CropHandle()
if (preferences.getInt(cropHandleXName, def.x) == def.x) {
return;
}
storeCropHandle(
CameraActivity.CAMERA_CROP_HANDLE,
CropHandle(
preferences.getInt(cropHandleXName, def.x),
preferences.getInt("crop_handle_y", def.y),
preferences.getInt("crop_handle_orientation", def.orientation)
)
)
preferences.edit().putInt(cropHandleXName, def.x).apply()
}
fun restoreCropHandle(
name: String
) = preferences.restoreCropHandle(name)
fun storeCropHandle(name: String, cropHandle: CropHandle) {
preferences.storeCropHandle(name, cropHandle)
}
fun beepTone() = when (beepToneName) {
"tone_cdma_confirm" -> ToneGenerator.TONE_CDMA_CONFIRM
"tone_sup_radio_ack" -> ToneGenerator.TONE_SUP_RADIO_ACK
@@ -377,9 +385,6 @@ class Preferences {
private fun put(label: String, value: Boolean) =
preferences.edit().putBoolean(label, value)
private fun put(label: String, value: String) =
preferences.edit().putString(label, value)
private fun apply(label: String, value: Boolean) {
put(label, value).apply()
}
@@ -392,6 +397,10 @@ class Preferences {
preferences.edit().putInt(label, value).apply()
}
private fun apply(label: String, value: Float) {
preferences.edit().putFloat(label, value).apply()
}
@SuppressLint("ApplySharedPref")
private fun commit(label: String, value: String) {
preferences.edit().putString(label, value).commit()
@@ -408,9 +417,6 @@ class Preferences {
}
private const val BARCODE_FORMATS = "formats"
private const val CROP_HANDLE_X = "crop_handle_x"
private const val CROP_HANDLE_Y = "crop_handle_y"
private const val CROP_HANDLE_ORIENTATION = "crop_handle_orientation"
private const val SHOW_CROP_HANDLE = "show_crop_handle"
private const val ZOOM_BY_SWIPING = "zoom_by_swiping"
private const val AUTO_ROTATE = "auto_rotate"
@@ -440,9 +446,9 @@ class Preferences {
private const val CUSTOM_LOCALE = "custom_locale"
private const val INDEX_OF_LAST_SELECTED_FORMAT = "index_of_last_selected_format"
private const val INDEX_OF_LAST_SELECTED_EC_LEVEL = "index_of_last_selected_ec_level"
private const val LAST_MARGIN = "last_margin"
private const val FREE_ROTATION = "free_rotation"
private const val EXPAND_ESCAPE_SEQUENCES = "expand_escape_sequences"
private const val BRIGHTEN_SCREEN = "brighten_screen"
private const val PREVIEW_SCALE = "preview_scale"
}
}
@@ -70,7 +70,13 @@ fun String.unescape(): String {
val sb = StringBuilder()
while (i < len) {
val ch = get(i++)
sb.append(if (ch == '\\' && i < len) expand() else ch)
sb.append(
if (ch == '\\' && i < len) {
expand()
} else {
ch
}
)
}
return sb.toString()
}
@@ -8,6 +8,7 @@ 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
@@ -57,10 +58,9 @@ private fun lastChildOutOfView(listView: AbsListView): Boolean {
return child != null && child.bottom >= listView.height
}
fun initSystemBars(activity: AppCompatActivity) {
fun AppCompatActivity.initBars() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Keeps the soft keyboard from repositioning the layout.
val window = activity.window
window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
)
@@ -69,7 +69,16 @@ fun initSystemBars(activity: AppCompatActivity) {
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
colorSystemAndToolBars(activity)
colorSystemAndToolBars(this)
setPaddingFromWindowInsets(
findViewById(R.id.main),
(findViewById(R.id.toolbar) as Toolbar).apply {
setSupportActionBar(this)
},
findViewById(R.id.navbar)?.apply {
setBackgroundColor(translucentPrimaryColor)
}
)
}
private var statusBarColorLocked = false
@@ -97,14 +106,27 @@ fun colorSystemAndToolBars(
val topColor = if (scrolled) translucentPrimaryColor else 0
val activity = getAppCompatActivity(context) ?: return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val window = activity.window
if (!statusBarColorLocked) {
window.statusBarColor = topColor
}
window.navigationBarColor = if (scrolled || scrollable) {
translucentPrimaryColor
// 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
}
@Suppress("DEPRECATION")
window.navigationBarColor = if (scrolled || scrollable) {
translucentPrimaryColor
} else {
0
}
} else {
0
activity.findViewById(R.id.navbar)?.apply {
visibility = if (scrolled || scrollable) {
View.VISIBLE
} else {
View.GONE
}
}
}
}
activity.supportActionBar?.setBackgroundDrawable(
@@ -7,10 +7,37 @@ 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
private var toolbarHeight = 0
fun recordToolbarHeight(toolbar: Toolbar) {
fun setPaddingFromWindowInsets(mainLayout: View, toolbar: Toolbar, navbar: View?) {
toolbarHeight = toolbar.layoutParams.height
// SDK 35+ is edge-to-edge by default, so the toolbar needs to extend
// below the status bar.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
return
}
mainLayout.setOnApplyWindowInsetsListener { _, insets ->
val systemBarInsets = insets.getInsets(
WindowInsets.Type.systemBars()
)
val statusBarTop = systemBarInsets.top
if (toolbar.paddingTop == 0 && statusBarTop > 0) {
toolbar.setPadding(0, statusBarTop, 0, 0)
toolbar.layoutParams.height += statusBarTop
}
val navBarBottom = systemBarInsets.bottom
if (navBarBottom > 0) {
mainLayout.setPadding(0, 0, 0, navBarBottom);
navbar?.apply {
layoutParams.height = navBarBottom
}
}
insets
}
}
fun View.setPaddingFromWindowInsets() {
@@ -10,6 +10,8 @@ import de.markusfisch.android.scalingimageview.widget.ScalingImageView
open class ConfinedScalingImageView : ScalingImageView {
val insets = Rect()
var runAfterLayout: (() -> Unit)? = null
constructor(context: Context, attrs: AttributeSet, defStyle: Int) :
super(context, attrs, defStyle)
@@ -37,5 +39,8 @@ open class ConfinedScalingImageView : ScalingImageView {
)
}
centerRemap()
runAfterLayout?.invoke()
}
fun isInBounds(): Boolean = inBounds()
}
@@ -19,6 +19,7 @@ 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 de.markusfisch.android.binaryeye.preference.CropHandle
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@@ -83,11 +84,16 @@ class DetectorView : View {
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) :
super(context, attrs, defStyleAttr)
fun saveCropHandlePos() {
fun storeCropHandlePos(name: String) {
val pos = getCropHandlePos()
prefs.cropHandleX = pos.x
prefs.cropHandleY = pos.y
prefs.cropHandleOrientation = currentOrientation
prefs.storeCropHandle(
name,
CropHandle(
pos.x,
pos.y,
currentOrientation
)
)
}
private fun getCropHandlePos() = if (handleActive) {
@@ -96,11 +102,12 @@ class DetectorView : View {
Point(-1, -1)
}
fun restoreCropHandlePos() {
fun restoreCropHandlePos(name: String) {
val cropHandle = prefs.restoreCropHandle(name)
setCropHandlePos(
prefs.cropHandleX,
prefs.cropHandleY,
prefs.cropHandleOrientation
cropHandle.x,
cropHandle.y,
cropHandle.orientation
)
}
@@ -3,19 +3,29 @@ package de.markusfisch.android.binaryeye.widget
import android.content.Context
import android.widget.Toast
fun Context.toast(message: Int) = Toast.makeText(
applicationContext,
message,
Toast.LENGTH_LONG
).show()
private var lastToast: Toast? = null
fun Context.toast(message: String) = Toast.makeText(
applicationContext,
message.ellipsize(128),
Toast.LENGTH_LONG
).show()
fun <T> Context.toast(message: T) {
lastToast?.cancel()
lastToast = when (message) {
is String -> Toast.makeText(
applicationContext,
message.ellipsize(),
Toast.LENGTH_LONG
)
private fun String.ellipsize(max: Int) = if (length < max) {
is Int -> Toast.makeText(
applicationContext,
message,
Toast.LENGTH_LONG
)
else -> return
}
lastToast?.show()
}
private fun String.ellipsize(max: Int = 128) = if (length < max) {
this
} else {
"${take(max)}"
@@ -0,0 +1,16 @@
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="true">
<item android:state_pressed="false">
<shape android:shape="rectangle">
<corners android:radius="2dp"/>
<solid android:color="@color/selected_row"/>
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="2dp"/>
<solid android:color="@color/pressed_row"/>
</shape>
</item>
</selector>
@@ -1,5 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M20,8.69L20,4h-4.69L12,0.69 8.69,4L4,4v4.69L0.69,12 4,15.31L4,20h4.69L12,23.31 15.31,20L20,20v-4.69L23.31,12 20,8.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4z"/>
<path android:fillColor="#fff" android:pathData="M20 8.69V4h-4.69L12 0.69 8.69 4H4v4.69L0.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69zM12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zm0-10c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z"/>
</vector>
@@ -1,3 +1,3 @@
<vector android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M14.54,18.49L14.54,16.51L17.51,16.51L17.51,13.54L19.49,13.54L19.49,16.51L22.46,16.51L22.46,18.49L19.508,18.508L19.49,21.46L17.51,21.46L17.492,18.508L14.54,18.49ZM13.35,14.75L11,12.4L11,7L13,7L13,11.6L14.4,13L13.35,14.75ZM3,10L3,4L5,4L5,6.35C5.85,5.283 6.888,4.458 8.113,3.875C9.338,3.292 10.633,3 12,3C14.5,3 16.625,3.875 18.375,5.625C20.125,7.375 21,9.5 21,12L19,12C19,10.05 18.321,8.396 16.963,7.037C15.604,5.679 13.95,5 12,5C10.85,5 9.775,5.267 8.775,5.8C7.775,6.333 6.933,7.067 6.25,8L9,8L9,10L3,10ZM12,21C9.7,21 7.696,20.237 5.988,18.712C4.279,17.187 3.3,15.283 3.05,13L5.1,13C5.333,14.733 6.104,16.167 7.413,17.3C8.721,18.433 10.25,19 12,19C12.183,19 12.354,18.996 12.513,18.987C12.671,18.979 12.833,18.958 13,18.925L13,20.95C12.833,20.967 12.671,20.979 12.513,20.987C12.354,20.996 12.183,21 12,21Z"/>
<path android:fillColor="#FF000000" android:pathData="M14.54 18.49v-1.98h2.97v-2.97h1.98v2.97h2.97v1.98l-2.952 0.018-0.018 2.952h-1.98l-0.018-2.952-2.952-0.018zm-1.19-3.74L11 12.4V7h2v4.6l1.4 1.4-1.05 1.75zM3 10V4h2v2.35c0.85-1.067 1.888-1.892 3.113-2.475C9.338 3.292 10.633 3 12 3c2.5 0 4.625 0.875 6.375 2.625S21 9.5 21 12h-2c0-1.95-0.679-3.604-2.037-4.963C15.604 5.679 13.95 5 12 5c-1.15 0-2.225 0.267-3.225 0.8S6.933 7.067 6.25 8H9v2H3zm9 11c-2.3 0-4.304-0.763-6.012-2.288C4.279 17.187 3.3 15.283 3.05 13H5.1c0.233 1.733 1.004 3.167 2.313 4.3C8.721 18.433 10.25 19 12 19c0.183 0 0.354-0.004 0.513-0.013 0.158-0.008 0.32-0.029 0.487-0.062v2.025c-0.167 0.017-0.329 0.029-0.487 0.037C12.354 20.996 12.183 21 12 21z"/>
</vector>
@@ -1,9 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:pathData="M54,72.9C49.17,72.9 44.96,71.3 41.37,68.1C37.78,64.89 35.73,60.9 35.2,56.1L39.51,56.1C40,59.74 41.62,62.75 44.37,65.13C47.11,67.51 50.32,68.7 54,68.7C58.1,68.7 61.57,67.28 64.42,64.42C67.28,61.57 68.7,58.1 68.7,54C68.7,49.9 67.28,46.43 64.42,43.58C61.57,40.72 58.1,39.3 54,39.3C51.58,39.3 49.33,39.86 47.23,40.98C45.13,42.1 43.36,43.64 41.92,45.6L47.7,45.6L47.7,49.8L35.1,49.8L35.1,37.2L39.3,37.2L39.3,42.13C41.08,39.89 43.26,38.16 45.84,36.94C48.41,35.71 51.13,35.1 54,35.1C56.63,35.1 59.08,35.6 61.38,36.59C63.67,37.59 65.67,38.94 67.36,40.64C69.06,42.33 70.41,44.33 71.41,46.62C72.4,48.92 72.9,51.37 72.9,54C72.9,56.63 72.4,59.08 71.41,61.38C70.41,63.67 69.06,65.67 67.36,67.36C65.67,69.06 63.67,70.41 61.38,71.41C59.08,72.4 56.63,72.9 54,72.9ZM59.88,62.82L51.9,54.84L51.9,43.5L56.1,43.5L56.1,53.16L62.82,59.88L59.88,62.82Z"
android:fillColor="#FFFFFF"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="108dp" android:height="108dp" android:viewportWidth="108" android:viewportHeight="108">
<path android:pathData="M54 72.9c-4.83 0-9.04-1.6-12.63-4.8-3.59-3.21-5.64-7.2-6.17-12h4.31c0.49 3.64 2.11 6.65 4.86 9.03 2.74 2.38 5.95 3.57 9.63 3.57 4.1 0 7.57-1.42 10.42-4.28C67.28 61.57 68.7 58.1 68.7 54s-1.42-7.57-4.28-10.42C61.57 40.72 58.1 39.3 54 39.3c-2.42 0-4.67 0.56-6.77 1.68-2.1 1.12-3.87 2.66-5.31 4.62h5.78v4.2H35.1V37.2h4.2v4.93c1.78-2.24 3.96-3.97 6.54-5.19 2.57-1.23 5.29-1.84 8.16-1.84 2.63 0 5.08 0.5 7.38 1.49 2.29 1 4.29 2.35 5.98 4.05 1.7 1.69 3.05 3.69 4.05 5.98 0.99 2.3 1.49 4.75 1.49 7.38s-0.5 5.08-1.49 7.38c-1 2.29-2.35 4.29-4.05 5.98-1.69 1.7-3.69 3.05-5.98 4.05-2.3 0.99-4.75 1.49-7.38 1.49zm5.88-10.08l-7.98-7.98V43.5h4.2v9.66l6.72 6.72-2.94 2.94z" android:fillColor="#FFFFFF"/>
</vector>
+2 -1
View File
@@ -8,9 +8,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
android:fitsSystemWindows="@bool/fitsSystemWindows">
<include layout="@layout/toolbar"/>
<SeekBar
android:id="@+id/zoom"
+3 -1
View File
@@ -4,9 +4,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
android:fitsSystemWindows="@bool/fitsSystemWindows">
<include layout="@layout/toolbar"/>
</FrameLayout>
<include layout="@layout/navbar"/>
</merge>
+3 -1
View File
@@ -9,9 +9,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
android:fitsSystemWindows="@bool/fitsSystemWindows">
<include layout="@layout/toolbar"/>
<android.support.design.widget.FloatingActionButton
style="@style/FAB"
@@ -19,4 +20,5 @@
android:contentDescription="@string/scan_code"
android:src="@drawable/ic_action_next"/>
</android.support.design.widget.CoordinatorLayout>
<include layout="@layout/navbar"/>
</merge>
@@ -0,0 +1,57 @@
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<!-- The FrameLayout is necessary because this LinearLayout
should have a padding which would be reset by the window
insets from `fitsSystemWindows`. -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:padding="24dp"
android:orientation="vertical"
tools:ignore="UselessParent">
<TextView
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:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/welcome"/>
<LinearLayout
style="@style/WelcomeButton"
android:id="@+id/expert"
android:layout_marginBottom="16dp"
android:orientation="vertical">
<TextView
style="@style/WelcomeButtonText"
android:text="@string/mode_expert"/>
<TextView
style="@style/WelcomeButtonSubText"
android:text="@string/mode_expert_description"/>
</LinearLayout>
<LinearLayout
style="@style/WelcomeButton"
android:id="@+id/simple"
android:orientation="vertical">
<TextView
style="@style/WelcomeButtonText"
android:text="@string/mode_simple"/>
<TextView
style="@style/WelcomeButtonSubText"
android:text="@string/mode_simple_description"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</ScrollView>
@@ -0,0 +1,22 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/find_code_with_content"/>
<EditText
android:id="@+id/term"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textShortMessage"
android:imeOptions="actionDone"
android:hint="@string/find_code_hint"
android:maxLines="1"
android:maxLength="1024"
android:importantForAutofill="no"/>
</LinearLayout>
+23
View File
@@ -0,0 +1,23 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/size_display"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_marginBottom="8dp"/>
<SeekBar
style="@style/Widget.AppCompat.SeekBar.Discrete"
android:id="@+id/size_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:progress="2"
android:max="4"/>
</LinearLayout>
+4 -34
View File
@@ -65,42 +65,12 @@
android:id="@+id/colors"
android:layout_marginBottom="16dp"
android:entries="@array/colors"/>
<TextView
android:id="@+id/size_display"
<android.support.v7.widget.SwitchCompat
android:visibility="gone"
android:id="@+id/add_quiet_zone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"/>
<SeekBar
style="@style/Widget.AppCompat.SeekBar.Discrete"
android:id="@+id/size_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:progress="4"
android:max="7"/>
<LinearLayout
android:id="@+id/margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/margin_display"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"/>
<SeekBar
style="@style/Widget.AppCompat.SeekBar.Discrete"
android:id="@+id/margin_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:max="32"/>
</LinearLayout>
android:text="@string/add_quiet_zone"/>
</LinearLayout>
</de.markusfisch.android.binaryeye.widget.ConfinedScrollView>
<android.support.design.widget.CoordinatorLayout
+8
View File
@@ -0,0 +1,8 @@
<!-- Navigation bar background from SDK35+ -->
<View
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/navbar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="bottom"
android:visibility="gone"/>
@@ -32,6 +32,11 @@
android:title="@string/restrict_format"
android:icon="@drawable/ic_action_restrict_format"
material:showAsAction="ifRoom"/>
<item
android:id="@+id/find_code"
android:title="@string/find_code"
android:icon="@drawable/ic_action_search"
material:showAsAction="ifRoom"/>
<item
android:id="@+id/preferences"
android:title="@string/preferences"
+222
View File
@@ -0,0 +1,222 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="welcome">مرحبًا!</string>
<string name="mode_expert">متقدم</string>
<string name="mode_expert_description">أود التحقق من المحتوى المقروء وفتحه يدويًا.</string>
<string name="mode_simple">بسيط</string>
<string name="mode_simple_description">أريد فقط قراءة الباركود وفتحه فورًا.</string>
<string name="camera_error">يتعذر الوصول إلى الكاميرا، يرجى المحاولة مرة أخرى</string>
<string name="scan_code">مسح الرمز</string>
<string name="compose_barcode">إنشاء رمز Bardcode</string>
<string name="decode_barcode">فك رمز Barcode</string>
<string name="content">المحتوى</string>
<string name="binary_data">(بيانات ثنائية)</string>
<plurals name="barcode_info">
<item quantity="zero">%2$d حروف، %1$s</item>
<item quantity="one">حرف واحد، %1$s</item>
<item quantity="two">حرفين، %1$s</item>
<item quantity="few">%2$d حروف، %1$s</item>
<item quantity="many">%2$d حرف، %1$s</item>
<item quantity="other">%2$d حرف، %1$s</item>
</plurals>
<string name="error_correction_level">مستوى تصحيح الأخطاء</string>
<string name="error_correction_level_l" formatted="false">منخفض (~7&#37; تصحيح)</string>
<string name="error_correction_level_m" formatted="false">متوسط (~15&#37; تصحيح)</string>
<string name="error_correction_level_q" formatted="false">ربع (~25&#37; تصحيح)</string>
<string name="error_correction_level_h" formatted="false">مرتفع (~30&#37; تصحيح)</string>
<string name="label">العنوان</string>
<string name="colors">المقدمة والخلفية</string>
<string name="colors_black_on_white">أسود على خلفية بيضاء</string>
<string name="colors_white_on_black">أبيض على خلفية سوداء</string>
<string name="colors_black_on_transparent">أسود على خلفية شفافة</string>
<string name="colors_white_on_transparent">أبيض على خلفية شفافة</string>
<string name="sequence_size">حجم التسلسل</string>
<string name="sequence_index">رقم التسلسل</string>
<string name="sequence_id">معرف التسلسل</string>
<string name="gtin_issue_number">رقم الإصدار</string>
<string name="gtin_country">بلد التصنيع المحتمل</string>
<string name="gtin_price">السعر المقترح</string>
<string name="gtin_add_on">إضافة UPC EAN</string>
<string name="barcode_version_number">الإصدار</string>
<string name="qr_version_and_modules" tools:ignore="PluralsCandidate">%1$s (%2$d وحدات)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">تشغيل/إيقاف الوميض</string>
<string name="error_flash">خطأ في تشغيل الوميض</string>
<string name="share">مشاركة</string>
<string name="share_file">مشاركة كملف</string>
<string name="share_as">مشاركة كـ؟</string>
<string name="copy_to_clipboard">نسخ إلى الحافظة</string>
<string name="copied_to_clipboard">تم النسخ إلى الحافظة</string>
<string name="copy_password">نسخ كلمة المرور إلى الحافظة</string>
<string name="copied_password_to_clipboard">تم نسخ كلمة المرور إلى الحافظة</string>
<string name="open_url">فتح الرابط</string>
<string name="cannot_resolve_action">لم يتم العثور على تطبيق يمكنه فتح ذلك</string>
<string name="pick_search_engine">اختر محرك البحث</string>
<string name="format">التنسيق</string>
<string name="size_width_by_height">الحجم بالبكسل: %1$d×%2$d</string>
<string name="size_no_magnification">بدون تكبير</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">أدخل المحتوى هنا</string>
<string name="unescape">توسيع رموز الهروب (escape sequences)</string>
<string name="encode">ترميز</string>
<string name="error_no_content">المحتوى مفقود</string>
<string name="error_encoding_barcode">لا يمكن إنشاء رمز Barcode</string>
<string name="view_barcode">عرض رمز Barcode</string>
<string name="info">معلومات</string>
<string name="switch_camera">تبديل الكاميرا</string>
<string name="bulk_mode">المسح بشكل مستمر</string>
<string name="bulk_mode_summary">ابدأ المسح دائمًا بشكل مستمر.</string>
<string name="bulk_mode_delay">الفارق الزمني بين عمليات المسح المستمرة</string>
<string name="restrict_format">تحديد التنسيق</string>
<string name="remove_restriction">إزالة التحديد</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">مسح %s</string>
<string name="quarter_second">ربع ثانية</string>
<string name="half_second">نصف ثانية</string>
<string name="a_second">ثانية واحدة</string>
<string name="two_seconds">ثانيتان</string>
<string name="five_seconds">خمس ثوانٍ</string>
<string name="history">التاريخ</string>
<string name="preferences">الإعدادات</string>
<string name="scan_category">المسح</string>
<string name="content_category">المحتوى</string>
<string name="locale_category">اللغة</string>
<string name="custom_locale">تغيير اللغة</string>
<string name="follow_system_settings">اتبع إعدادات النظام</string>
<string name="show_crop_handle">عرض محدد الاقتصاص</string>
<string name="show_crop_handle_summary">حصر المسح في منطقة قابلة للتخصيص.</string>
<string name="barcode_formats">تنسيقات Barcode</string>
<string name="zoom_by_swiping">مرر لأعلى أو لأسفل للتكبير/التصغير</string>
<string name="zoom_by_swiping_summary">مرر لأعلى أو لأسفل على واجهة الكاميرا للتحكم في التكبير/التصغير لها.</string>
<string name="auto_rotate">التعرف على رموز Barcode العمودية أحادية الأبعاد</string>
<string name="auto_rotate_summary">تدوير إطار الكاميرا تلقائيًا للتعرف على رموز Barcode العمودية أحادية الأبعاد. بناءً على الجهاز المستخدم، قد يؤثر ذلك على الأداء.</string>
<string name="try_harder">تحسين دقة القارئ</string>
<string name="try_harder_summary">قم بتمكين هذا الخيار للرموز التي يصعب قراءتها. سيؤثر على الأداء.</string>
<string name="show_toast_in_bulk_mode">عرض البيانات في الوضع المستمر</string>
<string name="show_toast_in_bulk_mode_summary">عرض سريع للبيانات الممسوحة عند المسح المستمر.</string>
<string name="vibrate">الاهتزاز عند الكشف</string>
<string name="vibrate_summary">قم بتمكين هذا إذا كنت تريد أن يهتز جهازك عندما يتم التعرف على رمز.</string>
<string name="beep">صوت صفير عند الكشف</string>
<string name="beep_summary">قم بتمكين هذا إذا كنت تريد أن يصدر جهازك صوتًا عند التعرف على رمز.</string>
<string name="beep_tone">نغمة الصفير</string>
<string name="tone_cdma_confirm">تأكيد CDMA</string>
<string name="tone_sup_confirm">تأكيد الإشراف على الاتصال</string>
<string name="tone_sup_radio_ack">إقرار مسار الراديو الإشرافي على الاتصال.</string>
<string name="tone_prop_ack">إقرار إيجابي</string>
<string name="tone_prop_beep">صوت صفير عام</string>
<string name="tone_prop_beep2">صوت صفير مزدوج عام</string>
<string name="use_history">حفظ تاريخ المسح</string>
<string name="use_history_summary">حفظ الرموز المتعرف عليها على جهازك.</string>
<string name="ignore_duplicates">تجاهل النسخ المكررة</string>
<string name="ignore_consecutive_duplicates">النسخ المكررة المتتالية</string>
<string name="ignore_any_duplicates">أي نسخ مكررة</string>
<string name="accept_duplicates">قبول النسخ المكررة</string>
<string name="open_immediately">فتح مباشرةً</string>
<string name="open_immediately_summary">تخطي الفحص وفتح المحتويات على الفور. قد يتم فتح محتويات ضارة إذا تم تمكينه.</string>
<string name="copy_immediately">نسخ تلقائي إلى الحافظة</string>
<string name="copy_immediately_summary">نسخ المحتويات الممسوحة إلى الحافظة تلقائيًا. يرجى ملاحظة أن التطبيقات الأخرى قد تتطفل على الحافظة الخاصة بك في الخلفية.</string>
<string name="show_meta_data">عرض البيانات الوصفية</string>
<string name="show_meta_data_summary">عرض بيانات إضافية حول رمز Barcode الممسوح.</string>
<string name="show_hex_dump">عرض التفريغ سداسي عشري</string>
<string name="show_hex_dump_summary">عرض تفريغ سداسي عشري للمحتويات الممسوحة.</string>
<string name="show_checksum">عرض الـ checksum</string>
<string name="no_checksum">الـ checksum غير متوفر</string>
<string name="show_recreation">إظهار رمز Barcode المعاد إنشاؤه</string>
<string name="show_recreation_summary">إعادة إنشاء وإظهار رمز Barcode من المحتوى الذي تمت قراءته إن أمكن.</string>
<string name="close_automatically">العودة للخلف بعد النسخ أو المشاركة</string>
<string name="close_automatically_summary">العودة تلقائيًا إلى شاشة المسح بعد نسخ أو مشاركة المحتويات المقروءة.</string>
<string name="default_search_engine">فتح البيانات المجهولة في</string>
<string name="always_ask">اسأل دائمًا</string>
<string name="open_with_url">فتح البيانات المجهولة باستخدام رابط</string>
<string name="clear_network_suggestions">إزالة الشبكات المقترحة</string>
<string name="clear_network_suggestions_summary">إزالة الشبكات المقترحة التي تمت إضافتها مسبقًا من خلال هذا التطبيق.</string>
<string name="really_remove_all_networks">هل تريد حقًا إزالة جميع الشبكات؟</string>
<string name="clear_network_suggestions_success">تم إزالة الشبكات المقترحة</string>
<string name="clear_network_suggestions_nothing_to_remove">لا يوجد أي شبكات المقترحة</string>
<string name="send_category">إعادة التوجيه</string>
<string name="send_scan_active">إعادة توجيه عمليات المسح</string>
<string name="send_scan_active_summary">قم بالتمكين لإعادة توجيه عمليات المسح إلى رابط معين.</string>
<string name="send_scan_url">الرابط المراد إعادة التوجيه إليه</string>
<string name="send_scan_type">نوع الطلب</string>
<string name="send_type_get_add_content">GET and simply add content</string>
<string name="send_type_get_query_string">GET with complete query string</string>
<string name="send_type_post_form">POST application/x-www-form-urlencoded</string>
<string name="send_type_post_json">POST application/json</string>
<string name="send_type_external_browser">فتح في متصفح خارجي</string>
<string name="test_url">رابط للاختبار</string>
<string name="send_scan_bluetooth">إرسال عمليات المسح عبر بلوتوث</string>
<string name="send_scan_bluetooth_summary">تمكين إرسال عمليات المسح إلى مضيف بلوتوث معين.</string>
<string name="send_scan_bluetooth_host">المضيف</string>
<string name="no_bluetooth_hosts_paired">لا يوجد اقتران مع مضيفين</string>
<string name="bluetooth_connect_fail">تعذر الاتصال بجهاز بلوتوث.</string>
<string name="bluetooth_send_fail">تعذر الإرسال إلى جهاز بلوتوث.</string>
<string name="bluetooth_send_success">نجح الإرسال إلى جهاز بلوتوث.</string>
<string name="generation_category">التوليد</string>
<string name="brighten_screen">شاشة ساطعة</string>
<string name="brighten_screen_summary">تعيين مستوى السطوع إلى الحد الأقصى لتحسين مسح الرمز من الشاشة.</string>
<string name="really_remove_scan">هل تريد حقًا إزالة المسح؟</string>
<string name="really_remove_all_scans">هل تريد حقًا إزالة كافة عمليات المسح؟</string>
<string name="really_remove_selected_scans">هل تريد حقًا إزالة عمليات المسح المحددة؟</string>
<string name="clear_history">مسح التاريخ</string>
<string name="copy_scan">نسخ عملية المسح</string>
<string name="edit_label">تعديل العنوان</string>
<string name="remove_scan">حذف عملية المسح</string>
<string name="enter_name">أدخل اسمًا لوصف عملية المسح</string>
<string name="enter_name_hint">اسم عملية المسح</string>
<string name="no_barcode_found">لا يوجد أي رمز Barcode</string>
<string name="pick_list_separator">الفاصل المستخدم لفصل عناصر القائمة؟</string>
<string name="separator_line_break">خط فاصل</string>
<string name="separator_ruler">المسطرة</string>
<string name="save_as_file_name">حفظ في مجلد التنزيلات؟</string>
<string name="file_name">اسم الملف</string>
<string name="error_saving_file">يتعذر حفظ الملف</string>
<string name="error_file_exists">الملف موجود بالفعل</string>
<string name="connect_to_wifi">الاتصال بشبكة Wi-Fi</string>
<string name="wifi_config_failed">تعذر تهيئة شبكة Wi-Fi</string>
<string name="wifi_added">تمت إضافة شبكة Wi-Fi</string>
<string name="sms_send">إرسال رسالة نصية قصيرة</string>
<string name="sms_error">تعذر إرسال رسالة نصية قصيرة</string>
<string name="tel_dial">الاتصال بالرقم</string>
<string name="tel_error">تعذر الاتصال بالرقم</string>
<string name="mail_send">إرسال بريد إلكتروني</string>
<string name="mail_error">تعذر إرسال البريد الإلكتروني</string>
<string name="vcard_add">إضافة إلى جهات الاتصال</string>
<string name="vcard_failed">تعذرت الإضافة إلى جهات الاتصال</string>
<string name="vevent_add">إضافة إلى التقويم</string>
<string name="vevent_failed">تعذرت الإضافة إلى التقويم</string>
<string name="otpauth_add">أضف المصادقة الثنائية (2FA)</string>
<string name="search_web">البحث عبر الإنترنت</string>
<string name="search_scan">البحث عن عملية مسح</string>
<string name="add_to_history">إضافة إلى التاريخ</string>
<string name="added_to_history">تمت الإضافة إلى التاريخ</string>
<string name="export_to_file">تصدير إلى ملف</string>
<string name="export_as">تصدير كـ؟</string>
<string name="export_csv_comma">ملف CSV مع فواصل</string>
<string name="export_csv_semicolon">ملف CSV مع فواصل منقوطة</string>
<string name="export_json">ملف JSON</string>
<string name="export_database">قاعدة بيانات SQLite</string>
<string name="saved_in_downloads">تم الحفظ في مجلد التنزيلات</string>
<string name="rotate_image_cw">تدوير الصورة باتجاه عقارب الساعة</string>
<string name="toggle_free_rotation">تبديل التدوير الحر</string>
<string name="pick_file">اختر ملف</string>
<string name="pick_image_file">اختر صورة</string>
<string name="pick_code_to_scan">اختر رمزًا لمسحه</string>
<string name="shortcut_decode">مسح رمز Barcode</string>
<string name="shortcut_encode">إنشاء رمز Barcode</string>
<string name="shortcut_history">التاريخ</string>
<string name="shortcut_preferences">الإعدادات</string>
<string name="background_request_failed">فشل الطلب للعمل في الخلفية</string>
<string name="entry_type">النوع</string>
<string name="wifi_network">شبكة Wi-Fi</string>
<string name="wifi_ssid">الاسم</string>
<string name="wifi_type">نوع المصادقة</string>
<string name="wifi_password">كلمة المرور</string>
<string name="wifi_hidden">شبكة مخفية</string>
<string name="wifi_eap">طريقة EAP</string>
<string name="wifi_anonymous_identity">هوية مجهولة</string>
<string name="wifi_identity">الهوية</string>
<string name="wifi_phase2">طريقة Phase 2</string>
<string name="network_suggestions">الشبكات المقترحة</string>
<string name="remove_suggestion">إزالة الاقتراحات</string>
</resources>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Добре дошли!</string>
<string name="mode_expert">Разширен</string>
<string name="mode_expert_description">Искам да проверя прочетеното съдържание и да го отворя ръчно.</string>
<string name="mode_simple">Опростен</string>
<string name="mode_simple_description">Искам просто да сканирам баркодове и да ги отварям веднага.</string>
<string name="camera_error">Няма достъп до камерата, моля, опитайте отново</string>
<string name="scan_code">Сканирайте код</string>
<string name="compose_barcode">Създаване на баркод</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN разширение</string>
<string name="barcode_version_number">Версия</string>
<string name="qr_version_and_modules">%1$s (%2$d модули)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Превключване на светкавицата</string>
<string name="error_flash">Грешка при превключването на светкавицата</string>
<string name="share">Сподели</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Изберете търсачка</string>
<string name="format">Формат</string>
<string name="size_width_by_height">Размер в пиксели: %1$d×%2$d</string>
<string name="margin_size">Марж в пиксели: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Въведете съдържание тук</string>
<string name="unescape">Разширете последователности за извеждане</string>
<string name="encode">КОДИРАНЕ</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Забавяне между непрекъснатите сканирания</string>
<string name="restrict_format">Ограничаване на формат</string>
<string name="remove_restriction">Премахване на ограничението</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Сканиране %s</string>
<string name="quarter_second">Червърт секунда</string>
<string name="half_second">Половин секунда</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">স্বাগতম!</string>
<string name="mode_expert">উন্নত</string>
<string name="mode_expert_description">আমি পড়া বিষয়বস্তু যাচাই করতে চাই এবং এটি নিজে খুলতে চাই।</string>
<string name="mode_simple">সহজ</string>
<string name="mode_simple_description">আমি কেবল বারকোড স্ক্যান করতে চাই এবং তা সঙ্গে সঙ্গে খুলতে চাই।</string>
<string name="camera_error">ক্যামেরা পাওয়া যাচ্ছে না, পরে চেষ্টা করো</string>
<string name="scan_code">সংকেতের পাঠোদ্ধার</string>
<string name="compose_barcode">বারকোড বানাও</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">ইউপিসি ইএএন বর্ধিত</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">আলো</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">ভাগ করো</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">একটা সার্চ ইঞ্জিন নাও</string>
<string name="format">ধরণ</string>
<string name="size_width_by_height">পিক্সেলে আকা:%1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">এখানে তথ্য দাও</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">সংকেতকরণ</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Delay between continuous scans</string>
<string name="restrict_format">Restrict format</string>
<string name="remove_restriction">Remove restriction</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">A quarter second</string>
<string name="half_second">Half a second</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Vítejte!</string>
<string name="mode_expert">Pokročilý</string>
<string name="mode_expert_description">Chci zkontrolovat načtený obsah a otevřít jej ručně.</string>
<string name="mode_simple">Jednoduchý</string>
<string name="mode_simple_description">Chci jen skenovat čárové kódy a okamžitě je otevírat.</string>
<string name="camera_error">Nepodařilo se otevřít fotoaparát, prosím zkuste to znovu</string>
<string name="scan_code">Naskenovat kód</string>
<string name="compose_barcode">Vytvořit čárový kód</string>
@@ -31,6 +36,7 @@
<string name="gtin_add_on">rozšíření UPC EAN</string>
<string name="barcode_version_number">Verze</string>
<string name="qr_version_and_modules">%1$s (%2$d modulů)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Přepnout blesk</string>
<string name="error_flash">Zapnutí/vypnutí blesku selhalo</string>
<string name="share">Sdílet</string>
@@ -45,7 +51,8 @@
<string name="pick_search_engine">Zvolte vyhledávač</string>
<string name="format">Formát</string>
<string name="size_width_by_height">Velikost v pixelech: %1$d×%2$d</string>
<string name="margin_size">Okraje v pixelech: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Sem vložte obsah</string>
<string name="unescape">Rozšířit escape sekvence</string>
<string name="encode">ZAKÓDOVAT</string>
@@ -59,6 +66,9 @@
<string name="bulk_mode_delay">Prodleva mezi skeny</string>
<string name="restrict_format">Omezit na formát</string>
<string name="remove_restriction">Zrušit omezení formátu</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Naskenovat %s</string>
<string name="quarter_second">Čtvrt sekundy</string>
<string name="half_second">Půl sekundy</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Velkommen!</string>
<string name="mode_expert">Avanceret</string>
<string name="mode_expert_description">Jeg vil kontrollere det læste indhold og åbne det manuelt.</string>
<string name="mode_simple">Simpel</string>
<string name="mode_simple_description">Jeg vil bare scanne stregkoder og få dem åbnet med det samme.</string>
<string name="camera_error">Kan ikke få adgang til kamera, prøv igen</string>
<string name="scan_code">Scan kode</string>
<string name="compose_barcode">Opret stregkode</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN udvidelse</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d moduler)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Slå blitz til/fra</string>
<string name="error_flash">Der opstod en fejl ved at slå blitz til/fra</string>
<string name="share">Del</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Vælg en søgemaskine</string>
<string name="format">Format</string>
<string name="size_width_by_height">Størrelse i pixels: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Indtast indhold her</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">INDKOD</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Forsinkelse mellem kontinuerlige scanninger</string>
<string name="restrict_format">Begræns format</string>
<string name="remove_restriction">Fjern begrænsningen</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">Et kvart sekund</string>
<string name="half_second">Et halvt sekund</string>
+12 -2
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Willkommen!</string>
<string name="mode_expert">Erweitert</string>
<string name="mode_expert_description">Ich möchte den gelesenen Inhalt überprüfen und manuell öffnen.</string>
<string name="mode_simple">Einfach</string>
<string name="mode_simple_description">Ich möchte nur Barcodes scannen und sie sofort öffnen.</string>
<string name="camera_error">Auf die Kamera kann nicht zugegriffen werden, bitte versuche es nochmal</string>
<string name="scan_code">Code scannen</string>
<string name="compose_barcode">Barcode erstellen</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN Erweiterung</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d Module)</string>
<string name="qr_data_mask">Maske</string>
<string name="toggle_flash">Licht an/ausschalten</string>
<string name="error_flash">Fehler beim ein/ausschalten des Lichts</string>
<string name="share">Teilen</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Suchmaschine auswählen</string>
<string name="format">Format</string>
<string name="size_width_by_height">Größe in Pixel: %1$d×%2$d</string>
<string name="margin_size">Randgröße in Pixel: %1$d</string>
<string name="size_no_magnification">Keine Vergrößerung</string>
<string name="add_quiet_zone">Ruhezone hinzufügen</string>
<string name="input_content_here">Gib den Inhalt hier ein</string>
<string name="unescape">Escape-Sequenzen interpretieren</string>
<string name="encode">KODIEREN</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Pause zwischen fortlaufenden Scans</string>
<string name="restrict_format">Format eingrenzen</string>
<string name="remove_restriction">Einschränkung entfernen</string>
<string name="find_code">Barcode finden</string>
<string name="find_code_with_content">Mit welchem Inhalt?</string>
<string name="find_code_hint">Begriff eingeben</string>
<string name="scan_format">%s scannen</string>
<string name="quarter_second">Eine Viertelsekunde</string>
<string name="half_second">Eine halbe Sekunde</string>
@@ -139,7 +149,7 @@
<string name="bluetooth_send_fail">Senden zum Bluetooth-Gerät fehlgeschlagen</string>
<string name="bluetooth_send_success">Erfolgreich zum Bluetooth-Gerät gesendet</string>
<string name="generation_category">Generation</string>
<string name="brighten_screen">Bildschrim aufhellen</string>
<string name="brighten_screen">Bildschirm aufhellen</string>
<string name="brighten_screen_summary">Helligkeit auf Maximum stellen um das Scannen eines Barcodes vom Bildschirm zu verbessern.</string>
<string name="really_remove_scan">Code wirklich entfernen?</string>
<string name="really_remove_all_scans">Alle Codes entfernen?</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">¡Bienvenido!</string>
<string name="mode_expert">Avanzado</string>
<string name="mode_expert_description">Quiero verificar el contenido leído y abrirlo manualmente.</string>
<string name="mode_simple">Simple</string>
<string name="mode_simple_description">Solo quiero escanear códigos de barras y abrirlos de inmediato.</string>
<string name="camera_error">No se puede acceder a la cámara, por favor, inténtelo de nuevo</string>
<string name="scan_code">Escanear código</string>
<string name="compose_barcode">Componer código</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">Extensión UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d modulos)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Activar el flash</string>
<string name="error_flash">Error activando flash</string>
<string name="share">Compartir</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Seleccionar motor de búsqueda</string>
<string name="format">Formato</string>
<string name="size_width_by_height">Tamaño en píxeles: %1$d×%2$d</string>
<string name="margin_size">Margen en pixeles: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Introduzca el contenido aquí</string>
<string name="unescape">Expandir secuencia de escape</string>
<string name="encode">CODIFICAR</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Demora entre escaneos continuos</string>
<string name="restrict_format">Restringir formato</string>
<string name="remove_restriction">Eliminar restricción</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Escanear %s</string>
<string name="quarter_second">Un cuarto de segundo</string>
<string name="half_second">Medio segundo</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">خوش آمدید!</string>
<string name="mode_expert">پیشرفته</string>
<string name="mode_expert_description">می‌خواهم محتوای خوانده شده را بررسی کرده و به صورت دستی باز کنم.</string>
<string name="mode_simple">ساده</string>
<string name="mode_simple_description">فقط می‌خواهم بارکدها را اسکن کنم و فوراً باز شوند.</string>
<string name="camera_error">نمی‌توان به دوربین دسترسی داشت، لطفاً دوباره تلاش کنید</string>
<string name="scan_code">پویش کد</string>
<string name="compose_barcode">ایجاد بارکد</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN extension</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">روشن/خاموش کردن چراغ</string>
<string name="error_flash">خطا هنگام روشن/خاموش کردن چراغ</string>
<string name="share">هم‌رسانی</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">یک موتور جست‌وجو برگزینید</string>
<string name="format">قالب</string>
<string name="size_width_by_height">اندازه به پیکسل: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">محتویات ورودی را اینجا بنویسید</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">رمزگذاری</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">تأخیر بین پویش‌های مداوم</string>
<string name="restrict_format">محدود کردن قالب</string>
<string name="remove_restriction">برداشتن محدودیت</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">پویش %s</string>
<string name="quarter_second">یک‌چهارم ثانیه</string>
<string name="half_second">نیم ثانیه</string>
+16 -6
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Bienvenue !</string>
<string name="mode_expert">Avancé</string>
<string name="mode_expert_description">Je souhaite vérifier le contenu lu et l\'ouvrir manuellement.</string>
<string name="mode_simple">Simple</string>
<string name="mode_simple_description">Je veux simplement scanner les codes-barres et les ouvrir immédiatement.</string>
<string name="camera_error">Impossible d\'accéder à la caméra, veuillez réessayer</string>
<string name="scan_code">Scanner un code</string>
<string name="compose_barcode">Créer un code-barres</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">Extension UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Activer/Désactiver le flash</string>
<string name="error_flash">Erreur de changement d\'état du flash</string>
<string name="share">Partager</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Choisir un moteur de recherche</string>
<string name="format">Format</string>
<string name="size_width_by_height">Taille en pixels : %1$d×%2$d</string>
<string name="margin_size">Marge en pixels : %1$d</string>
<string name="size_no_magnification">Pas de grossissement</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Insérer le contenu ici</string>
<string name="unescape">Étendre les caractères d\'échappement</string>
<string name="encode">ENCODER</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Délai entre les scans continus</string>
<string name="restrict_format">Restreindre le format</string>
<string name="remove_restriction">Supprimer la restriction</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">Un quart de seconde</string>
<string name="half_second">Une demi-seconde</string>
@@ -106,8 +116,8 @@
<string name="show_meta_data_summary">Afficher des informations supplémentaires sur le code-barres scanné.</string>
<string name="show_hex_dump">Afficher le dump hexadécimal</string>
<string name="show_hex_dump_summary">Afficher le dump hexadécimal du contenu scanné.</string>
<string name="show_checksum">Show checksum</string>
<string name="no_checksum">No checksum</string>
<string name="show_checksum">Afficher la somme de contrôle</string>
<string name="no_checksum">Pas de somme de contrôle</string>
<string name="show_recreation">Afficher le code-barres recréé</string>
<string name="show_recreation_summary">Recréer et afficher, si possible, le code-barres à partir du contenu scanné.</string>
<string name="close_automatically">Revenir après une copie/partage</string>
@@ -138,9 +148,9 @@
<string name="bluetooth_connect_fail">Impossible de se connecter à l\'appareil Bluetooth.</string>
<string name="bluetooth_send_fail">Impossible d\'envoyer à l\'appareil Bluetooth.</string>
<string name="bluetooth_send_success">Envoi Bluetooth réussi.</string>
<string name="generation_category">Generation</string>
<string name="brighten_screen">Brighten screen</string>
<string name="brighten_screen_summary">Set brightness to maximum to enhance scanning a barcode from the screen.</string>
<string name="generation_category">Génération</string>
<string name="brighten_screen">Augmenter la luminosité de l\'écran</string>
<string name="brighten_screen_summary">Régler la luminosité au maximum pour améliorer la lecture d\'un code-barres à l\'écran.</string>
<string name="really_remove_scan">Supprimer le scan ?</string>
<string name="really_remove_all_scans">Supprimer tous les scans ?</string>
<string name="really_remove_selected_scans">Supprimer les scans sélectionnés ?</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Üdvözöljük!</string>
<string name="mode_expert">Haladó</string>
<string name="mode_expert_description">Szeretném ellenőrizni az olvasott tartalmat és kézzel megnyitni.</string>
<string name="mode_simple">Egyszerű</string>
<string name="mode_simple_description">Csak be akarom olvasni a vonalkódokat, és azonnal megnyitni őket.</string>
<string name="camera_error">Nem lehet hozzáférni a kamerához, próbálja meg újra</string>
<string name="scan_code">Kód beolvasása</string>
<string name="compose_barcode">Vonalkód létrehozása</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN kiterjesztés</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Vaku be- vagy kikapcsolása</string>
<string name="error_flash">Hiba a vaku be- vagy kikapcsolásakor</string>
<string name="share">Megosztás</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Válasszon keresőmotort</string>
<string name="format">Formátum</string>
<string name="size_width_by_height">Méret képpontban: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Itt adja meg a tartalmat</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">KÓDOLÁS</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Folyamatos beolvasások közti késleltetés</string>
<string name="restrict_format">Formátum korlátozása</string>
<string name="remove_restriction">Korlátozás eltávolítása</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">%s beolvasása</string>
<string name="quarter_second">Negyed másodperc</string>
<string name="half_second">Fél másodperc</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Selamat datang!</string>
<string name="mode_expert">Lanjutan</string>
<string name="mode_expert_description">Saya ingin memeriksa konten yang dibaca dan membukanya secara manual.</string>
<string name="mode_simple">Sederhana</string>
<string name="mode_simple_description">Saya hanya ingin memindai kode batang dan langsung membukanya.</string>
<string name="camera_error">Tidak bisa mengakses kamera, silakan coba lagi</string>
<string name="scan_code">Pindai kode</string>
<string name="compose_barcode">Buat barcode</string>
@@ -28,6 +33,7 @@
<string name="gtin_add_on">Ekstensi UPC EAN</string>
<string name="barcode_version_number">Versi</string>
<string name="qr_version_and_modules">%1$s (%2$d modul)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Nyala/matikan blitz</string>
<string name="error_flash">Galat nyala/matikan blitz</string>
<string name="share">Bagikan</string>
@@ -42,7 +48,8 @@
<string name="pick_search_engine">Pilih mesin pencari</string>
<string name="format">Format</string>
<string name="size_width_by_height">Ukuran dalam piksel: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Masukkan konten di sini</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">ENKODE</string>
@@ -56,6 +63,9 @@
<string name="bulk_mode_delay">Tundaan antara pemindaian tanpa henti</string>
<string name="restrict_format">Batasi format</string>
<string name="remove_restriction">Hapus pembatasan</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Pindai %s</string>
<string name="quarter_second">Seperempat detik</string>
<string name="half_second">Setengah detik</string>
+12 -2
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Benvenuto!</string>
<string name="mode_expert">Avanzato</string>
<string name="mode_expert_description">Voglio controllare il contenuto letto e aprirlo manualmente.</string>
<string name="mode_simple">Semplice</string>
<string name="mode_simple_description">Voglio solo scansionare codici a barre e aprirli immediatamente.</string>
<string name="camera_error">Impossibile accedere alla fotocamera. Riprova</string>
<string name="scan_code">Scansione codice</string>
<string name="compose_barcode">Crea codice a barre</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">Estensione UPC EAN</string>
<string name="barcode_version_number">Versione</string>
<string name="qr_version_and_modules">%1$s (%2$d moduli)</string>
<string name="qr_data_mask">Maschera dati</string>
<string name="toggle_flash">Attiva/disattiva flash</string>
<string name="error_flash">Errore durante attivazione/disattivazione flash</string>
<string name="share">Condividi</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Scegli motore di ricerca</string>
<string name="format">Formato</string>
<string name="size_width_by_height">Dimensioni (pixel): %1$d×%2$d</string>
<string name="margin_size">Margine (pixel): %1$d</string>
<string name="size_no_magnification">Nessun ingrandimento</string>
<string name="add_quiet_zone">Aggiungi zona tranquilla</string>
<string name="input_content_here">Inserisci qui il contenuto</string>
<string name="unescape">Espandi sequenze escape</string>
<string name="encode">CODIFICA</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Ritardo tra scansioni continue</string>
<string name="restrict_format">Limita formato</string>
<string name="remove_restriction">Rimuovi limitazione</string>
<string name="find_code">Trova codice</string>
<string name="find_code_with_content">Quale contenuto?</string>
<string name="find_code_hint">Inserisci un termine</string>
<string name="scan_format">Scansiona %s</string>
<string name="quarter_second">Un quarto di secondo</string>
<string name="half_second">Mezzo secondo</string>
@@ -105,7 +115,7 @@
<string name="show_meta_data">Visualizza metadati</string>
<string name="show_meta_data_summary">Visualizza dati aggiuntivi codice a barre scansionato.</string>
<string name="show_hex_dump">Visualizza dump esadecimale</string>
<string name="show_hex_dump_summary">Visualizza un dump esadecimale dei contenuti scansionati.</string>
<string name="show_hex_dump_summary">Visualizza dump esadecimale contenuti scansionati.</string>
<string name="show_checksum">Visualizza checksum</string>
<string name="no_checksum">Nessuna checksum</string>
<string name="show_recreation">Visualizza codice a barre ricreato</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">ようこそ!</string>
<string name="mode_expert">上級</string>
<string name="mode_expert_description">読み取った内容を確認し、手動で開きたい。</string>
<string name="mode_simple">簡単</string>
<string name="mode_simple_description">バーコードをスキャンしてすぐに開きたい。</string>
<string name="camera_error">カメラに接続できませんでした。再試行してください。</string>
<string name="scan_code">バーコードをスキャン</string>
<string name="compose_barcode">バーコードを作成</string>
@@ -28,6 +33,7 @@
<string name="gtin_add_on">UPC/EAN 拡張型</string>
<string name="barcode_version_number">バージョン</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">フラッシュの切り替え</string>
<string name="error_flash">フラッシュの切り替えエラー</string>
<string name="share">共有</string>
@@ -42,7 +48,8 @@
<string name="pick_search_engine">検索エンジンを選択</string>
<string name="format">フォーマット</string>
<string name="size_width_by_height">大きさ(ピクセル): %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">ここに内容を入力</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">エンコード</string>
@@ -56,6 +63,9 @@
<string name="bulk_mode_delay">連続スキャンの間隔</string>
<string name="restrict_format">フォーマットの制限</string>
<string name="remove_restriction">制限を解除</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">%sをスキャン</string>
<string name="quarter_second">0.25秒</string>
<string name="half_second">0.5秒</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">მოგესალმებით!</string>
<string name="mode_expert">გაფართოებული</string>
<string name="mode_expert_description">მინდა გადავამოწმო წაკითხული შინაარსი და გავხსნა ხელით.</string>
<string name="mode_simple">მარტივი</string>
<string name="mode_simple_description">მხოლოდ მინდა დავასკანერო ბარკოდი და გავხსნა დაუყოვნებლივ.</string>
<string name="camera_error">კამერაზე წვდომის მოპოვება ვერ ხერხდება, გთხოვთ, კიდევ სცადეთ</string>
<string name="scan_code">შტრიხ-კოდის სკანირება</string>
<string name="compose_barcode">შტრიხ-კოდის შექმნა</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN გაფართოება</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">განათების ჩართვა</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">გაზიარება</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">აირჩიეთ საძიებო სისტემა</string>
<string name="format">ფორმატი</string>
<string name="size_width_by_height">ზომა პიქსელებში: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">შეიყვანეთ ტექსტი აქ</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">შექმნა"</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Delay between continuous scans</string>
<string name="restrict_format">Restrict format</string>
<string name="remove_restriction">Remove restriction</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">A quarter second</string>
<string name="half_second">Half a second</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">환영합니다!</string>
<string name="mode_expert">고급</string>
<string name="mode_expert_description">읽은 내용을 확인하고 수동으로 열고 싶습니다.</string>
<string name="mode_simple">간단</string>
<string name="mode_simple_description">바코드를 스캔하고 즉시 열고 싶습니다.</string>
<string name="camera_error">카메라를 접근할 수 없습니다. 다시 시도하세요</string>
<string name="scan_code">Scan code</string>
<string name="compose_barcode">Compose barcode</string>
@@ -28,6 +33,7 @@
<string name="gtin_add_on">UPC EAN extension</string>
<string name="barcode_version_number">버전</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Toggle flash</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Share</string>
@@ -42,7 +48,8 @@
<string name="pick_search_engine">Pick a search engine</string>
<string name="format">Format</string>
<string name="size_width_by_height">Size in pixels: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Input content here</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">ENCODE</string>
@@ -56,6 +63,9 @@
<string name="bulk_mode_delay">Delay between continuous scans</string>
<string name="restrict_format">Restrict format</string>
<string name="remove_restriction">Remove restriction</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">A quarter second</string>
<string name="half_second">Half a second</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Welkom!</string>
<string name="mode_expert">Geavanceerd</string>
<string name="mode_expert_description">Ik wil de gelezen inhoud controleren en handmatig openen.</string>
<string name="mode_simple">Eenvoudig</string>
<string name="mode_simple_description">Ik wil gewoon barcodes scannen en direct openen.</string>
<string name="camera_error">Geen toegang tot camera, probeer opnieuw.</string>
<string name="scan_code">Scan een code</string>
<string name="compose_barcode">Barcode scannen</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN extensie</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Zaklamp aan/uit</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Delen</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Zoekmachine kiezen</string>
<string name="format">Format</string>
<string name="size_width_by_height">Afmeting in pixels: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Voer hier de inhoud in</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">Coderen</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Vertraging tussen ononderbroken scans</string>
<string name="restrict_format">Restrict format</string>
<string name="remove_restriction">Remove restriction</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">¼ seconde</string>
<string name="half_second">½ seconde</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Witamy!</string>
<string name="mode_expert">Zaawansowany</string>
<string name="mode_expert_description">Chcę sprawdzić odczytaną treść i otworzyć ją ręcznie.</string>
<string name="mode_simple">Prosty</string>
<string name="mode_simple_description">Chcę tylko skanować kody kreskowe i otwierać je natychmiast.</string>
<string name="open_url">Otwórz URL</string>
<string name="content">Zawartość</string>
<string name="copied_to_clipboard">Skopiowano do schowka</string>
@@ -90,6 +95,9 @@
<string name="bulk_mode_delay">Opóźnienie między kolejnymi skanami</string>
<string name="restrict_format">Ogranicz format</string>
<string name="remove_restriction">Usuń ograniczenie</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Skan %s</string>
<string name="quarter_second">Ćwierć sekundy</string>
<string name="half_second">Pół sekundy</string>
@@ -176,6 +184,7 @@
<string name="gtin_add_on">Dodatek UPC EAN</string>
<string name="barcode_version_number">Wersja</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="gtin_country">Możliwy kraj produkcji</string>
<string name="encode">ZAKODUJ</string>
<string name="error_no_content">Brak zawartości</string>
@@ -185,7 +194,8 @@
<string name="show_toast_in_bulk_mode_summary">Zwięźle pokazuje zeskanowane dane podczas skanowania ciągłego.</string>
<string name="cannot_resolve_action">Żadna aplikacja nie może tego otworzyć</string>
<string name="size_width_by_height">Rozmiar w pikselach: %1$d×%2$d</string>
<string name="margin_size">Margines w pikselach: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Wprowadź zawartość tutaj</string>
<string name="unescape">Rozwiń sekwencje ucieczki</string>
<string name="pick_list_separator">Jak oddzielić elementy listy?</string>
+24 -15
View File
@@ -1,13 +1,17 @@
<resources>
<string name="welcome">Bem-vindo!</string>
<string name="mode_expert">Avançado</string>
<string name="mode_expert_description">Quero verificar o conteúdo lido e abri-lo manualmente.</string>
<string name="mode_simple">Simples</string>
<string name="mode_simple_description">Quero apenas ler códigos de barras e abri-los imediatamente.</string>
<string name="camera_error">Não foi possível acessar a câmera, tente novamente</string>
<string name="scan_code">Leia o código</string>
<string name="scan_code">Escanear código</string>
<string name="compose_barcode">Compor código de barras</string>
<string name="decode_barcode">Decodificar código de barras</string>
<string name="content">Conteúdo</string>
<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 caracteres, %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>
@@ -30,6 +34,7 @@
<string name="gtin_add_on">Extensão UPC EAN</string>
<string name="barcode_version_number">Versão</string>
<string name="qr_version_and_modules">%1$s (%2$d módulos)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Ligar lanterna</string>
<string name="error_flash">Falha ao ligar a lanterna</string>
<string name="share">Compartilhar</string>
@@ -44,7 +49,8 @@
<string name="pick_search_engine">Escolha um motor de pesquisa</string>
<string name="format">Formato</string>
<string name="size_width_by_height">Tamanho em pixels: %1$d×%2$d</string>
<string name="margin_size">Margem em pixels: %1$d</string>
<string name="size_no_magnification">Sem magnificação</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Digite algum conteúdo aqui</string>
<string name="unescape">Expandir sequências de escape</string>
<string name="encode">CODIFICAR</string>
@@ -52,12 +58,15 @@
<string name="error_encoding_barcode">Código de barras não pode ser gerado</string>
<string name="view_barcode">Ver código de barras</string>
<string name="info">Informações</string>
<string name="switch_camera">Alterar câmera</string>
<string name="switch_camera">Trocar câmera</string>
<string name="bulk_mode">Digitalizar continuamente</string>
<string name="bulk_mode_summary">Sempre iniciar digitalizando continuamente.</string>
<string name="bulk_mode_delay">Delay entre digitalizações contínuas</string>
<string name="bulk_mode_delay">Espera entre digitalizações contínuas</string>
<string name="restrict_format">Restringir formato</string>
<string name="remove_restriction">Remover restrição</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Digitalizar %s</string>
<string name="quarter_second">Um quarto de segundo</string>
<string name="half_second">Meio segundo</string>
@@ -84,8 +93,8 @@
<string name="show_toast_in_bulk_mode_summary">Mostrar brevemente os dados durante digitalização contínua.</string>
<string name="vibrate">Vibrar ao detectar</string>
<string name="vibrate_summary">Ative esta opção se quiser que seu dispositivo vibre ao reconhecer um código.</string>
<string name="beep">Fazer um \'beep\' ao reconhecer</string>
<string name="beep_summary">Ative esta opção se quiser se quer que seu dispositivo faça um \'beep\' ao reconhecer um código.</string>
<string name="beep">Tocar um \'beep\' ao reconhecer</string>
<string name="beep_summary">Ative esta opção se quiser se quer que seu dispositivo faça um som de \'beep\' ao reconhecer um código.</string>
<string name="beep_tone">Tom do beep</string>
<string name="tone_cdma_confirm">Confirmação CDMA</string>
<string name="tone_sup_confirm">Confirmação de supervisão de chamada</string>
@@ -95,12 +104,12 @@
<string name="tone_prop_beep2">Duplo beep comum</string>
<string name="use_history">Salvar histórico de digitalizações</string>
<string name="use_history_summary">Salve códigos reconhecidos em seu dispositivo.</string>
<string name="ignore_duplicates">Ignorar duplicaçõe</string>
<string name="ignore_consecutive_duplicates">Duplicações consecutivas</string>
<string name="ignore_any_duplicates">Qualquer duplicação</string>
<string name="accept_duplicates">Aceitar duplicações</string>
<string name="ignore_duplicates">Ignorar duplicata</string>
<string name="ignore_consecutive_duplicates">Duplicatas consecutivas</string>
<string name="ignore_any_duplicates">Quaisquer duplicatas</string>
<string name="accept_duplicates">Aceitar duplicatas</string>
<string name="open_immediately">Abrir imediatamente</string>
<string name="open_immediately_summary">Pular a inspeção e abrir um conteúdo instantaneamente. Quando ativado, pode abrir conteúdo malicioso.</string>
<string name="open_immediately_summary">Pular a inspeção e abrir um conteúdo instantaneamente. Pode abrir conteúdo malicioso se ativado.</string>
<string name="copy_immediately">Botar na área de transferência</string>
<string name="copy_immediately_summary">Copiar automaticamente para a área de transferência o conteúdo digitalizado. Note que outros apps podem examinar sua área de transferência em segundo plano.</string>
<string name="show_meta_data">Mostrar metadados</string>
@@ -139,9 +148,9 @@
<string name="bluetooth_connect_fail">Não foi possível conectar com o dispositivo Bluetooth.</string>
<string name="bluetooth_send_fail">Não foi possível enviar para o dispositivo Bluetooth.</string>
<string name="bluetooth_send_success">Envio Bluetooth com sucesso.</string>
<string name="generation_category">Generation</string>
<string name="brighten_screen">Brighten screen</string>
<string name="brighten_screen_summary">Set brightness to maximum to enhance scanning a barcode from the screen.</string>
<string name="generation_category">Geração</string>
<string name="brighten_screen">Clarear tela</string>
<string name="brighten_screen_summary">Aumente o brilho do monitor para melhorar a leitura do código de barras.</string>
<string name="really_remove_scan">Deseja excluir esta digitalização?</string>
<string name="really_remove_all_scans">Deseja excluir todas as digitalizações?</string>
<string name="really_remove_selected_scans">Deseja excluir as digitalizações selecionadas?</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Добро пожаловать!</string>
<string name="mode_expert">Продвинутый</string>
<string name="mode_expert_description">Я хочу проверить прочитанный контент и открыть его вручную.</string>
<string name="mode_simple">Простой</string>
<string name="mode_simple_description">Я просто хочу сканировать штрихкоды и сразу их открывать.</string>
<string name="camera_error">Невозможно получить доступ к камере, попробуйте ещё раз</string>
<string name="scan_code">Сканировать штрих-код</string>
<string name="compose_barcode">Создать штрих-код</string>
@@ -31,6 +36,7 @@
<string name="gtin_add_on">Расширение UPC EAN</string>
<string name="barcode_version_number">Версия</string>
<string name="qr_version_and_modules">%1$s (модули: %2$d)</string>
<string name="qr_data_mask">Маска данных</string>
<string name="toggle_flash">Включить вспышку</string>
<string name="error_flash">Ошибка при переключении вспышки</string>
<string name="share">Поделиться</string>
@@ -45,7 +51,8 @@
<string name="pick_search_engine">Выберите поисковую систему</string>
<string name="format">Формат</string>
<string name="size_width_by_height">Размер в пикселях: %1$d×%2$d</string>
<string name="margin_size">Отступ в пикселях: %1$d</string>
<string name="size_no_magnification">Без увеличения</string>
<string name="add_quiet_zone">Добавить отступы</string>
<string name="input_content_here">Введите текст здесь</string>
<string name="unescape">Раскрывать управляющие последовательности</string>
<string name="encode">Создать</string>
@@ -59,6 +66,9 @@
<string name="bulk_mode_delay">Задержка непрерывного сканирования</string>
<string name="restrict_format">Исключить формат</string>
<string name="remove_restriction">Включить формат</string>
<string name="find_code">Поиск кода</string>
<string name="find_code_with_content">Что искать?</string>
<string name="find_code_hint">Введите поисковый запрос</string>
<string name="scan_format">Сканировать %s</string>
<string name="quarter_second">Четверть секунды</string>
<string name="half_second">Полсекунды</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Hoş geldiniz!</string>
<string name="mode_expert">Gelişmiş</string>
<string name="mode_expert_description">Okunan içeriği kontrol etmek ve manuel olarak açmak istiyorum.</string>
<string name="mode_simple">Basit</string>
<string name="mode_simple_description">Barkodları taramak ve hemen açmak istiyorum.</string>
<string name="camera_error">Kameraya erişilemiyor, lütfen yeniden deneyin</string>
<string name="scan_code">Kod tara</string>
<string name="compose_barcode">Barkod oluştur</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN eklentisi</string>
<string name="barcode_version_number">Sürüm</string>
<string name="qr_version_and_modules">%1$s (%2$d modül)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Flaşı aç</string>
<string name="error_flash">Flaş açılırken hata oluştu</string>
<string name="share">Paylaş</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Arama motoru seç</string>
<string name="format">Biçim</string>
<string name="size_width_by_height">Piksel türünde boyut: %1$d×%2$d</string>
<string name="margin_size">Piksel türünde kenar boşluğu: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">İçeriği buraya gir</string>
<string name="unescape">Kaçış dizilerini genişlet</string>
<string name="encode">KODLA</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Sürekli taramalar arasındaki gecikme</string>
<string name="restrict_format">Biçimi kısıtla</string>
<string name="remove_restriction">Kısıtlamayı kaldır</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">%s tara</string>
<string name="quarter_second">Çeyrek saniye</string>
<string name="half_second">Yarım saniye</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Ласкаво просимо!</string>
<string name="mode_expert">Розширений</string>
<string name="mode_expert_description">Я хочу перевірити прочитаний вміст і відкрити його вручну.</string>
<string name="mode_simple">Простий</string>
<string name="mode_simple_description">Я просто хочу сканувати штрих-коди і відкривати їх одразу.</string>
<string name="camera_error">Неможливо отримати доступ до камери, будь ласка, спробуйте ще раз</string>
<string name="scan_code">Сканування коду</string>
<string name="compose_barcode">Створити штрих-код</string>
@@ -30,6 +35,7 @@
<string name="gtin_add_on">Розширення UPC EAN</string>
<string name="barcode_version_number">Версія</string>
<string name="qr_version_and_modules">%1$s (%2$d модулі)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Увімкнути спалах</string>
<string name="error_flash">Помилка під час увімкнення спалаху</string>
<string name="share">Поділитися</string>
@@ -44,7 +50,8 @@
<string name="pick_search_engine">Вибрати пошукову систему</string>
<string name="format">Формат</string>
<string name="size_width_by_height">Розмір у пікселях: %1$d×%2$d</string>
<string name="margin_size">Відступ у пікселях: %1$d</string>
<string name="size_no_magnification">Без збільшення</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Введіть вміст сюди</string>
<string name="unescape">Розгорнути спеціальні послідовності</string>
<string name="encode">КОДУВАТИ</string>
@@ -58,6 +65,9 @@
<string name="bulk_mode_delay">Затримка між безперервним скануванням</string>
<string name="restrict_format">Обмежити формат</string>
<string name="remove_restriction">Скасувати обмеження</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Сканувати %s</string>
<string name="quarter_second">Чверть секунди</string>
<string name="half_second">Півсекунди</string>
+3
View File
@@ -0,0 +1,3 @@
<resources>
<bool name="fitsSystemWindows">false</bool>
</resources>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">Chào mừng!</string>
<string name="mode_expert">Nâng cao</string>
<string name="mode_expert_description">Tôi muốn kiểm tra nội dung đã đọc và mở nó theo cách thủ công.</string>
<string name="mode_simple">Đơn giản</string>
<string name="mode_simple_description">Tôi chỉ muốn quét mã vạch và mở ngay lập tức.</string>
<string name="camera_error">Không thể mở camera, hãy thử lại</string>
<string name="scan_code">Quét mã</string>
<string name="compose_barcode">Tạo mã vạch</string>
@@ -28,6 +33,7 @@
<string name="gtin_add_on">Phần mở rộng UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Bật/tắt đèn</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Chia sẻ</string>
@@ -42,7 +48,8 @@
<string name="pick_search_engine">Chọn một trình tìm kiếm</string>
<string name="format">Định dạng</string>
<string name="size_width_by_height">Kích cỡ theo pixel: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Nhập nội dung vào đây</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">MÃ HOÁ</string>
@@ -56,6 +63,9 @@
<string name="bulk_mode_delay">Thời gian giữa các lần quét</string>
<string name="restrict_format">Restrict format</string>
<string name="remove_restriction">Remove restriction</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">Một phần tư giây</string>
<string name="half_second">Nửa giây</string>
+14 -4
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">欢迎!</string>
<string name="mode_expert">高级</string>
<string name="mode_expert_description">我想检查读取的内容并手动打开。</string>
<string name="mode_simple">简单</string>
<string name="mode_simple_description">我只想扫描条形码并立即打开。</string>
<string name="camera_error">无法访问相机,请重试</string>
<string name="scan_code">扫码</string>
<string name="compose_barcode">生成条码</string>
@@ -28,6 +33,7 @@
<string name="gtin_add_on">UPC EAN 扩展</string>
<string name="barcode_version_number">版本</string>
<string name="qr_version_and_modules">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">开关闪光灯</string>
<string name="error_flash">开关闪光灯出错</string>
<string name="share">分享</string>
@@ -42,7 +48,8 @@
<string name="pick_search_engine">选择一个搜索引擎</string>
<string name="format">编码格式</string>
<string name="size_width_by_height">图片尺寸: %1$d×%2$d</string>
<string name="margin_size">边距(像素):%1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">在这里输入内容</string>
<string name="unescape">展开转义字符</string>
<string name="encode">编码</string>
@@ -56,6 +63,9 @@
<string name="bulk_mode_delay">连续扫描之间的延迟</string>
<string name="restrict_format">严格模式(扫描指定编码格式)</string>
<string name="remove_restriction">解除限制</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">扫描 %s</string>
<string name="quarter_second">四分之一秒</string>
<string name="half_second">半秒</string>
@@ -137,9 +147,9 @@
<string name="bluetooth_connect_fail">无法连接蓝牙设备。</string>
<string name="bluetooth_send_fail">无法将结果发送至蓝牙设备。</string>
<string name="bluetooth_send_success">已通过蓝牙发送。</string>
<string name="generation_category">Generation</string>
<string name="brighten_screen">Brighten screen</string>
<string name="brighten_screen_summary">Set brightness to maximum to enhance scanning a barcode from the screen.</string>
<string name="generation_category">生成</string>
<string name="brighten_screen">点亮屏幕</string>
<string name="brighten_screen_summary">将屏幕亮度设为最大,以增强从屏幕扫描的效果。</string>
<string name="really_remove_scan">确定删除记录?</string>
<string name="really_remove_all_scans">确定删除全部记录?</string>
<string name="really_remove_selected_scans">确定删除所选记录?</string>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources>
<string name="welcome">歡迎!</string>
<string name="mode_expert">進階</string>
<string name="mode_expert_description">我想檢查讀取的內容並手動開啟。</string>
<string name="mode_simple">簡單</string>
<string name="mode_simple_description">我只想掃描條碼並立即開啟。</string>
<string name="camera_error">無法開啟相機,請再試一次</string>
<string name="scan_code">掃描條碼</string>
<string name="compose_barcode">製作條碼</string>
@@ -28,6 +33,7 @@
<string name="gtin_add_on">UPC EAN 擴充</string>
<string name="barcode_version_number">版本</string>
<string name="qr_version_and_modules">%1$s (%2$d 模組)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">控制閃光燈</string>
<string name="error_flash">控制閃光燈時發生錯誤</string>
<string name="share">分享</string>
@@ -42,7 +48,8 @@
<string name="pick_search_engine">選擇一個搜尋引擎</string>
<string name="format">格式</string>
<string name="size_width_by_height">圖片尺寸: %1$d×%2$d</string>
<string name="margin_size">間距大小: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">請在這裡輸入內容</string>
<string name="unescape">展開逸出序列</string>
<string name="encode">編碼</string>
@@ -56,6 +63,9 @@
<string name="bulk_mode_delay">連續掃描間的延遲</string>
<string name="restrict_format">限制格式</string>
<string name="remove_restriction">刪除限制</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">掃描 %s</string>
<string name="quarter_second">四分之一秒</string>
<string name="half_second">半秒</string>
+3
View File
@@ -0,0 +1,3 @@
<resources>
<bool name="fitsSystemWindows">true</bool>
</resources>
+11 -1
View File
@@ -1,4 +1,9 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="welcome">Welcome!</string>
<string name="mode_expert">Advanced</string>
<string name="mode_expert_description">I would like to check the read content and open it manually.</string>
<string name="mode_simple">Simple</string>
<string name="mode_simple_description">I just want to read barcodes and have them opened immediately.</string>
<string name="camera_error">Can\'t access camera, please try again</string>
<string name="scan_code">Scan code</string>
<string name="compose_barcode">Compose barcode</string>
@@ -29,6 +34,7 @@
<string name="gtin_add_on">UPC EAN extension</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules" tools:ignore="PluralsCandidate">%1$s (%2$d modules)</string>
<string name="qr_data_mask">Data mask</string>
<string name="toggle_flash">Toggle flash</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Share</string>
@@ -43,7 +49,8 @@
<string name="pick_search_engine">Pick a search engine</string>
<string name="format">Format</string>
<string name="size_width_by_height">Size in pixels: %1$d×%2$d</string>
<string name="margin_size">Margin in pixels: %1$d</string>
<string name="size_no_magnification">No magnification</string>
<string name="add_quiet_zone">Add quiet zone</string>
<string name="input_content_here">Input content here</string>
<string name="unescape">Expand escape sequences</string>
<string name="encode">ENCODE</string>
@@ -57,6 +64,9 @@
<string name="bulk_mode_delay">Delay between continuous scans</string>
<string name="restrict_format">Restrict format</string>
<string name="remove_restriction">Remove restriction</string>
<string name="find_code">Find code</string>
<string name="find_code_with_content">What content?</string>
<string name="find_code_hint">Enter a term</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">A quarter second</string>
<string name="half_second">Half a second</string>
+20
View File
@@ -26,6 +26,26 @@
<item name="android:paddingRight">@dimen/button_padding</item>
<item name="android:maxLines">1</item>
</style>
<style name="WelcomeButton" parent="Button">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">@drawable/button_welcome</item>
<item name="android:padding">24dp</item>
</style>
<style name="WelcomeButtonText">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginBottom">8dp</item>
<item name="android:gravity">center</item>
<item name="android:textStyle">bold</item>
<item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
</style>
<style name="WelcomeButtonSubText">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:gravity">center</item>
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
</style>
<style name="Spinner">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
@@ -6,25 +6,25 @@ import org.junit.Test
class EscapeTest {
@Test
fun oneLetter() {
assertEquals("foo\\nbar".unescape(), "foo\nbar")
assertEquals("foo\\tbar".unescape(), "foo\tbar")
assertEquals("\\tfoo\\tbar\\n".unescape(), "\tfoo\tbar\n")
assertEquals("foo\nbar", "foo\\nbar".unescape())
assertEquals("foo\tbar", "foo\\tbar".unescape())
assertEquals("\tfoo\tbar\n", "\\tfoo\\tbar\\n".unescape())
}
@Test
fun specialChars() {
assertEquals("foo\\\\bar".unescape(), "foo\\bar")
assertEquals("foo\\\"bar".unescape(), "foo\"bar")
assertEquals("foo\\bar", "foo\\\\bar".unescape())
assertEquals("foo\"bar", "foo\\\"bar".unescape())
}
@Test
fun hexCode() {
assertEquals("\\x48\\x65\\x78".unescape(), "Hex")
assertEquals("\\u263A".unescape(), "")
assertEquals("Hex", "\\x48\\x65\\x78".unescape())
assertEquals("", "\\u263A".unescape())
}
@Test
fun incomplete() {
assertEquals("foo\\".unescape(), "foo\\")
assertEquals("foo\\", "foo\\".unescape())
}
}
+3 -3
View File
@@ -1,8 +1,8 @@
buildscript {
ext {
kotlin_version = '1.9.22'
tools_version = '8.4.1'
sdk_version = 34
kotlin_version = '2.1.0'
tools_version = '8.8.1'
sdk_version = 35
support_version = '25.3.1'
}
@@ -0,0 +1,4 @@
* Update parcel tracking URL
* Update multiple translations
* Only ask for barcode size when exporting/sharing
@@ -0,0 +1,2 @@
* Fix magnifying barcode recreation
@@ -0,0 +1,9 @@
* Find barcode by content
* Immediately replace toasts
* Use detected barcode for recreation
* Show data mask of QR Codes
* Fix deep linking
* Replace margin with quiet zone switch when generating barcodes
* Update Russian translation
* Update Portuguese (Brazil) translation
@@ -0,0 +1,3 @@
* Handle empty input for recreation
* Fix setting up database
@@ -0,0 +1,4 @@
* Separate crop window settings for image scanning
* Fix initializing dataMask
* Update Russian translation
@@ -0,0 +1,6 @@
* Add a welcome screen to choose a mode
* Add a deep link to encode a barcode
* Remember zoom level of generated barcodes
* Remove Human Readable Interpretation (HRI) decoration
* Update Italian translation
@@ -0,0 +1,2 @@
* Consertado pré-processamento para Android 7+
* Consertados ícones adaptativos para Android 8+
@@ -1 +1 @@
Mais um leitor de códigos QR para Android. Sem anúncios e de software livre.
Mais um leitor de códigos QR para Android. Sem anúncios e de código-aberto.
+1 -1
View File
@@ -1 +1 @@
Mais um leitor de códigos QR etc
Mais um leitor de códigos QR
+1 -1
View File
@@ -1,6 +1,6 @@
#Wed Jan 26 11:58:22 CET 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
distributionPath=wrapper/dists
networkTimeout=10000
zipStorePath=wrapper/dists