Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6999f0a863 | ||
|
|
6574a5d651 | ||
|
|
1639e73738 | ||
|
|
68fa67f54f | ||
|
|
326c34b6c1 | ||
|
|
a43dca3644 | ||
|
|
168ccf7d10 | ||
|
|
a9630b4d53 | ||
|
|
4a138bd425 | ||
|
|
339ff59270 | ||
|
|
d208ec12bc | ||
|
|
893ddefa71 | ||
|
|
5d56365e79 | ||
|
|
3237467503 | ||
|
|
346529469c | ||
|
|
9f4e420dbb | ||
|
|
cf4020c613 | ||
|
|
93edde7ed1 | ||
|
|
362e462c2a | ||
|
|
a7241bc0fb | ||
|
|
f26046f34b | ||
|
|
a70813ea5c | ||
|
|
3f251fdb66 | ||
|
|
b76cf329dd | ||
|
|
e0ad177a62 | ||
|
|
1223bd3679 | ||
|
|
b4e24fa328 | ||
|
|
0368ab5f68 | ||
|
|
c44ee8f063 | ||
|
|
3bfa6345a0 | ||
|
|
77d87ba995 | ||
|
|
a2ac68028f | ||
|
|
aeb945f145 | ||
|
|
aadde397ea | ||
|
|
063fea913e | ||
|
|
9d57889b81 | ||
|
|
233b69623f | ||
|
|
c7d6e60efb | ||
|
|
63688a9994 | ||
|
|
dc74e33b8b | ||
|
|
81f2620a69 | ||
|
|
1c95550f5d | ||
|
|
37a821818d | ||
|
|
29e0bdfbc3 | ||
|
|
d4bbcef011 | ||
|
|
81fc41ea81 | ||
|
|
8cadf42c86 | ||
|
|
e29ec2cc40 | ||
|
|
05952e7f7f | ||
|
|
0e8abb4607 | ||
|
|
cede9186a2 | ||
|
|
c1c9fa050b | ||
|
|
76d86288cc | ||
|
|
c0902f8830 | ||
|
|
1d3546d676 | ||
|
|
58baab6ffd | ||
|
|
3bafa60d59 | ||
|
|
825062ba78 | ||
|
|
d128e3cc24 | ||
|
|
83619834a8 | ||
|
|
cb16220ebb | ||
|
|
7f3af23773 |
@@ -1,5 +1,41 @@
|
||||
# Change Log
|
||||
|
||||
# 1.22.2
|
||||
* Fix getting window insets for Android Lollipop and above
|
||||
|
||||
# 1.22.1
|
||||
* Ensure non-printable content is saved as raw data
|
||||
|
||||
# 1.22.0
|
||||
* Highlight detected barcodes in camera view
|
||||
* Add bing and yandex search engines
|
||||
* Update Chinese Translation
|
||||
* Update Italian translation
|
||||
* Update Indonesian translation
|
||||
|
||||
# 1.21.0
|
||||
* Save and restore history list state
|
||||
* Improve scanning from large images
|
||||
* Fix opening image files by "Open with"
|
||||
|
||||
# 1.20.1
|
||||
* Fix window insets below Android Lollipop
|
||||
|
||||
# 1.20.0
|
||||
* Scroll content below tool and system bars
|
||||
* Preset file name to save with format and content
|
||||
* Add encode menu item to make encoding easier when keyboard is visible
|
||||
* Increase font size of barcode contents in history
|
||||
* Update Hungarian translation
|
||||
* Update Indonesian translation
|
||||
* Fix encoding for old Androids
|
||||
* Fix returning result for ZXing's SCAN intent again
|
||||
* Fix transfering barcode format from history
|
||||
|
||||
# 1.19.0
|
||||
* Allow scaling a new barcode to half its size
|
||||
* Remember last selected barcode format
|
||||
|
||||
# 1.18.0
|
||||
* Make open URL default action after decoding a barcode
|
||||
* Add a setting to open contents without inspection
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ to squash when merging into master:
|
||||
|
||||
$ git merge cool_feature --squash
|
||||
|
||||
Then write a [good commit messages][commit_messages] to keep the history
|
||||
Then write a [good commit message][commit_messages] to keep the history
|
||||
meaningful and useful. One feature, one commit.
|
||||
|
||||
[android_best_practices]: https://developer.android.com/distribute/best-practices/develop/
|
||||
|
||||
@@ -2,15 +2,51 @@
|
||||
|
||||
Yet another barcode scanner for Android. As if there weren't [enough][play].
|
||||
|
||||
This one is totally free, open source and does use the [ZXing][zxing] barcode
|
||||
scanning library.
|
||||
This one is free, without any ads and open source.
|
||||
|
||||
Unlike many others, it works in portrait and landscape orientation, can read
|
||||
inverted codes, comes in Material Design and doesn't do much else but decoding
|
||||
a barcode.
|
||||
Works in portrait and landscape orientation, can read inverted codes,
|
||||
comes in Material Design and can also generate barcodes.
|
||||
|
||||
And it's written in [Kotlin][kotlin] because I wanted to explore that a
|
||||
bit more.
|
||||
Binary Eye uses the [ZXing][zxing] ("Zebra Crossing") barcode scanning
|
||||
library.
|
||||
|
||||
## Supported Barcode Formats
|
||||
|
||||
### Read
|
||||
|
||||
ZXing can _read_ the following barcode formats:
|
||||
* [AZTEC][aztec]
|
||||
* [CODABAR][codabar]
|
||||
* [CODE 39][code_39]
|
||||
* [CODE 93][code_93]
|
||||
* [CODE 128][code_128]
|
||||
* [DATA MATRIX][data_matrix]
|
||||
* [EAN 8][ean_8]
|
||||
* [EAN 13][ean_13]
|
||||
* [ITF][itf]
|
||||
* [MAXICODE][maxicode]
|
||||
* [PDF417][pdf417]
|
||||
* [QR CODE][qr_code]
|
||||
* [RSS 14][rss]
|
||||
* [RSS EXPANDED][rss]
|
||||
* [UPC A][upc_a]
|
||||
* [UPC E][upc_e]
|
||||
* [UPC EAN EXTENSION][upc_ean]
|
||||
|
||||
### Generate
|
||||
|
||||
ZXing can _generate_ the following barcode formats:
|
||||
* [AZTEC][aztec]
|
||||
* [CODABAR][codabar]
|
||||
* [CODE 39][code_39]
|
||||
* [CODE 128][code_128]
|
||||
* [DATA MATRIX][data_matrix]
|
||||
* [EAN 8][ean_8]
|
||||
* [EAN 13][ean_13]
|
||||
* [ITF][itf]
|
||||
* [PDF 417][pdf417]
|
||||
* [QR CODE][qr_code]
|
||||
* [UPC A][upc_a]
|
||||
|
||||
## Screenshots
|
||||
|
||||
@@ -31,3 +67,19 @@ bit more.
|
||||
[play]: https://play.google.com/store/search?q=barcode%20scanner&c=apps
|
||||
[zxing]: https://github.com/zxing/zxing
|
||||
[kotlin]: http://kotlinlang.org/
|
||||
[aztec]: https://en.wikipedia.org/wiki/Aztec_Code
|
||||
[codabar]: https://en.wikipedia.org/wiki/Codabar
|
||||
[code_39]: https://en.wikipedia.org/wiki/Code_39
|
||||
[code_93]: https://en.wikipedia.org/wiki/Code_93
|
||||
[code_128]: https://en.wikipedia.org/wiki/Code_128
|
||||
[data_matrix]: https://en.wikipedia.org/wiki/Data_Matrix
|
||||
[ean_8]: https://en.wikipedia.org/wiki/EAN-8
|
||||
[ean_13]: https://en.wikipedia.org/wiki/International_Article_Number
|
||||
[itf]: https://en.wikipedia.org/wiki/Interleaved_2_of_5
|
||||
[maxicode]: https://en.wikipedia.org/wiki/MaxiCode
|
||||
[pdf417]: https://en.wikipedia.org/wiki/PDF417
|
||||
[qr_code]: https://en.wikipedia.org/wiki/QR_code
|
||||
[rss]: https://en.wikipedia.org/wiki/GS1_DataBar
|
||||
[upc_a]: https://en.wikipedia.org/wiki/Universal_Product_Code
|
||||
[upc_e]: https://en.wikipedia.org/wiki/Universal_Product_Code#UPC-E
|
||||
[upc_ean]: https://en.wikipedia.org/wiki/Universal_Product_Code#EAN-13
|
||||
|
||||
+7
-5
@@ -9,8 +9,8 @@ android {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion sdk_version
|
||||
|
||||
versionCode 46
|
||||
versionName '1.18.0'
|
||||
versionCode 54
|
||||
versionName '1.22.2'
|
||||
|
||||
// it's recommended to set this value to the lowest API level
|
||||
// able to provide all the functionality
|
||||
@@ -18,6 +18,8 @@ android {
|
||||
renderscriptSupportModeEnabled true
|
||||
|
||||
testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
|
||||
|
||||
buildConfigField 'boolean', 'IS_CATALINA', is_catalina.toString()
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
@@ -58,10 +60,10 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
androidTestImplementation ('com.android.support.test:runner:1.0.2') {
|
||||
androidTestImplementation('com.android.support.test:runner:1.0.2') {
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
androidTestImplementation ('com.android.support.test:rules:1.0.2') {
|
||||
androidTestImplementation('com.android.support.test:rules:1.0.2') {
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
testImplementation 'junit:junit:4.12'
|
||||
@@ -74,5 +76,5 @@ dependencies {
|
||||
// https://github.com/zxing/zxing/issues/1170
|
||||
implementation 'com.google.zxing:core:3.3.3'
|
||||
implementation 'com.github.markusfisch:CameraView:1.8.4'
|
||||
implementation 'com.github.markusfisch:ScalingImageView:1.1.4'
|
||||
implementation 'com.github.markusfisch:ScalingImageView:1.2.0'
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,10 +3,10 @@
|
||||
<!-- Lint can't understand Kotlin sources and reports all resources
|
||||
as unused -->
|
||||
<issue id="UnusedResources">
|
||||
<ignore path="src/main/res/"/>
|
||||
<ignore path="src/main/res/" />
|
||||
</issue>
|
||||
<!-- Ignore RenderScript output -->
|
||||
<issue id="UnusedResources">
|
||||
<ignore path="*/res/rs/debug/raw/bc*"/>
|
||||
<ignore path="*/res/rs/debug/raw/bc*" />
|
||||
</issue>
|
||||
</lint>
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:name=".app.BinaryEyeApp"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="true"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:supportsRtl="true"
|
||||
android:resizeableActivity="true"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:theme="@style/AppTheme">
|
||||
@@ -54,7 +55,8 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.PickActivity"
|
||||
android:label="@string/pick_code_to_scan">
|
||||
android:label="@string/pick_code_to_scan"
|
||||
tools:ignore="AppLinkUrlError">
|
||||
<intent-filter android:label="@string/decode_barcode">
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
@@ -63,7 +65,7 @@
|
||||
<intent-filter android:label="@string/decode_barcode">
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="image/*" android:scheme="file"/>
|
||||
<data android:mimeType="image/*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
|
||||
@@ -22,7 +22,10 @@ import de.markusfisch.android.binaryeye.app.db
|
||||
import de.markusfisch.android.binaryeye.app.hasCameraPermission
|
||||
import de.markusfisch.android.binaryeye.app.initSystemBars
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.graphics.Mapping
|
||||
import de.markusfisch.android.binaryeye.graphics.frameToView
|
||||
import de.markusfisch.android.binaryeye.rs.Preprocessor
|
||||
import de.markusfisch.android.binaryeye.widget.DetectorView
|
||||
import de.markusfisch.android.binaryeye.zxing.Zxing
|
||||
import de.markusfisch.android.cameraview.widget.CameraView
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@@ -33,12 +36,14 @@ class CameraActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var vibrator: Vibrator
|
||||
private lateinit var cameraView: CameraView
|
||||
private lateinit var detectorView: DetectorView
|
||||
private lateinit var zoomBar: SeekBar
|
||||
private lateinit var flashFab: View
|
||||
|
||||
private var preprocessor: Preprocessor? = null
|
||||
private var invert = false
|
||||
private var flash = false
|
||||
private var returnResult = false
|
||||
private var frontFacing = false
|
||||
private var fallbackBuffer: IntArray? = null
|
||||
|
||||
@@ -82,12 +87,13 @@ class CameraActivity : AppCompatActivity() {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_camera)
|
||||
|
||||
vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
|
||||
initSystemBars(this)
|
||||
setSupportActionBar(findViewById(R.id.toolbar) as Toolbar)
|
||||
|
||||
vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
|
||||
cameraView = findViewById(R.id.camera_view) as CameraView
|
||||
detectorView = findViewById(R.id.detector_view) as DetectorView
|
||||
zoomBar = findViewById(R.id.zoom) as SeekBar
|
||||
flashFab = findViewById(R.id.flash)
|
||||
flashFab.setOnClickListener { toggleTorchMode() }
|
||||
@@ -113,6 +119,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
System.gc()
|
||||
returnResult = "com.google.zxing.client.android.SCAN" == intent.action
|
||||
if (hasCameraPermission(this, REQUEST_CAMERA)) {
|
||||
openCamera()
|
||||
}
|
||||
@@ -262,6 +269,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
val frameWidth = cameraView.frameWidth
|
||||
val frameHeight = cameraView.frameHeight
|
||||
val frameOrientation = cameraView.frameOrientation
|
||||
var mapping: Mapping? = null
|
||||
var decoding = true
|
||||
camera.setPreviewCallback { frameData, _ ->
|
||||
if (decoding) {
|
||||
@@ -272,9 +280,25 @@ class CameraActivity : AppCompatActivity() {
|
||||
frameOrientation
|
||||
)
|
||||
result?.let {
|
||||
preprocessor?.let {
|
||||
mapping = mapping ?: frameToView(
|
||||
it.outWidth,
|
||||
it.outHeight,
|
||||
cameraView.previewRect
|
||||
)
|
||||
}
|
||||
cameraView.post {
|
||||
mapping?.let {
|
||||
detectorView.mark(
|
||||
it.map(result.resultPoints)
|
||||
)
|
||||
}
|
||||
vibrator.vibrate(100)
|
||||
showResult(this@CameraActivity, result)
|
||||
showResult(
|
||||
this@CameraActivity,
|
||||
result,
|
||||
returnResult
|
||||
)
|
||||
}
|
||||
decoding = false
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.colorSystemAndToolBars
|
||||
import de.markusfisch.android.binaryeye.app.initSystemBars
|
||||
import de.markusfisch.android.binaryeye.app.setFragment
|
||||
import de.markusfisch.android.binaryeye.app.setSystemAndToolBarTransparency
|
||||
import de.markusfisch.android.binaryeye.app.setupInsets
|
||||
import de.markusfisch.android.binaryeye.fragment.DecodeFragment
|
||||
import de.markusfisch.android.binaryeye.fragment.EncodeFragment
|
||||
import de.markusfisch.android.binaryeye.fragment.HistoryFragment
|
||||
@@ -30,13 +31,15 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_main)
|
||||
initSystemBars(this)
|
||||
|
||||
setSupportActionBar(findViewById(R.id.toolbar) as Toolbar)
|
||||
initSystemBars(this)
|
||||
val toolbar = findViewById(R.id.toolbar) as Toolbar
|
||||
setupInsets(findViewById(android.R.id.content), toolbar)
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
supportFragmentManager.addOnBackStackChangedListener {
|
||||
setSystemAndToolBarTransparency(this@MainActivity)
|
||||
colorSystemAndToolBars(this@MainActivity)
|
||||
}
|
||||
|
||||
if (state == null) {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.provider.MediaStore
|
||||
import android.os.Vibrator
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.Menu
|
||||
@@ -14,36 +16,37 @@ import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import com.google.zxing.Result
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.colorSystemAndToolBars
|
||||
import de.markusfisch.android.binaryeye.app.initSystemBars
|
||||
import de.markusfisch.android.binaryeye.app.setSystemAndToolBarTransparency
|
||||
import de.markusfisch.android.binaryeye.app.setWindowInsetListener
|
||||
import de.markusfisch.android.binaryeye.app.setupInsets
|
||||
import de.markusfisch.android.binaryeye.graphics.crop
|
||||
import de.markusfisch.android.binaryeye.graphics.downsizeIfBigger
|
||||
import de.markusfisch.android.binaryeye.graphics.loadImageUri
|
||||
import de.markusfisch.android.binaryeye.graphics.mapResult
|
||||
import de.markusfisch.android.binaryeye.widget.CropImageView
|
||||
import de.markusfisch.android.binaryeye.zxing.Zxing
|
||||
import java.io.IOException
|
||||
import kotlin.math.min
|
||||
import kotlin.math.max
|
||||
|
||||
class PickActivity : AppCompatActivity() {
|
||||
private val zxing = Zxing()
|
||||
|
||||
private lateinit var vibrator: Vibrator
|
||||
private lateinit var cropImageView: CropImageView
|
||||
|
||||
private var returnResult = false
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setContentView(R.layout.activity_pick)
|
||||
initSystemBars(this)
|
||||
|
||||
setSupportActionBar(findViewById(R.id.toolbar) as Toolbar)
|
||||
vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
|
||||
initSystemBars(this)
|
||||
val toolbar = findViewById(R.id.toolbar) as Toolbar
|
||||
setupInsets(findViewById(android.R.id.content), toolbar)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
supportFragmentManager.addOnBackStackChangedListener {
|
||||
setSystemAndToolBarTransparency(this@PickActivity)
|
||||
colorSystemAndToolBars(this@PickActivity)
|
||||
}
|
||||
|
||||
returnResult = intent?.action == "com.google.zxing.client.android.SCAN"
|
||||
|
||||
val bitmap = if (
|
||||
intent?.action == Intent.ACTION_SEND &&
|
||||
intent.type?.startsWith("image/") == true
|
||||
@@ -69,7 +72,7 @@ class PickActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
val scannedRect = Rect()
|
||||
val scanBounds: () -> Result? = {
|
||||
val scanWithinBounds: () -> Result? = {
|
||||
var result: Result? = null
|
||||
crop(
|
||||
bitmap,
|
||||
@@ -85,35 +88,24 @@ class PickActivity : AppCompatActivity() {
|
||||
cropImageView = findViewById(R.id.image) as CropImageView
|
||||
cropImageView.setImageBitmap(bitmap)
|
||||
cropImageView.onScan = {
|
||||
val rect = Rect()
|
||||
scanBounds()?.also {
|
||||
rect.left = Int.MAX_VALUE
|
||||
rect.top = Int.MAX_VALUE
|
||||
for (rp in it.resultPoints) {
|
||||
val x = rp.x.toInt()
|
||||
val y = rp.y.toInt()
|
||||
rect.left = min(rect.left, x)
|
||||
rect.right = max(rect.right, x)
|
||||
rect.top = min(rect.top, y)
|
||||
rect.bottom = max(rect.bottom, y)
|
||||
}
|
||||
// map result points onto view
|
||||
val bounds = cropImageView.getBoundsRect()
|
||||
val fx = bounds.width() / scannedRect.width().toFloat()
|
||||
val fy = bounds.height() / scannedRect.height().toFloat()
|
||||
rect.set(
|
||||
(rect.left * fx).toInt(),
|
||||
(rect.top * fy).toInt(),
|
||||
(rect.right * fx).toInt(),
|
||||
(rect.bottom * fx).toInt()
|
||||
var points: List<Point>? = null
|
||||
scanWithinBounds()?.let {
|
||||
points = mapResult(
|
||||
scannedRect.width(),
|
||||
scannedRect.height(),
|
||||
cropImageView.getBoundsRect(),
|
||||
it
|
||||
)
|
||||
rect.offset(bounds.left.toInt(), bounds.top.toInt())
|
||||
vibrator.vibrate(100)
|
||||
}
|
||||
rect
|
||||
points
|
||||
}
|
||||
setWindowInsetListener { insets ->
|
||||
cropImageView.windowInsets.set(insets)
|
||||
}
|
||||
|
||||
findViewById(R.id.scan).setOnClickListener {
|
||||
scanImage(scanBounds())
|
||||
scanImage(scanWithinBounds())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,26 +132,17 @@ class PickActivity : AppCompatActivity() {
|
||||
val uri = intent.getParcelableExtra<Parcelable>(
|
||||
Intent.EXTRA_STREAM
|
||||
) as? Uri ?: return null
|
||||
return loadImageUri(uri)
|
||||
return loadImageUri(contentResolver, uri)
|
||||
}
|
||||
|
||||
private fun loadImageToOpen(intent: Intent): Bitmap? {
|
||||
val uri = intent.data ?: return null
|
||||
return loadImageUri(uri)
|
||||
}
|
||||
|
||||
private fun loadImageUri(uri: Uri): Bitmap? = try {
|
||||
downsizeIfBigger(
|
||||
MediaStore.Images.Media.getBitmap(contentResolver, uri),
|
||||
1024
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
return loadImageUri(contentResolver, uri)
|
||||
}
|
||||
|
||||
private fun scanImage(result: Result?) {
|
||||
if (result != null) {
|
||||
showResult(this, result, returnResult)
|
||||
showResult(this, result)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -20,11 +20,9 @@ class ScansAdapter(context: Context, cursor: Cursor) :
|
||||
context: Context,
|
||||
cursor: Cursor,
|
||||
parent: ViewGroup
|
||||
): View {
|
||||
return LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.row_scan, parent, false
|
||||
)
|
||||
}
|
||||
) = LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.row_scan, parent, false
|
||||
)
|
||||
|
||||
override fun bindView(
|
||||
view: View,
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import android.app.Application
|
||||
import android.support.v8.renderscript.RenderScript
|
||||
import de.markusfisch.android.binaryeye.BuildConfig
|
||||
import de.markusfisch.android.binaryeye.preference.Preferences
|
||||
import de.markusfisch.android.binaryeye.repository.DatabaseRepository
|
||||
|
||||
@@ -12,9 +13,19 @@ class BinaryEyeApp : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
// required to make RenderScript work for Lineage 16.0
|
||||
// possibly because of a system/device bug
|
||||
RenderScript.forceCompat()
|
||||
// Since RenderScript can no longer be compiled on macOS Catalina
|
||||
// because Catalina cannot run 32bit binaries and Google failed
|
||||
// to provide a 64bit compiler in time. Now, as if that wasn't
|
||||
// bad enough, `RenderScript.forceCompat()` makes any build compiled
|
||||
// with the new build tools that provide a 64bit compiler crash
|
||||
// so we need to exclude this if we're building on Catalina.
|
||||
// Maybe `RenderScript.forceCompat()` isn't required anymore for
|
||||
// those new builds but I don't have a device to test this.
|
||||
if (!BuildConfig.IS_CATALINA) {
|
||||
// required to make RenderScript work for Lineage 16.0
|
||||
// possibly because of a system/device bug
|
||||
RenderScript.forceCompat()
|
||||
}
|
||||
|
||||
db.open(this)
|
||||
prefs.init(this)
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.View
|
||||
import android.widget.AbsListView
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
val windowInsets = Rect()
|
||||
val systemBarScrollListener = object : AbsListView.OnScrollListener {
|
||||
override fun onScroll(
|
||||
view: AbsListView,
|
||||
@@ -25,8 +26,8 @@ val systemBarScrollListener = object : AbsListView.OnScrollListener {
|
||||
val scrolled = firstVisibleItem > 0 ||
|
||||
(totalItemCount > 0 && view.getChildAt(0).top < 0)
|
||||
val scrollable = if (scrolled) true else totalItemCount > 0 &&
|
||||
view.getChildAt(view.lastVisiblePosition).bottom > view.height
|
||||
setSystemAndToolBarTransparency(view.context, scrolled, scrollable)
|
||||
view.getChildAt(view.lastVisiblePosition).bottom >= view.height
|
||||
colorSystemAndToolBars(view.context, scrolled, scrollable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,16 +38,25 @@ val systemBarScrollListener = object : AbsListView.OnScrollListener {
|
||||
}
|
||||
}
|
||||
|
||||
fun setSystemAndToolBarTransparency(
|
||||
fun initSystemBars(activity: AppCompatActivity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
activity.window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
}
|
||||
colorSystemAndToolBars(activity)
|
||||
}
|
||||
|
||||
fun colorSystemAndToolBars(
|
||||
context: Context,
|
||||
scrolled: Boolean = false,
|
||||
scrollable: Boolean = false
|
||||
) {
|
||||
val opaqueColor = ContextCompat.getColor(context, R.color.primary)
|
||||
val transparentColor = 0x00000000
|
||||
val topColor = if (scrolled) opaqueColor else transparentColor
|
||||
val bottomColor = if (scrolled || scrollable) opaqueColor else transparentColor
|
||||
val activity = context as AppCompatActivity
|
||||
val translucentColor = getTranslucentPrimaryColor(context)
|
||||
val topColor = if (scrolled) translucentColor else 0
|
||||
val bottomColor = if (scrolled || scrollable) translucentColor else 0
|
||||
val activity = getAppCompatActivity(context) ?: return
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val window = activity.window
|
||||
window.statusBarColor = topColor
|
||||
@@ -55,29 +65,54 @@ fun setSystemAndToolBarTransparency(
|
||||
activity.supportActionBar?.setBackgroundDrawable(ColorDrawable(topColor))
|
||||
}
|
||||
|
||||
fun initSystemBars(activity: AppCompatActivity) {
|
||||
activity.findViewById(R.id.main_layout)?.also { view ->
|
||||
setWindowInsetListener(view)
|
||||
private fun getTranslucentPrimaryColor(context: Context) = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.primary
|
||||
) and 0xffffff or 0xd8000000.toInt()
|
||||
|
||||
private fun getAppCompatActivity(context: Context): AppCompatActivity? {
|
||||
var ctx = context
|
||||
while (ctx is ContextWrapper) {
|
||||
if (ctx is AppCompatActivity) {
|
||||
return ctx
|
||||
}
|
||||
ctx = ctx.baseContext ?: break
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
activity.window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
}
|
||||
setSystemAndToolBarTransparency(activity)
|
||||
return null
|
||||
}
|
||||
|
||||
private fun setWindowInsetListener(view: View) {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->
|
||||
if (insets.hasSystemWindowInsets()) {
|
||||
val left = insets.systemWindowInsetLeft
|
||||
val top = insets.systemWindowInsetTop
|
||||
val right = insets.systemWindowInsetRight
|
||||
val bottom = insets.systemWindowInsetBottom
|
||||
view.setPadding(left, top, right, bottom)
|
||||
windowInsets.set(left, top, right, bottom)
|
||||
}
|
||||
insets.consumeSystemWindowInsets()
|
||||
private var windowInsetsListener: ((insets: Rect) -> Unit)? = null
|
||||
// invoke this from Fragment.onCreateView() *or* Activity.onCreate()
|
||||
fun setWindowInsetListener(listener: (insets: Rect) -> Unit) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
listener(windowInsets)
|
||||
} else {
|
||||
windowInsetsListener = listener
|
||||
}
|
||||
}
|
||||
|
||||
private val windowInsets = Rect()
|
||||
// invoke this from Activity.onCreate() to setup listening for insets
|
||||
fun setupInsets(view: View, toolbar: Toolbar) {
|
||||
val toolBarHeight = toolbar.layoutParams.height
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
// save insets so setWindowInsetListener() can return them
|
||||
// when it's called from Fragment.onCreateView() later on
|
||||
windowInsets.set(0, toolBarHeight, 0, 0)
|
||||
windowInsetsListener?.also { it(windowInsets) }
|
||||
return
|
||||
}
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->
|
||||
// runs *after* layout and thus *after* Fragment.onCreateView()
|
||||
if (insets.hasSystemWindowInsets()) {
|
||||
windowInsets.set(
|
||||
insets.systemWindowInsetLeft,
|
||||
insets.systemWindowInsetTop + toolBarHeight,
|
||||
insets.systemWindowInsetRight,
|
||||
insets.systemWindowInsetBottom
|
||||
)
|
||||
windowInsetsListener?.also { it(windowInsets) }
|
||||
}
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +59,9 @@ class Database {
|
||||
timestamp
|
||||
).toString()
|
||||
)
|
||||
if (hasNonPrintableCharacters(content) && raw != null) {
|
||||
if (hasNonPrintableCharacters(content)) {
|
||||
cv.put(SCANS_CONTENT, "")
|
||||
cv.put(SCANS_RAW, raw)
|
||||
cv.put(SCANS_RAW, if (raw != null) raw else content.toByteArray())
|
||||
} else {
|
||||
cv.put(SCANS_CONTENT, content)
|
||||
}
|
||||
|
||||
@@ -8,13 +8,15 @@ import android.os.Environment
|
||||
import android.support.v4.app.Fragment
|
||||
import android.view.*
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.addSuffixIfNotGiven
|
||||
import de.markusfisch.android.binaryeye.app.hasWritePermission
|
||||
import de.markusfisch.android.binaryeye.app.setWindowInsetListener
|
||||
import de.markusfisch.android.binaryeye.app.shareFile
|
||||
import de.markusfisch.android.binaryeye.view.setPadding
|
||||
import de.markusfisch.android.binaryeye.widget.ConfinedScalingImageView
|
||||
import de.markusfisch.android.binaryeye.zxing.Zxing
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@@ -22,9 +24,12 @@ import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class BarcodeFragment : Fragment() {
|
||||
private var barcode: Bitmap? = null
|
||||
private var content: String = ""
|
||||
private var format: BarcodeFormat? = null
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
@@ -59,7 +64,18 @@ class BarcodeFragment : Fragment() {
|
||||
fragmentManager.popBackStack()
|
||||
return null
|
||||
}
|
||||
view.findViewById<ImageView>(R.id.barcode).setImageBitmap(barcode)
|
||||
this.content = content
|
||||
this.format = format
|
||||
|
||||
val imageView = view.findViewById<ConfinedScalingImageView>(
|
||||
R.id.barcode
|
||||
)
|
||||
imageView.setImageBitmap(barcode)
|
||||
imageView.post {
|
||||
// make sure to invoke this after ScalingImageView.onLayout()
|
||||
imageView.minWidth /= 2f
|
||||
}
|
||||
|
||||
view.findViewById<View>(R.id.share).setOnClickListener {
|
||||
val bitmap = barcode
|
||||
bitmap?.let {
|
||||
@@ -67,6 +83,11 @@ class BarcodeFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
setWindowInsetListener { insets ->
|
||||
(view.findViewById(R.id.inset_layout) as View).setPadding(insets)
|
||||
imageView.insets.set(insets)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
@@ -90,6 +111,7 @@ class BarcodeFragment : Fragment() {
|
||||
val ac = activity ?: return
|
||||
val view = ac.layoutInflater.inflate(R.layout.dialog_save_file, null)
|
||||
val editText = view.findViewById<EditText>(R.id.file_name)
|
||||
editText.setText(encodeFileName("${format.toString()}_$content"))
|
||||
AlertDialog.Builder(ac)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
@@ -193,3 +215,7 @@ private fun saveBitmap(bitmap: Bitmap, file: File): Boolean {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private val fileNameCharacters = "[^A-Za-z0-9]".toRegex()
|
||||
private fun encodeFileName(name: String): String =
|
||||
fileNameCharacters.replace(name, "_").take(16).trim('_').toLowerCase(Locale.getDefault())
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.google.zxing.BarcodeFormat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.actions.ActionRegistry
|
||||
import de.markusfisch.android.binaryeye.app.*
|
||||
import de.markusfisch.android.binaryeye.view.setPadding
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -106,6 +107,11 @@ class DecodeFragment : Fragment() {
|
||||
|
||||
updateViewsAndAction(raw)
|
||||
|
||||
setWindowInsetListener { insets ->
|
||||
(view.findViewById(R.id.inset_layout) as View).setPadding(insets)
|
||||
(view.findViewById(R.id.scroll_view) as View).setPadding(insets)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
|
||||
@@ -3,19 +3,22 @@ package de.markusfisch.android.binaryeye.fragment
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.*
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.*
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.addFragment
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.app.setWindowInsetListener
|
||||
import de.markusfisch.android.binaryeye.view.setPadding
|
||||
|
||||
class EncodeFragment : Fragment() {
|
||||
private lateinit var formatView: Spinner
|
||||
private lateinit var sizeView: TextView
|
||||
private lateinit var sizeBarView: SeekBar
|
||||
private lateinit var contentView: EditText
|
||||
|
||||
private val writers = arrayListOf(
|
||||
BarcodeFormat.AZTEC,
|
||||
BarcodeFormat.CODABAR,
|
||||
@@ -30,6 +33,11 @@ class EncodeFragment : Fragment() {
|
||||
BarcodeFormat.UPC_A
|
||||
)
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@@ -55,40 +63,72 @@ class EncodeFragment : Fragment() {
|
||||
sizeBarView = view.findViewById(R.id.size_bar)
|
||||
initSizeBar()
|
||||
|
||||
val contentView = view.findViewById<EditText>(R.id.content)
|
||||
contentView = view.findViewById<EditText>(R.id.content)
|
||||
|
||||
val args = arguments
|
||||
args?.let {
|
||||
contentView.setText(args.getString(CONTENT))
|
||||
formatView.setSelection(
|
||||
writers.indexOf(
|
||||
args.getSerializable(FORMAT) as BarcodeFormat?
|
||||
)
|
||||
)
|
||||
args?.also {
|
||||
contentView.setText(it.getString(CONTENT))
|
||||
}
|
||||
|
||||
view.findViewById<View>(R.id.encode).setOnClickListener { v ->
|
||||
val format = writers[formatView.selectedItemPosition]
|
||||
val size = getSize(sizeBarView.progress)
|
||||
val content = contentView.text.toString()
|
||||
if (content.isEmpty()) {
|
||||
Toast.makeText(
|
||||
v.context,
|
||||
R.string.error_no_content,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} else {
|
||||
hideSoftKeyboard(contentView)
|
||||
addFragment(
|
||||
fragmentManager,
|
||||
BarcodeFragment.newInstance(content, format, size)
|
||||
)
|
||||
val barcodeFormat = args?.getSerializable(FORMAT) as BarcodeFormat?
|
||||
if (barcodeFormat != null) {
|
||||
formatView.setSelection(writers.indexOf(barcodeFormat))
|
||||
} else if (state == null) {
|
||||
formatView.post {
|
||||
formatView.setSelection(prefs.indexOfLastSelectedFormat)
|
||||
}
|
||||
}
|
||||
|
||||
view.findViewById<View>(R.id.encode).setOnClickListener { v ->
|
||||
encode()
|
||||
}
|
||||
|
||||
setWindowInsetListener { insets ->
|
||||
(view.findViewById(R.id.inset_layout) as View).setPadding(insets)
|
||||
(view.findViewById(R.id.scroll_view) as View).setPadding(insets)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
prefs.indexOfLastSelectedFormat = formatView.selectedItemPosition
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.fragment_encode, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.next -> {
|
||||
encode()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun encode() {
|
||||
val format = writers[formatView.selectedItemPosition]
|
||||
val size = getSize(sizeBarView.progress)
|
||||
val content = contentView.text.toString()
|
||||
if (content.isEmpty()) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.error_no_content,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} else {
|
||||
hideSoftKeyboard(contentView)
|
||||
addFragment(
|
||||
fragmentManager,
|
||||
BarcodeFragment.newInstance(content, format, size)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initSizeBar() {
|
||||
updateSize(sizeBarView.progress)
|
||||
sizeBarView.setOnSeekBarChangeListener(
|
||||
@@ -129,11 +169,13 @@ class EncodeFragment : Fragment() {
|
||||
|
||||
fun newInstance(
|
||||
content: String,
|
||||
format: BarcodeFormat = BarcodeFormat.AZTEC
|
||||
format: BarcodeFormat? = null
|
||||
): Fragment {
|
||||
val args = Bundle()
|
||||
args.putString(CONTENT, content)
|
||||
args.putSerializable(FORMAT, format)
|
||||
format?.let {
|
||||
args.putSerializable(FORMAT, format)
|
||||
}
|
||||
val fragment = EncodeFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
|
||||
@@ -3,10 +3,12 @@ package de.markusfisch.android.binaryeye.fragment
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.support.annotation.WorkerThread
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.widget.SwitchCompat
|
||||
import android.view.*
|
||||
import android.widget.AbsListView
|
||||
import android.widget.ListView
|
||||
import android.widget.Toast
|
||||
import com.google.zxing.BarcodeFormat
|
||||
@@ -15,6 +17,7 @@ import de.markusfisch.android.binaryeye.adapter.ScansAdapter
|
||||
import de.markusfisch.android.binaryeye.app.*
|
||||
import de.markusfisch.android.binaryeye.data.csv.csvBuilder
|
||||
import de.markusfisch.android.binaryeye.repository.DatabaseRepository
|
||||
import de.markusfisch.android.binaryeye.view.setPadding
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
@@ -28,6 +31,9 @@ class HistoryFragment : Fragment() {
|
||||
private val parentJob = Job()
|
||||
private val scope = CoroutineScope(Dispatchers.IO + parentJob)
|
||||
|
||||
private var scansAdapter: ScansAdapter? = null
|
||||
private var listViewState: Parcelable? = null
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
@@ -51,7 +57,17 @@ class HistoryFragment : Fragment() {
|
||||
) as SwitchCompat
|
||||
initHistorySwitch(useHistorySwitch)
|
||||
|
||||
val headView = View(context)
|
||||
val footView = View(context)
|
||||
setWindowInsetListener { insets ->
|
||||
(view.findViewById(R.id.inset_layout) as View).setPadding(insets)
|
||||
headView.layoutParams = AbsListView.LayoutParams(0, insets.top)
|
||||
footView.layoutParams = AbsListView.LayoutParams(0, insets.bottom)
|
||||
}
|
||||
|
||||
listView = view.findViewById(R.id.scans)
|
||||
listView.addHeaderView(headView, null, false)
|
||||
listView.addFooterView(footView, null, false)
|
||||
listView.emptyView = useHistorySwitch
|
||||
listView.setOnItemClickListener { _, _, _, id ->
|
||||
showScan(id)
|
||||
@@ -74,7 +90,7 @@ class HistoryFragment : Fragment() {
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
(listView.adapter as ScansAdapter?)?.changeCursor(null)
|
||||
scansAdapter?.changeCursor(null)
|
||||
parentJob.cancel()
|
||||
}
|
||||
|
||||
@@ -83,6 +99,11 @@ class HistoryFragment : Fragment() {
|
||||
update(context)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
listViewState = listView.onSaveInstanceState()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.fragment_history, menu)
|
||||
}
|
||||
@@ -120,12 +141,12 @@ class HistoryFragment : Fragment() {
|
||||
View.GONE
|
||||
}
|
||||
cursor?.let {
|
||||
if (listView.adapter == null) {
|
||||
listView.adapter = ScansAdapter(context, cursor)
|
||||
} else {
|
||||
val adapter = listView.adapter as ScansAdapter
|
||||
adapter.changeCursor(cursor)
|
||||
adapter.notifyDataSetChanged()
|
||||
// close previous cursor
|
||||
scansAdapter?.also { it.changeCursor(null) }
|
||||
scansAdapter = ScansAdapter(context, it)
|
||||
listView.adapter = scansAdapter
|
||||
listViewState?.also {
|
||||
listView.onRestoreInstanceState(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-3
@@ -9,6 +9,8 @@ import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.app.setWindowInsetListener
|
||||
import de.markusfisch.android.binaryeye.view.setPadding
|
||||
|
||||
class PreferencesFragment : Fragment() {
|
||||
private lateinit var openImmediatelySwitch: SwitchCompat
|
||||
@@ -28,19 +30,23 @@ class PreferencesFragment : Fragment() {
|
||||
false
|
||||
)
|
||||
|
||||
openImmediatelySwitch = view.findViewById<SwitchCompat>(R.id.open_immediately)
|
||||
openImmediatelySwitch = view.findViewById(R.id.open_immediately)
|
||||
if (prefs.openImmediately) {
|
||||
openImmediatelySwitch.toggle()
|
||||
}
|
||||
|
||||
useHistorySwitch = view.findViewById<SwitchCompat>(R.id.use_history)
|
||||
useHistorySwitch = view.findViewById(R.id.use_history)
|
||||
if (prefs.useHistory) {
|
||||
useHistorySwitch.toggle()
|
||||
}
|
||||
|
||||
openWithUrlInput = view.findViewById<EditText>(R.id.open_with_url)
|
||||
openWithUrlInput = view.findViewById(R.id.open_with_url)
|
||||
openWithUrlInput.setText(prefs.openWithUrl)
|
||||
|
||||
setWindowInsetListener { insets ->
|
||||
(view.findViewById(R.id.scroll_view) as View).setPadding(insets)
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,52 @@
|
||||
package de.markusfisch.android.binaryeye.graphics
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.RectF
|
||||
import kotlin.math.max
|
||||
import android.net.Uri
|
||||
import java.io.IOException
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun downsizeIfBigger(bitmap: Bitmap, maxSize: Int): Bitmap = if (
|
||||
max(bitmap.width, bitmap.height) > maxSize
|
||||
) {
|
||||
val srcWidth = bitmap.width
|
||||
val srcHeight = bitmap.height
|
||||
var newWidth = maxSize
|
||||
var newHeight = maxSize
|
||||
if (srcWidth > srcHeight) {
|
||||
newHeight = (newWidth.toFloat() / srcWidth.toFloat() *
|
||||
srcHeight.toFloat()).roundToInt()
|
||||
} else {
|
||||
newWidth = (newHeight.toFloat() / srcHeight.toFloat() *
|
||||
srcWidth.toFloat()).roundToInt()
|
||||
fun loadImageUri(cr: ContentResolver, uri: Uri): Bitmap? = try {
|
||||
val options = BitmapFactory.Options()
|
||||
cr.openInputStream(uri)?.use {
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeStream(it, null, options)
|
||||
options.inSampleSize = calculateInSampleSize(
|
||||
options.outWidth,
|
||||
options.outHeight,
|
||||
1024,
|
||||
1024
|
||||
)
|
||||
options.inJustDecodeBounds = false
|
||||
}
|
||||
Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true)
|
||||
} else {
|
||||
bitmap
|
||||
cr.openInputStream(uri)?.use {
|
||||
BitmapFactory.decodeStream(it, null, options)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun calculateInSampleSize(
|
||||
width: Int,
|
||||
height: Int,
|
||||
reqWidth: Int,
|
||||
reqHeight: Int
|
||||
): Int {
|
||||
var inSampleSize = 1
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
val halfHeight = height / 2
|
||||
val halfWidth = width / 2
|
||||
while (
|
||||
halfHeight / inSampleSize >= reqHeight ||
|
||||
halfWidth / inSampleSize >= reqWidth
|
||||
) {
|
||||
inSampleSize *= 2
|
||||
}
|
||||
}
|
||||
return inSampleSize
|
||||
}
|
||||
|
||||
fun crop(bitmap: Bitmap, rect: RectF, rotation: Float) = try {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package de.markusfisch.android.binaryeye.graphics
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.support.v4.content.ContextCompat
|
||||
import com.google.zxing.Result
|
||||
import com.google.zxing.ResultPoint
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class Candidates(context: Context) {
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val radius = 8f * context.resources.displayMetrics.density
|
||||
|
||||
init {
|
||||
paint.color = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.candidate
|
||||
)
|
||||
paint.style = Paint.Style.FILL
|
||||
}
|
||||
|
||||
fun draw(canvas: Canvas, points: List<Point>) {
|
||||
for (point in points) {
|
||||
canvas.drawCircle(
|
||||
point.x.toFloat(),
|
||||
point.y.toFloat(),
|
||||
radius,
|
||||
paint
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun mapResult(
|
||||
width: Int,
|
||||
height: Int,
|
||||
viewRect: Rect,
|
||||
result: Result
|
||||
): List<Point> = frameToView(width, height, viewRect).map(result.resultPoints)
|
||||
|
||||
fun frameToView(width: Int, height: Int, viewRect: Rect) = Mapping(
|
||||
viewRect.width().toFloat() / width.toFloat(),
|
||||
viewRect.height().toFloat() / height.toFloat(),
|
||||
viewRect.left,
|
||||
viewRect.top
|
||||
)
|
||||
|
||||
data class Mapping(
|
||||
val ratioX: Float,
|
||||
val ratioY: Float,
|
||||
val offsetX: Int,
|
||||
val offsetY: Int
|
||||
) {
|
||||
fun map(points: Array<ResultPoint>): List<Point> {
|
||||
return points.map {
|
||||
Point(
|
||||
(it.x * ratioX).roundToInt() + offsetX,
|
||||
(it.y * ratioY).roundToInt() + offsetY
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,11 @@ class Preferences {
|
||||
setString(OPEN_WITH_URL, value)
|
||||
field = value
|
||||
}
|
||||
var indexOfLastSelectedFormat: Int = 0
|
||||
set(value) {
|
||||
setInt(INDEX_OF_LAST_SELECTED_FORMAT, value)
|
||||
field = value
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
@@ -29,9 +34,18 @@ class Preferences {
|
||||
}
|
||||
|
||||
fun update() {
|
||||
openImmediately = preferences.getBoolean(OPEN_IMMEDIATELY, openImmediately)
|
||||
openImmediately = preferences.getBoolean(
|
||||
OPEN_IMMEDIATELY,
|
||||
openImmediately
|
||||
)
|
||||
useHistory = preferences.getBoolean(USE_HISTORY, useHistory)
|
||||
preferences.getString(OPEN_WITH_URL, openWithUrl)?.also { openWithUrl = it }
|
||||
indexOfLastSelectedFormat = preferences.getInt(
|
||||
INDEX_OF_LAST_SELECTED_FORMAT,
|
||||
indexOfLastSelectedFormat
|
||||
)
|
||||
preferences.getString(OPEN_WITH_URL, openWithUrl)?.also {
|
||||
openWithUrl = it
|
||||
}
|
||||
}
|
||||
|
||||
private fun setBoolean(label: String, value: Boolean) {
|
||||
@@ -46,9 +60,16 @@ class Preferences {
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
private fun setInt(label: String, value: Int) {
|
||||
val editor = preferences.edit()
|
||||
editor.putInt(label, value)
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val OPEN_IMMEDIATELY = "open_immediately"
|
||||
const val USE_HISTORY = "use_history"
|
||||
const val OPEN_WITH_URL = "open_with_url"
|
||||
const val INDEX_OF_LAST_SELECTED_FORMAT = "index_of_last_selected_format"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package de.markusfisch.android.binaryeye.view
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
|
||||
fun View.setPadding(rect: Rect) {
|
||||
this.setPadding(
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.right,
|
||||
rect.bottom
|
||||
)
|
||||
}
|
||||
+23
-2
@@ -2,11 +2,14 @@ package de.markusfisch.android.binaryeye.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import de.markusfisch.android.binaryeye.app.setSystemAndToolBarTransparency
|
||||
import de.markusfisch.android.binaryeye.app.colorSystemAndToolBars
|
||||
import de.markusfisch.android.scalingimageview.widget.ScalingImageView
|
||||
|
||||
open class ConfinedScalingImageView : ScalingImageView {
|
||||
val insets = Rect()
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) :
|
||||
super(context, attrs, defStyle)
|
||||
|
||||
@@ -15,6 +18,24 @@ open class ConfinedScalingImageView : ScalingImageView {
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
setSystemAndToolBarTransparency(context, !bounds.contains(mappedRect))
|
||||
colorSystemAndToolBars(context, !bounds.contains(mappedRect))
|
||||
}
|
||||
|
||||
override fun layoutImage(
|
||||
changed: Boolean,
|
||||
left: Int,
|
||||
top: Int,
|
||||
right: Int,
|
||||
bottom: Int
|
||||
) {
|
||||
if (changed) {
|
||||
setBounds(
|
||||
(left + insets.left).toFloat(),
|
||||
(top + insets.top).toFloat(),
|
||||
(right - insets.right).toFloat(),
|
||||
(bottom - insets.bottom).toFloat()
|
||||
)
|
||||
}
|
||||
centerRemap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package de.markusfisch.android.binaryeye.widget
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ScrollView
|
||||
import de.markusfisch.android.binaryeye.app.setSystemAndToolBarTransparency
|
||||
import de.markusfisch.android.binaryeye.app.colorSystemAndToolBars
|
||||
|
||||
class ConfinedScrollView : ScrollView {
|
||||
private var scrollable = false
|
||||
@@ -28,9 +28,9 @@ class ConfinedScrollView : ScrollView {
|
||||
post {
|
||||
getChildAt(0)?.also { child ->
|
||||
scrollable = height < child.height + paddingTop + paddingBottom
|
||||
setSystemAndToolBarTransparency(
|
||||
colorSystemAndToolBars(
|
||||
context,
|
||||
false,
|
||||
scrollY > 0,
|
||||
scrollable
|
||||
)
|
||||
}
|
||||
@@ -40,6 +40,6 @@ class ConfinedScrollView : ScrollView {
|
||||
|
||||
override fun onScrollChanged(x: Int, y: Int, oldx: Int, oldy: Int) {
|
||||
super.onScrollChanged(x, y, oldx, oldy)
|
||||
setSystemAndToolBarTransparency(context, y > 0, scrollable)
|
||||
colorSystemAndToolBars(context, y > 0, scrollable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,35 +5,34 @@ import android.graphics.*
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.AttributeSet
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.windowInsets
|
||||
import de.markusfisch.android.binaryeye.graphics.Candidates
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class CropImageView(context: Context, attr: AttributeSet) :
|
||||
ConfinedScalingImageView(context, attr) {
|
||||
var onScan: (() -> Rect)? = null
|
||||
val windowInsets = Rect()
|
||||
|
||||
var onScan: (() -> List<Point>?)? = null
|
||||
|
||||
private val candidates = Candidates(context)
|
||||
private val boundsPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val candidatePaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val lastMappedRect = RectF()
|
||||
private val dp = context.resources.displayMetrics.density
|
||||
private val padding: Int = (dp * 24f).roundToInt()
|
||||
private val onScanRunnable = Runnable {
|
||||
onScan?.invoke()?.also {
|
||||
candidateRect = it
|
||||
candidatePoints = it
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private var candidateRect: Rect? = null
|
||||
private var candidatePoints: List<Point>? = null
|
||||
|
||||
init {
|
||||
boundsPaint.color = ContextCompat.getColor(context, R.color.crop_bound)
|
||||
boundsPaint.style = Paint.Style.STROKE
|
||||
boundsPaint.strokeWidth = dp * 2f
|
||||
boundsPaint.pathEffect = DashPathEffect(floatArrayOf(dp * 10f, dp * 10f), 0f)
|
||||
candidatePaint.color = ContextCompat.getColor(context, R.color.candidate)
|
||||
candidatePaint.style = Paint.Style.FILL_AND_STROKE
|
||||
candidatePaint.strokeWidth = dp * 3f
|
||||
scaleType = ScaleType.CENTER_CROP
|
||||
}
|
||||
|
||||
@@ -53,9 +52,12 @@ class CropImageView(context: Context, attr: AttributeSet) :
|
||||
)
|
||||
}
|
||||
|
||||
fun getBoundsRect(): RectF {
|
||||
return bounds
|
||||
}
|
||||
fun getBoundsRect() = Rect(
|
||||
bounds.left.roundToInt(),
|
||||
bounds.top.roundToInt(),
|
||||
bounds.right.roundToInt(),
|
||||
bounds.bottom.roundToInt()
|
||||
)
|
||||
|
||||
private fun setBoundsWithPadding(
|
||||
left: Int,
|
||||
@@ -83,11 +85,10 @@ class CropImageView(context: Context, attr: AttributeSet) :
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
canvas.drawRect(bounds, boundsPaint)
|
||||
val rc = candidateRect
|
||||
if (rc != null && rc.width() > 0) {
|
||||
canvas.drawRect(rc, candidatePaint)
|
||||
candidateRect = null
|
||||
candidatePoints?.let {
|
||||
candidates.draw(canvas, it)
|
||||
}
|
||||
candidatePoints = null
|
||||
val mr = mappedRect ?: return
|
||||
if (mr != lastMappedRect) {
|
||||
removeCallbacks(onScanRunnable)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.markusfisch.android.binaryeye.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Point
|
||||
import android.graphics.PorterDuff
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import de.markusfisch.android.binaryeye.graphics.Candidates
|
||||
|
||||
class DetectorView : View {
|
||||
private val candidates = Candidates(context)
|
||||
private var marks: List<Point>? = null
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) :
|
||||
super(context, attrs)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) :
|
||||
super(context, attrs, defStyleAttr)
|
||||
|
||||
fun mark(points: List<Point>) {
|
||||
marks = points
|
||||
invalidate()
|
||||
postDelayed({
|
||||
marks = null
|
||||
invalidate()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
canvas.drawColor(0, PorterDuff.Mode.CLEAR)
|
||||
marks?.let {
|
||||
candidates.draw(canvas, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import com.google.zxing.common.HybridBinarizer
|
||||
import java.util.*
|
||||
|
||||
class Zxing {
|
||||
private val multiFormatReader: MultiFormatReader = MultiFormatReader()
|
||||
private val multiFormatReader = MultiFormatReader()
|
||||
|
||||
init {
|
||||
val decodeFormats = EnumSet.noneOf<BarcodeFormat>(
|
||||
@@ -63,10 +63,11 @@ class Zxing {
|
||||
|
||||
fun decodePositiveNegative(bitmap: Bitmap): Result? {
|
||||
val result = decode(bitmap, false)
|
||||
if (result != null) {
|
||||
return result
|
||||
return if (result != null) {
|
||||
result
|
||||
} else {
|
||||
decode(bitmap, true)
|
||||
}
|
||||
return decode(bitmap, true)
|
||||
}
|
||||
|
||||
fun decode(bitmap: Bitmap, invert: Boolean = false): Result? {
|
||||
@@ -86,8 +87,10 @@ class Zxing {
|
||||
} else {
|
||||
bitmap
|
||||
}.getPixels(pixels, 0, width, 0, 0, width, height)
|
||||
val source = RGBLuminanceSource(width, height, pixels)
|
||||
return decodeLuminanceSource(source, invert)
|
||||
return decodeLuminanceSource(
|
||||
RGBLuminanceSource(width, height, pixels),
|
||||
invert
|
||||
)
|
||||
}
|
||||
|
||||
private fun decodeLuminanceSource(
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<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="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
|
||||
</vector>
|
||||
@@ -1,12 +1,13 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<de.markusfisch.android.cameraview.widget.CameraView
|
||||
android:id="@+id/camera_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<RelativeLayout
|
||||
android:id="@+id/main_layout"
|
||||
<de.markusfisch.android.binaryeye.widget.DetectorView
|
||||
android:id="@+id/detector_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
@@ -15,24 +16,15 @@
|
||||
android:id="@+id/zoom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginRight="80dp"
|
||||
android:layout_marginEnd="80dp"
|
||||
android:padding="16dp"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
tools:ignore="UnusedAttribute"
|
||||
style="@style/FAB"
|
||||
android:id="@+id/flash"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_margin="20dp"
|
||||
android:contentDescription="@string/toggle_flash"
|
||||
android:src="@drawable/ic_action_flash"
|
||||
app:elevation="4dp"/>
|
||||
</RelativeLayout>
|
||||
android:src="@drawable/ic_action_flash"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</merge>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<LinearLayout
|
||||
android:id="@+id/main_layout"
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:fitsSystemWindows="true">
|
||||
<include layout="@layout/toolbar"/>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</merge>
|
||||
|
||||
@@ -1,26 +1,18 @@
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<de.markusfisch.android.binaryeye.widget.CropImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@string/view_barcode"/>
|
||||
<include layout="@layout/toolbar"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:id="@+id/scan"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_margin="20dp"
|
||||
android:contentDescription="@string/scan_code"
|
||||
android:src="@drawable/ic_action_scan"
|
||||
app:elevation="4dp"/>
|
||||
</RelativeLayout>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
<include layout="@layout/toolbar"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/scan"
|
||||
android:contentDescription="@string/scan_code"
|
||||
android:src="@drawable/ic_action_scan"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</merge>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<RelativeLayout
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<de.markusfisch.android.binaryeye.widget.ConfinedScalingImageView
|
||||
@@ -9,16 +7,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@string/view_barcode"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:id="@+id/share"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_margin="20dp"
|
||||
android:contentDescription="@string/share"
|
||||
android:src="@drawable/ic_action_share"
|
||||
app:elevation="4dp"/>
|
||||
</RelativeLayout>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/share"
|
||||
android:contentDescription="@string/share"
|
||||
android:src="@drawable/ic_action_share"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
<RelativeLayout
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<de.markusfisch.android.binaryeye.widget.ConfinedScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:gravity="start|top"
|
||||
android:hint="@string/content"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
@@ -23,8 +27,8 @@
|
||||
android:inputType="textMultiLine"
|
||||
android:typeface="monospace"
|
||||
tools:ignore="UnusedAttribute"/>
|
||||
|
||||
<TextView
|
||||
style="@style/SecondaryText"
|
||||
android:id="@+id/format"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -32,8 +36,7 @@
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="end|top"
|
||||
android:textSize="14sp" />
|
||||
android:gravity="end|top" />
|
||||
<TextView
|
||||
android:id="@+id/hex"
|
||||
android:layout_width="match_parent"
|
||||
@@ -47,19 +50,16 @@
|
||||
android:typeface="monospace"
|
||||
android:textSize="12sp"
|
||||
tools:text="54 65 73 74 20 51 52 20 Test QR\n43 6F 64 65 Code"/>
|
||||
|
||||
</RelativeLayout>
|
||||
</de.markusfisch.android.binaryeye.widget.ConfinedScrollView>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:id="@+id/open"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_margin="20dp"
|
||||
android:contentDescription="@string/open_url"
|
||||
android:src="@drawable/ic_action_open"
|
||||
app:elevation="4dp"/>
|
||||
</RelativeLayout>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/open"
|
||||
android:contentDescription="@string/open_url"
|
||||
android:src="@drawable/ic_action_open"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -1,64 +1,74 @@
|
||||
<de.markusfisch.android.binaryeye.widget.ConfinedScrollView
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
<de.markusfisch.android.binaryeye.widget.ConfinedScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/format"/>
|
||||
<Spinner
|
||||
android:id="@+id/format"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/size"/>
|
||||
<TextView
|
||||
android:id="@+id/size_display"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:gravity="center"/>
|
||||
<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:progress="4"
|
||||
android:max="7"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/content"/>
|
||||
<EditText
|
||||
tools:targetApi="o"
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="start|top"
|
||||
android:typeface="monospace"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textMultiLine"
|
||||
android:hint="@string/input_content_here"
|
||||
android:importantForAutofill="no"/>
|
||||
<Button
|
||||
style="@style/Button"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/format"/>
|
||||
<Spinner
|
||||
android:id="@+id/format"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/size"/>
|
||||
<TextView
|
||||
android:id="@+id/size_display"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:gravity="center"/>
|
||||
<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:progress="4"
|
||||
android:max="7"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/content"/>
|
||||
<EditText
|
||||
tools:targetApi="o"
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="start|top"
|
||||
android:typeface="monospace"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textMultiLine"
|
||||
android:hint="@string/input_content_here"
|
||||
android:importantForAutofill="no"/>
|
||||
</LinearLayout>
|
||||
</de.markusfisch.android.binaryeye.widget.ConfinedScrollView>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/encode"
|
||||
android:layout_width="match_parent"
|
||||
android:text="@string/encode"/>
|
||||
</LinearLayout>
|
||||
</de.markusfisch.android.binaryeye.widget.ConfinedScrollView>
|
||||
android:contentDescription="@string/encode"
|
||||
android:src="@drawable/ic_action_next"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<RelativeLayout
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<ListView
|
||||
@@ -11,26 +9,24 @@
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@color/separator"
|
||||
android:dividerHeight="1px"/>
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:visibility="gone"
|
||||
android:id="@+id/use_history"
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/inset_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:padding="16dp"
|
||||
android:text="@string/use_history"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/share"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_margin="20dp"
|
||||
android:contentDescription="@string/share"
|
||||
android:src="@drawable/ic_action_share"
|
||||
app:elevation="4dp"/>
|
||||
android:layout_height="match_parent">
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:visibility="gone"
|
||||
android:id="@+id/use_history"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:padding="16dp"
|
||||
android:text="@string/use_history"/>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/share"
|
||||
android:contentDescription="@string/share"
|
||||
android:src="@drawable/ic_action_share"/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
<include layout="@layout/progress_view"/>
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<de.markusfisch.android.binaryeye.widget.ConfinedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/scroll_view"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
style="@style/SecondaryText"
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -11,6 +12,7 @@
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"/>
|
||||
<TextView
|
||||
style="@style/SecondaryText"
|
||||
android:id="@+id/format"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -26,5 +28,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/time"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:typeface="monospace"/>
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:material="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/next"
|
||||
android:title="@string/encode"
|
||||
android:icon="@drawable/ic_action_next"
|
||||
material:showAsAction="ifRoom"/>
|
||||
</menu>
|
||||
@@ -7,8 +7,8 @@
|
||||
<string name="content">Inhalt</string>
|
||||
<string name="binary_data">(Binäre Daten)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d Zeichen</item>
|
||||
<item quantity="other">%1$s\n%2$d Zeichen</item>
|
||||
<item quantity="one">%2$d Zeichen, %1$s</item>
|
||||
<item quantity="other">%2$d Zeichen, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Licht an/ausschalten</string>
|
||||
<string name="share">Teilen</string>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<string name="content">Contenu</string>
|
||||
<string name="binary_data">(binary data)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d character</item>
|
||||
<item quantity="other">%1$s\n%2$d characters</item>
|
||||
<item quantity="one">%2$d characters, %1$s</item>
|
||||
<item quantity="other">%2$d characters, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Toggle flash</string>
|
||||
<string name="share">Share</string>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<string name="content">Tartalom</string>
|
||||
<string name="binary_data">(bináris adat)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d karakter</item>
|
||||
<item quantity="other">%1$s\n%2$d karakter</item>
|
||||
<item quantity="one">%2$d karakter, %1$s</item>
|
||||
<item quantity="other">%2$d karakter, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Vaku be- vagy kikapcsolása</string>
|
||||
<string name="share">Megosztás</string>
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="switch_camera">Kamera átkapcsolása</string>
|
||||
<string name="history">Előzmények</string>
|
||||
<string name="preferences">Beállítások</string>
|
||||
<string name="open_immediately">Skip inspection and open contents immediately</string>
|
||||
<string name="open_immediately">Vizsgálat kihagyása és a tartalom azonnali megnyitása</string>
|
||||
<string name="use_history">Beolvasási előzmények mentése</string>
|
||||
<string name="open_with_url">Ismeretlen adat megnyitása URL-lel</string>
|
||||
<string name="really_remove_scan">Valóban eltávolítja a beolvasást?</string>
|
||||
@@ -67,7 +67,7 @@
|
||||
<string name="no">Nem</string>
|
||||
<string name="csv_allow_binary_message">Valószínűleg ezt nem szeretné engedélyezni, mivel tönkre fogja tenni a fájlformátumot, és a szövegszerkesztők talán nem fogják tudni többé olvasni.</string>
|
||||
<string name="saved_in_downloads">Elmentve a letöltésekbe</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
<string name="pick_code_to_scan">Pick code to scan</string>
|
||||
<string name="rotate_image_cw">Kép forgatása jobbra</string>
|
||||
<string name="pick_file">Képfájl kiválasztása</string>
|
||||
<string name="pick_code_to_scan">Kód kiválasztása a beolvasáshoz</string>
|
||||
</resources>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<string name="compose_barcode">Buat barcode</string>
|
||||
<string name="decode_barcode">Dekode barcode</string>
|
||||
<string name="content">Konten</string>
|
||||
<string name="binary_data">(data binari)</string>
|
||||
<string name="binary_data">(data biner)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d karakter</item>
|
||||
<item quantity="other">%1$s\n%2$d karakter</item>
|
||||
<item quantity="one">%1$s, %2$d karakter</item>
|
||||
<item quantity="other">%1$s, %2$d karakter</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Nyala/Matikan blitz</string>
|
||||
<string name="share">Bagikan</string>
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="switch_camera">Ganti kamera</string>
|
||||
<string name="history">Riwayat</string>
|
||||
<string name="preferences">Preferensi</string>
|
||||
<string name="open_immediately">Skip inspection and open contents immediately</string>
|
||||
<string name="open_immediately">Lewati inspeksi dan segera buka konten</string>
|
||||
<string name="use_history">Simpan riwayat pemindaian</string>
|
||||
<string name="open_with_url">Buka data tak dikenal dengan URL</string>
|
||||
<string name="really_remove_scan">Yakin menghapus pemindaian?</string>
|
||||
@@ -63,11 +63,11 @@
|
||||
<string name="csv_delimiter">Karakter pemisah apa yang harus digunakan (Berkas-CSV)?</string>
|
||||
<string name="delimiter_comma">Koma</string>
|
||||
<string name="delimiter_semicolon">Titik koma</string>
|
||||
<string name="csv_allow_binary">Izinkan data binari di dalam berkas keluaran?</string>
|
||||
<string name="csv_allow_binary">Izinkan data biner di dalam berkas keluaran?</string>
|
||||
<string name="no">Tidak</string>
|
||||
<string name="csv_allow_binary_message">Anda sebaiknya tidak mengizinkannya, karena akan merusak format berkas dan kemungkinan tidak bisa lagi dibaca oleh aplikasi penyunting teks.</string>
|
||||
<string name="saved_in_downloads">Simpan di dalam unduhan</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
<string name="pick_code_to_scan">Pick code to scan</string>
|
||||
<string name="rotate_image_cw">Putar gambar searah jarum jam</string>
|
||||
<string name="pick_file">Pilih berkas gambar</string>
|
||||
<string name="pick_code_to_scan">Pilih kode untuk dipindai</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<resources>
|
||||
<string name="no_camera_no_fun">Quest\'app non ha alcuna utilità senza accesso alla camera. Addio.</string>
|
||||
<string name="camera_error">Impossibile accedere alla camera. Riprovare</string>
|
||||
<string name="scan_code">Codice</string>
|
||||
<string name="no_camera_no_fun">Quest\'app non ha alcun senso senza l\'accesso alla fotocamera. Ciao.</string>
|
||||
<string name="camera_error">Impossibile accedere alla fotocamera, riprova</string>
|
||||
<string name="scan_code">Scansiona codice</string>
|
||||
<string name="compose_barcode">Crea codice a barre</string>
|
||||
<string name="decode_barcode">Decodifica codice a barre</string>
|
||||
<string name="content">Contenuto</string>
|
||||
<string name="binary_data">(dati binari)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d carattere</item>
|
||||
<item quantity="other">%1$s\n%2$d caratteri</item>
|
||||
<item quantity="one">%2$d carattere, %1$s</item>
|
||||
<item quantity="other">%2$d caratteri, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Flash</string>
|
||||
<string name="share">Condividi</string>
|
||||
@@ -20,44 +20,44 @@
|
||||
<string name="format">Formato</string>
|
||||
<string name="size">Dimensioni in pixel</string>
|
||||
<string name="width_by_height">%1$d×%2$d</string>
|
||||
<string name="input_content_here">Contenuto input qui</string>
|
||||
<string name="input_content_here">Inserisci il contenuto qui</string>
|
||||
<string name="encode">CODIFICA</string>
|
||||
<string name="error_no_content">Contenuto mancante</string>
|
||||
<string name="error_encoding_barcode">Il codice a barre non può essere generato</string>
|
||||
<string name="view_barcode">Vedi codice a barre</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="switch_camera">Cambia camera</string>
|
||||
<string name="switch_camera">Cambia fotocamera</string>
|
||||
<string name="history">Cronologia</string>
|
||||
<string name="preferences">Preferences</string>
|
||||
<string name="open_immediately">Skip inspection and open contents immediately</string>
|
||||
<string name="preferences">Preferenze</string>
|
||||
<string name="open_immediately">Salta l\'analisi e apri i contenuti direttamente</string>
|
||||
<string name="use_history">Salva cronologia delle scansioni</string>
|
||||
<string name="open_with_url">Apri dati sconosciuti con URL</string>
|
||||
<string name="really_remove_scan">Vuoi veramente rimuovere la scansione?</string>
|
||||
<string name="really_remove_all_scans">Vuoi veramente rimuovere tutte le scansioni?</string>
|
||||
<string name="clear_history">Pulisci cronologia</string>
|
||||
<string name="no_barcode_found">Nessun codice a barre trovato</string>
|
||||
<string name="pick_list_separator">Come separare elementi di una lista?</string>
|
||||
<string name="pick_list_separator">Come separare elementi della lista?</string>
|
||||
<string name="separator_line_break">Interruzione di linea</string>
|
||||
<string name="separator_ruler">Righello</string>
|
||||
<string name="save_as_file_name">Salvare come file?</string>
|
||||
<string name="file_name">Nome del file</string>
|
||||
<string name="error_saving_binary_data">Impossibile salvare il file</string>
|
||||
<string name="error_file_exists">Il File esiste già</string>
|
||||
<string name="connect_to_wifi">Connecti al WiFi</string>
|
||||
<string name="error_file_exists">Il file esiste già</string>
|
||||
<string name="connect_to_wifi">Connetti al WiFi</string>
|
||||
<string name="wifi_config_failed">Impossibile configurare il WiFi</string>
|
||||
<string name="wifi_added">WiFi aggiunto</string>
|
||||
<string name="sms_send">Invia SMS</string>
|
||||
<string name="sms_error">Impossibile inviare SMS</string>
|
||||
<string name="tel_dial">Componi numero</string>
|
||||
<string name="tel_error">Impossibile comporre il numero</string>
|
||||
<string name="mail_send">Invia mail</string>
|
||||
<string name="mail_error">Impossibile inviare la mail</string>
|
||||
<string name="mail_send">Invia email</string>
|
||||
<string name="mail_error">Impossibile inviare l\'email</string>
|
||||
<string name="vcard_add">Aggiungi ai contatti</string>
|
||||
<string name="vcard_failed">Impossibile aggiungere ai contatti</string>
|
||||
<string name="vevent_add">Aggiungi al calendario</string>
|
||||
<string name="vevent_failed">Impossibile aggiungere al calendario</string>
|
||||
<string name="otpauth_add">Aggiungi 2FA</string>
|
||||
<string name="otpauth_error">Impossibile aggiungre il 2FA</string>
|
||||
<string name="otpauth_error">Impossibile aggiungre la 2FA</string>
|
||||
<string name="search_web">Cerca nel web</string>
|
||||
<string name="export_to_file">Esporta su file</string>
|
||||
<string name="csv_delimiter">Quale delimitatore usare (File-CSV)?</string>
|
||||
@@ -65,9 +65,9 @@
|
||||
<string name="delimiter_semicolon">Punto e virgola</string>
|
||||
<string name="csv_allow_binary">Permetti dati binari nel file di output?</string>
|
||||
<string name="no">No</string>
|
||||
<string name="csv_allow_binary_message">È consigliato non permetterlo, perché rompe il formato del file e probabilmente lo renderà non più leggibile dagli editor di testo.</string>
|
||||
<string name="csv_allow_binary_message">È consigliato non permetterlo, perché rovina il formato del file e probabilmente lo renderà non più leggibile dagli editor di testo.</string>
|
||||
<string name="saved_in_downloads">Salvato nei download</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
<string name="pick_code_to_scan">Pick code to scan</string>
|
||||
<string name="rotate_image_cw">Ruota immagine in senso orario</string>
|
||||
<string name="pick_file">Scegli file immagine</string>
|
||||
<string name="pick_code_to_scan">Scegli codice da scansionare</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<string name="content">Inhoud</string>
|
||||
<string name="binary_data">(binaire data)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d character</item>
|
||||
<item quantity="other">%1$s\n%2$d characters</item>
|
||||
<item quantity="one">%2$d character, %1$s</item>
|
||||
<item quantity="other">%2$d characters, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Flitslicht schakelen</string>
|
||||
<string name="share">Delen</string>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<string name="content">Conteúdo</string>
|
||||
<string name="binary_data">(binários)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d cacractere</item>
|
||||
<item quantity="other">%1$s\n%2$d caracteres</item>
|
||||
<item quantity="one">%2$d caractere, %1$s</item>
|
||||
<item quantity="other">%2$d caracteres, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Ativar lanterna</string>
|
||||
<string name="share">Compartilhar</string>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<resources>
|
||||
<string name="no_camera_no_fun">没有相机权限,这个软件有啥意义。再见!</string>
|
||||
<string name="no_camera_no_fun">没有给我相机权限,扫个锤子。再见!</string>
|
||||
<string name="camera_error">无法访问相机,请重试。</string>
|
||||
<string name="scan_code">Scan code</string>
|
||||
<string name="scan_code">扫描</string>
|
||||
<string name="compose_barcode">制作条形码</string>
|
||||
<string name="decode_barcode">解码条形码</string>
|
||||
<string name="content">内容</string>
|
||||
<string name="binary_data">(二进制数据)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d 字符</item>
|
||||
<item quantity="other">%1$s\n%2$d 字符</item>
|
||||
<item quantity="one">%2$d 字符, %1$s</item>
|
||||
<item quantity="other">%2$d 字符, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">切换闪光灯</string>
|
||||
<string name="toggle_flash">开关闪光灯</string>
|
||||
<string name="share">分享</string>
|
||||
<string name="copy_to_clipboard">复制到剪切板</string>
|
||||
<string name="put_into_clipboard">复制到剪切板</string>
|
||||
<string name="open_url">打开链接</string>
|
||||
<string name="cannot_resolve_action">没有应用程序可以打开它</string>
|
||||
<string name="cannot_resolve_action">没有相关APP可以打开它</string>
|
||||
<string name="pick_search_engine">选择一个搜索引擎</string>
|
||||
<string name="format">编码格式</string>
|
||||
<string name="size">图片尺寸</string>
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="switch_camera">切换摄像头</string>
|
||||
<string name="history">历史</string>
|
||||
<string name="preferences">首选项</string>
|
||||
<string name="open_immediately">Skip inspection and open contents immediately</string>
|
||||
<string name="open_immediately">跳过内容展示并立即打开</string>
|
||||
<string name="use_history">保存扫描历史</string>
|
||||
<string name="open_with_url">使用URL打开未知数据</string>
|
||||
<string name="really_remove_scan">确定删除记录?</string>
|
||||
@@ -56,18 +56,18 @@
|
||||
<string name="vcard_failed">无法添加到通讯录</string>
|
||||
<string name="vevent_add">添加到日历</string>
|
||||
<string name="vevent_failed">无法添加到日历</string>
|
||||
<string name="otpauth_add">Add 2FA</string>
|
||||
<string name="otpauth_error">Could not add 2FA</string>
|
||||
<string name="search_web">Search the web</string>
|
||||
<string name="export_to_file">Export to file</string>
|
||||
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
|
||||
<string name="delimiter_comma">Comma</string>
|
||||
<string name="delimiter_semicolon">Semicolon</string>
|
||||
<string name="csv_allow_binary">Allow binary data in output file?</string>
|
||||
<string name="no">No</string>
|
||||
<string name="csv_allow_binary_message">You probably don\'t want to allow that, as it will break the file format and maybe isn\'t readable by text editors anymore.</string>
|
||||
<string name="saved_in_downloads">Saved in downloads</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
<string name="pick_code_to_scan">Pick code to scan</string>
|
||||
<string name="otpauth_add">添加两步验证</string>
|
||||
<string name="otpauth_error">无法添加两步验证</string>
|
||||
<string name="search_web">在互联网中搜索</string>
|
||||
<string name="export_to_file">导出为CSV文件</string>
|
||||
<string name="csv_delimiter">使用哪个分隔符 (CSV-文件)?</string>
|
||||
<string name="delimiter_comma">逗号</string>
|
||||
<string name="delimiter_semicolon">分号</string>
|
||||
<string name="csv_allow_binary">允许输出文件中的二进制数据?</string>
|
||||
<string name="no">否</string>
|
||||
<string name="csv_allow_binary_message">您可能不想这样做,因为它会破坏文件格式,并且可能无法再由文本编辑器读取。</string>
|
||||
<string name="saved_in_downloads">已保存到下载目录</string>
|
||||
<string name="rotate_image_cw">旋转图片</string>
|
||||
<string name="pick_file">选择图片文件</string>
|
||||
<string name="pick_code_to_scan">选择扫描的编码</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<string name="content">内容</string>
|
||||
<string name="binary_data">(2進制碼)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d 個字符</item>
|
||||
<item quantity="other">%1$s\n%2$d 個字符</item>
|
||||
<item quantity="one">%2$d 個字符, %1$s</item>
|
||||
<item quantity="other">%2$d 個字符, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">閃光燈</string>
|
||||
<string name="share">分享</string>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<resources>
|
||||
<color name="primary">#222</color>
|
||||
<color name="primary_dark">#111</color>
|
||||
<color name="accent">#b6d46f</color>
|
||||
<color name="accent_dark">#a6c45f</color>
|
||||
<color name="background_color">#111</color>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<item>Google</item>
|
||||
<item>DuckDuckGo</item>
|
||||
<item>Qwant</item>
|
||||
<item>Bing</item>
|
||||
<item>Yandex</item>
|
||||
<item>OpenFoodFacts.org</item>
|
||||
<item>OpenBeautyFacts.org</item>
|
||||
<item>OpenPetFoodFacts.org</item>
|
||||
@@ -11,6 +13,8 @@
|
||||
<item>https://www.google.com/search?q=</item>
|
||||
<item>https://duckduckgo.com/?q=</item>
|
||||
<item>https://www.qwant.com/?q=</item>
|
||||
<item>https://bing.com/?q=</item>
|
||||
<item>https://yandex.com/?q=</item>
|
||||
<item>https://world.openfoodfacts.org/cgi/search.pl?search_terms=</item>
|
||||
<item>https://world.openbeautyfacts.org/cgi/search.pl?search_terms=</item>
|
||||
<item>https://world.openpetfoodfacts.org/cgi/search.pl?search_terms=</item>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<string name="content">Content</string>
|
||||
<string name="binary_data">(binary data)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="one">%1$s\n%2$d character</item>
|
||||
<item quantity="other">%1$s\n%2$d characters</item>
|
||||
<item quantity="one">%2$d character, %1$s</item>
|
||||
<item quantity="other">%2$d characters, %1$s</item>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Toggle flash</string>
|
||||
<string name="share">Share</string>
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
<resources>
|
||||
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primary_dark</item>
|
||||
<item name="colorPrimaryDark">@android:color/transparent</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="android:windowBackground">@drawable/background_window</item>
|
||||
</style>
|
||||
<style name="SplashTheme" parent="@style/AppTheme">
|
||||
<item name="android:windowBackground">@drawable/background_splash</item>
|
||||
</style>
|
||||
<style
|
||||
name="SecondaryText"
|
||||
parent="@android:style/Widget.TextView">
|
||||
<item name="android:textSize">12sp</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
</style>
|
||||
<style
|
||||
name="Button"
|
||||
parent="@android:style/Widget.Button">
|
||||
@@ -21,4 +27,13 @@
|
||||
<item name="android:paddingRight">@dimen/button_padding</item>
|
||||
<item name="android:maxLines">1</item>
|
||||
</style>
|
||||
<style
|
||||
name="FAB"
|
||||
parent="Widget.Design.FloatingActionButton">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_margin">20dp</item>
|
||||
<item name="android:layout_gravity">bottom|end</item>
|
||||
<item name="elevation">4dp</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<full-backup-content>
|
||||
<include domain="root" path="."/>
|
||||
</full-backup-content>
|
||||
@@ -7,7 +7,10 @@ fun simpleFail(message: String = "Unknown reason, but failed"): Nothing {
|
||||
throw IllegalStateException("You should never have reached this point in the code, but anyways: $message")
|
||||
}
|
||||
|
||||
inline fun <reified E : Throwable> assertThrows(message: String = "Unknown reason, but didn't failed even though should fail", block: () -> Unit) {
|
||||
inline fun <reified E : Throwable> assertThrows(
|
||||
message: String = "Unknown reason, but didn't failed even though should fail",
|
||||
block: () -> Unit
|
||||
) {
|
||||
try {
|
||||
block()
|
||||
fail(message)
|
||||
|
||||
+3
-6
@@ -1,10 +1,7 @@
|
||||
package de.markusfisch.android.binaryeye.actions.wifi
|
||||
|
||||
import de.markusfisch.android.binaryeye.simpleFail
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertFalse
|
||||
import junit.framework.TestCase.assertNull
|
||||
import junit.framework.TestCase.assertTrue
|
||||
import junit.framework.TestCase.*
|
||||
import org.junit.Test
|
||||
|
||||
class WifiConfigurationFactoryTest {
|
||||
@@ -86,8 +83,8 @@ class WifiConfigurationFactoryTest {
|
||||
|
||||
private fun simpleDataAccessor(wifiString: String): WifiConfigurationFactory.SimpleDataAccessor {
|
||||
val map = WifiConfigurationFactory.parseMap(wifiString)
|
||||
?: simpleFail("parsing map of valid string fails ($wifiString)")
|
||||
?: simpleFail("parsing map of valid string fails ($wifiString)")
|
||||
return WifiConfigurationFactory.SimpleDataAccessor.of(map)
|
||||
?: simpleFail("could not create SimpleDataAccessor of (potentially) valid map ($map of $wifiString)")
|
||||
?: simpleFail("could not create SimpleDataAccessor of (potentially) valid map ($map of $wifiString)")
|
||||
}
|
||||
}
|
||||
|
||||
+22
-5
@@ -1,9 +1,26 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
ext.tools_version = '3.5.2'
|
||||
ext.build_tools_version = '28.0.3'
|
||||
ext.sdk_version = 28
|
||||
ext.support_version = '25.3.1'
|
||||
// Since RenderScript can no longer be compiled on macOS Catalina
|
||||
// because Catalina cannot run 32bit binaries and Google failed
|
||||
// to provide a 64bit compiler in time. Now, as if that wasn't
|
||||
// bad enough, the new build tools that provide a 64bit compiler
|
||||
// don't work on any other system than macOS unfortunately.
|
||||
ext.is_catalina = {
|
||||
if (System.properties['os.name'] == 'Mac OS X') {
|
||||
def numbers = System.properties['os.version'].split('\\.')
|
||||
if (numbers.length > 1) {
|
||||
return numbers[1].toInteger() >= 15
|
||||
}
|
||||
}
|
||||
return false
|
||||
}()
|
||||
|
||||
ext {
|
||||
kotlin_version = '1.3.61'
|
||||
tools_version = '3.6.1'
|
||||
build_tools_version = ext.is_catalina ? '29.0.3' : '28.0.3'
|
||||
sdk_version = 29
|
||||
support_version = '25.3.1'
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
|
||||
Reference in New Issue
Block a user