Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
694ebf83ed | ||
|
|
78bb03fabf | ||
|
|
902215f064 | ||
|
|
eaf38729bd | ||
|
|
bdd89ca539 | ||
|
|
39ecd31455 | ||
|
|
c96a2cf3ec | ||
|
|
ea9e29b98c | ||
|
|
96e1ef5a52 | ||
|
|
ed4b0a75dd | ||
|
|
37354338cb | ||
|
|
3cd2eecc22 | ||
|
|
0e40d3f7c3 | ||
|
|
c8fa01116d | ||
|
|
04539b4c37 | ||
|
|
b9e8f4cfca | ||
|
|
ad06c2bf9e | ||
|
|
2c7ec74b1b | ||
|
|
b34f29c95f | ||
|
|
e11518c3f5 | ||
|
|
57c4fad307 | ||
|
|
856b8e37e1 | ||
|
|
6b8dd8e864 | ||
|
|
c993cd53f1 | ||
|
|
934983f668 | ||
|
|
ccf425faad | ||
|
|
a244763109 | ||
|
|
7ab712e040 | ||
|
|
cb7219b290 | ||
|
|
7f4ba50ee4 | ||
|
|
b1f00f0592 | ||
|
|
80f8f908d2 | ||
|
|
506308ece9 | ||
|
|
baecded9d5 | ||
|
|
ceefee397f | ||
|
|
e45804be31 | ||
|
|
edef1acbfb | ||
|
|
742939182c | ||
|
|
a21bfcdea6 | ||
|
|
bd281e449b | ||
|
|
0e1464a15f | ||
|
|
8a6441ddf3 | ||
|
|
94874c0a9e | ||
|
|
b9a6410959 | ||
|
|
512f5e00dd | ||
|
|
91c2364958 | ||
|
|
1e3f1c553c | ||
|
|
80c65a48a0 | ||
|
|
4c04ffb7db | ||
|
|
cc3949fa71 | ||
|
|
904a0ecbdd | ||
|
|
9155dd026d | ||
|
|
7286a06985 | ||
|
|
a71552a406 | ||
|
|
5857e8c394 | ||
|
|
429af04714 | ||
|
|
f134987572 | ||
|
|
d8a9043f94 | ||
|
|
3782fa8360 | ||
|
|
023e32f796 | ||
|
|
82f3abdc86 | ||
|
|
1345d31a6d | ||
|
|
c56fa39c15 | ||
|
|
7c8997ae9a | ||
|
|
584343c4e9 |
@@ -1,5 +1,51 @@
|
||||
# Change Log
|
||||
|
||||
## 1.9.0
|
||||
* Try Google when opening content as URL fails
|
||||
* Show generic error message if barcode generation fails
|
||||
|
||||
## 1.8.1
|
||||
* Distribute APK instead of App Bundle
|
||||
|
||||
## 1.8.0
|
||||
* Save binary data into external file
|
||||
* Fix storage of binary data
|
||||
* Remove horizontal orientation line from scanner
|
||||
|
||||
## 1.7.3
|
||||
* Fix crashes on Lineage and remove RenderScript fallback
|
||||
* Improve handling of binary data
|
||||
|
||||
## 1.7.2
|
||||
* Add a fallback for RenderScript
|
||||
* Add italian translation
|
||||
|
||||
## 1.7.1
|
||||
* Fix support for 64 bit architectures
|
||||
|
||||
## 1.7.0
|
||||
* Pick list separator on sharing history listing
|
||||
* Update Hungarian translation
|
||||
|
||||
## 1.6.0
|
||||
* Share history listing as plain text
|
||||
* Add separator line between history items
|
||||
* Add content description for floating action buttons
|
||||
|
||||
## 1.5.1
|
||||
* Fix generating hex dump
|
||||
|
||||
## 1.5.0
|
||||
* Show a hex dump of decoded contents
|
||||
* Fix processing text from share menu
|
||||
* Add French translation
|
||||
|
||||
## 1.4.3
|
||||
* Fix broken history listing
|
||||
|
||||
## 1.4.2
|
||||
* Show barcode type and content length after decoding
|
||||
|
||||
## 1.4.1
|
||||
* Toggle availability of torch mode button according to camera features
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Contribution Guidelines
|
||||
|
||||
Please try to keep things in good shape and comply to what's there.
|
||||
|
||||
This project follows Android [best practices][android_best_practices]
|
||||
so please have a look if you've never heard of them.
|
||||
|
||||
The code is formatted according to Android Studio's standard, with the
|
||||
exception of indent being tabs instead of spaces.
|
||||
|
||||
Use the feature branch workflow to add new features and make sure
|
||||
to squash when merging into master:
|
||||
|
||||
$ git merge cool_feature --squash
|
||||
|
||||
Then write a [good commit messages][commit_messages] to keep the history
|
||||
meaningful and useful. One feature, one commit.
|
||||
|
||||
[android_best_practices]: https://developer.android.com/distribute/best-practices/develop/
|
||||
[commit_messages]: https://juffalow.com/other/write-good-git-commit-message
|
||||
@@ -1,5 +1,4 @@
|
||||
PACKAGE = de.markusfisch.android.binaryeye
|
||||
APK = app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
all: debug install start
|
||||
|
||||
@@ -7,11 +6,10 @@ debug:
|
||||
./gradlew assembleDebug
|
||||
|
||||
release: lint
|
||||
@./gradlew assembleRelease \
|
||||
-Pandroid.injected.signing.store.file=$(ANDROID_KEYFILE) \
|
||||
-Pandroid.injected.signing.store.password=$(ANDROID_STORE_PASSWORD) \
|
||||
-Pandroid.injected.signing.key.alias=$(ANDROID_KEY_ALIAS) \
|
||||
-Pandroid.injected.signing.key.password=$(ANDROID_KEY_PASSWORD)
|
||||
./gradlew assembleRelease
|
||||
|
||||
bundle: lint
|
||||
./gradlew bundleRelease
|
||||
|
||||
lint:
|
||||
./gradlew lintDebug
|
||||
@@ -26,7 +24,7 @@ test:
|
||||
./gradlew cAT
|
||||
|
||||
install:
|
||||
adb $(TARGET) install -r $(APK)
|
||||
adb $(TARGET) install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
start:
|
||||
adb $(TARGET) shell 'am start -n \
|
||||
|
||||
@@ -9,7 +9,7 @@ Unlike many others it works in portrait and landscape orientation, can read
|
||||
inverted codes, uses Material Design and doesn't do anything else but decoding
|
||||
a barcode.
|
||||
|
||||
<a href="https://f-droid.org/en/packages/de.markusfisch.android.binaryeye/"><img alt="Get it on F-Droid" src="https://f-droid.org/badge/get-it-on.png" height="80"/></a> <a href="https://play.google.com/store/apps/details?id=de.markusfisch.android.binaryeye"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" height="80"/></a>
|
||||
<a href="https://f-droid.org/en/packages/de.markusfisch.android.binaryeye/"><img alt="Get it on F-Droid" src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="80"/></a> <a href="https://play.google.com/store/apps/details?id=de.markusfisch.android.binaryeye"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" height="80"/></a>
|
||||
|
||||
And it's written in [Kotlin][kotlin] because I wanted to explore that a
|
||||
bit more.
|
||||
|
||||
+17
-12
@@ -1,10 +1,5 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'net.ltgt.errorprone'
|
||||
|
||||
configurations.errorprone {
|
||||
resolutionStrategy.force 'com.google.errorprone:error_prone_core:2.0.19'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion sdk_version
|
||||
@@ -14,18 +9,29 @@ android {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion sdk_version
|
||||
|
||||
versionCode 16
|
||||
versionName '1.4.1'
|
||||
versionCode 28
|
||||
versionName '1.9.0'
|
||||
|
||||
// it's recommended to set this value to the lowest API level
|
||||
// able to provide all the functionality
|
||||
renderscriptTargetApi 18
|
||||
renderscriptTargetApi 24
|
||||
renderscriptSupportModeEnabled true
|
||||
|
||||
testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
config {
|
||||
keyAlias System.getenv('ANDROID_KEY_ALIAS')
|
||||
keyPassword System.getenv('ANDROID_KEY_PASSWORD')
|
||||
storePassword System.getenv('ANDROID_STORE_PASSWORD')
|
||||
def filePath = System.getenv('ANDROID_KEYFILE')
|
||||
storeFile filePath ? file(filePath) : null
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
androidTest.java.srcDirs += 'src/androidTest/kotlin'
|
||||
}
|
||||
|
||||
@@ -35,11 +41,10 @@ android {
|
||||
}
|
||||
|
||||
release {
|
||||
proguardFiles \
|
||||
getDefaultProguardFile('proguard-android.txt'), \
|
||||
'proguard-rules.pro'
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
signingConfig signingConfigs.config
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,5 +70,5 @@ dependencies {
|
||||
implementation "com.android.support:appcompat-v7:$support_version"
|
||||
implementation "com.android.support:design:$support_version"
|
||||
implementation 'com.google.zxing:core:3.3.3'
|
||||
implementation 'com.github.markusfisch:CameraView:1.8.2'
|
||||
implementation 'com.github.markusfisch:CameraView:1.8.3'
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package de.markusfisch.android.binaryeye.activity
|
||||
|
||||
import com.google.zxing.Result
|
||||
import com.google.zxing.ResultMetadataType
|
||||
|
||||
import de.markusfisch.android.cameraview.widget.CameraView
|
||||
|
||||
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.rs.Preprocessor
|
||||
@@ -21,8 +23,6 @@ import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.os.Vibrator
|
||||
import android.provider.MediaStore
|
||||
import android.support.v4.app.ActivityCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.Menu
|
||||
@@ -38,31 +38,18 @@ import java.io.IOException
|
||||
|
||||
class CameraActivity : AppCompatActivity() {
|
||||
private val zxing = Zxing()
|
||||
private val decodingRunnable = Runnable {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
val result = decodeFrame()
|
||||
if (result != null) {
|
||||
cameraView.post { found(result) }
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var vibrator: Vibrator
|
||||
private lateinit var cameraView: CameraView
|
||||
private lateinit var zoomBar: SeekBar
|
||||
private lateinit var flashFab: View
|
||||
|
||||
private var decodingThread: Thread? = null
|
||||
private var preprocessor: Preprocessor? = null
|
||||
private var frameData: ByteArray? = null
|
||||
private var frameWidth: Int = 0
|
||||
private var frameHeight: Int = 0
|
||||
private var frameOrientation: Int = 0
|
||||
private var invert = false
|
||||
private var flash = false
|
||||
private var returnResult = false
|
||||
private var frontFacing = false
|
||||
private var fallbackBuffer: IntArray? = null
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
@@ -70,8 +57,9 @@ class CameraActivity : AppCompatActivity() {
|
||||
grantResults: IntArray
|
||||
) {
|
||||
when (requestCode) {
|
||||
REQUEST_CAMERA -> if (grantResults.size > 0 &&
|
||||
grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
REQUEST_CAMERA -> if (grantResults.isNotEmpty() &&
|
||||
grantResults[0] != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
R.string.no_camera_no_fun,
|
||||
@@ -94,14 +82,14 @@ class CameraActivity : AppCompatActivity() {
|
||||
cameraView = findViewById(R.id.camera_view) as CameraView
|
||||
zoomBar = findViewById(R.id.zoom) as SeekBar
|
||||
flashFab = findViewById(R.id.flash)
|
||||
flashFab.setOnClickListener { _ -> toggleTorchMode() }
|
||||
flashFab.setOnClickListener { toggleTorchMode() }
|
||||
|
||||
initCameraView()
|
||||
initZoomBar()
|
||||
restoreZoom()
|
||||
|
||||
if (intent?.action == Intent.ACTION_SEND) {
|
||||
if ("text/plain" == intent.type) {
|
||||
if (intent.type == "text/plain") {
|
||||
handleSendText(intent)
|
||||
} else if (intent.type?.startsWith("image/") == true) {
|
||||
handleSendImage(intent)
|
||||
@@ -112,16 +100,15 @@ class CameraActivity : AppCompatActivity() {
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
preprocessor?.destroy()
|
||||
fallbackBuffer = null
|
||||
saveZoom()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
System.gc()
|
||||
returnResult = "com.google.zxing.client.android.SCAN".equals(
|
||||
intent.action
|
||||
)
|
||||
if (hasCameraPermission()) {
|
||||
returnResult = "com.google.zxing.client.android.SCAN" == intent.action
|
||||
if (hasCameraPermission(this, REQUEST_CAMERA)) {
|
||||
openCamera()
|
||||
}
|
||||
}
|
||||
@@ -144,7 +131,6 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun closeCamera() {
|
||||
cancelDecoding()
|
||||
cameraView.close()
|
||||
}
|
||||
|
||||
@@ -204,18 +190,15 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun handleSendText(intent: Intent) {
|
||||
var text = intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
if (text?.isEmpty() == true) {
|
||||
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
if (text?.isEmpty() == false) {
|
||||
startActivity(MainActivity.getEncodeIntent(this, text, true))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSendImage(intent: Intent) {
|
||||
var uri = intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri
|
||||
if (uri == null) {
|
||||
return
|
||||
}
|
||||
val uri = intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri ?: return
|
||||
val bitmap = try {
|
||||
MediaStore.Images.Media.getBitmap(contentResolver, uri)
|
||||
} catch (e: IOException) {
|
||||
@@ -229,7 +212,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
).show()
|
||||
return
|
||||
}
|
||||
val result = zxing.decode(downsizeIfBigger(bitmap, 1024))
|
||||
val result = zxing.decodePositiveNegative(downsizeIfBigger(bitmap, 1024))
|
||||
if (result != null) {
|
||||
showResult(result)
|
||||
finish()
|
||||
@@ -243,21 +226,6 @@ class CameraActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun hasCameraPermission(): Boolean {
|
||||
val permission = android.Manifest.permission.CAMERA
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, permission) !=
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(
|
||||
this, arrayOf(permission),
|
||||
REQUEST_CAMERA
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun initCameraView() {
|
||||
cameraView.setUseOrientationListener(true)
|
||||
cameraView.setTapToFocus()
|
||||
@@ -265,21 +233,21 @@ class CameraActivity : AppCompatActivity() {
|
||||
override fun onConfigureParameters(
|
||||
parameters: Camera.Parameters
|
||||
) {
|
||||
if (parameters.isZoomSupported()) {
|
||||
val max = parameters.getMaxZoom()
|
||||
if (parameters.isZoomSupported) {
|
||||
val max = parameters.maxZoom
|
||||
if (zoomBar.max != max) {
|
||||
zoomBar.max = max
|
||||
zoomBar.progress = max / 10
|
||||
saveZoom()
|
||||
}
|
||||
parameters.setZoom(zoomBar.progress)
|
||||
parameters.zoom = zoomBar.progress
|
||||
} else {
|
||||
zoomBar.visibility = View.GONE
|
||||
}
|
||||
val sceneModes = parameters.supportedSceneModes
|
||||
sceneModes?.let {
|
||||
for (mode in sceneModes) {
|
||||
if (mode.equals(Camera.Parameters.SCENE_MODE_BARCODE)) {
|
||||
if (mode == Camera.Parameters.SCENE_MODE_BARCODE) {
|
||||
parameters.sceneMode = mode
|
||||
break
|
||||
}
|
||||
@@ -299,18 +267,33 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun onCameraReady(camera: Camera) {
|
||||
frameWidth = cameraView.frameWidth
|
||||
frameHeight = cameraView.frameHeight
|
||||
frameOrientation = cameraView.frameOrientation
|
||||
camera.setPreviewCallback { data, _ -> frameData = data }
|
||||
val frameWidth = cameraView.frameWidth
|
||||
val frameHeight = cameraView.frameHeight
|
||||
val frameOrientation = cameraView.frameOrientation
|
||||
var decoding = true
|
||||
camera.setPreviewCallback { frameData, _ ->
|
||||
if (decoding) {
|
||||
val result = decodeFrame(
|
||||
frameData,
|
||||
frameWidth,
|
||||
frameHeight,
|
||||
frameOrientation
|
||||
)
|
||||
result?.let {
|
||||
cameraView.post {
|
||||
vibrator.vibrate(100)
|
||||
showResult(result)
|
||||
}
|
||||
decoding = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreviewStarted(camera: Camera) {
|
||||
startDecoding()
|
||||
}
|
||||
|
||||
override fun onCameraStopping(camera: Camera) {
|
||||
cancelDecoding()
|
||||
camera.setPreviewCallback(null)
|
||||
}
|
||||
})
|
||||
@@ -334,12 +317,12 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun setZoom(zoom: Int) {
|
||||
val camera: Camera? = cameraView.getCamera()
|
||||
val camera: Camera? = cameraView.camera
|
||||
camera?.let {
|
||||
try {
|
||||
val params = camera.getParameters()
|
||||
params.setZoom(zoom)
|
||||
camera.setParameters(params)
|
||||
val params = camera.parameters
|
||||
params.zoom = zoom
|
||||
camera.parameters = params
|
||||
} catch (e: RuntimeException) {
|
||||
// ignore; there's nothing we can do
|
||||
}
|
||||
@@ -370,18 +353,16 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun toggleTorchMode() {
|
||||
val camera = cameraView.getCamera()
|
||||
val parameters = camera?.getParameters()
|
||||
parameters?.setFlashMode(
|
||||
if (flash) {
|
||||
Camera.Parameters.FLASH_MODE_OFF
|
||||
} else {
|
||||
Camera.Parameters.FLASH_MODE_TORCH
|
||||
}
|
||||
)
|
||||
val camera = cameraView.camera
|
||||
val parameters = camera?.parameters
|
||||
parameters?.flashMode = if (flash) {
|
||||
Camera.Parameters.FLASH_MODE_OFF
|
||||
} else {
|
||||
Camera.Parameters.FLASH_MODE_TORCH
|
||||
}
|
||||
parameters?.let {
|
||||
try {
|
||||
camera.setParameters(parameters)
|
||||
camera.parameters = parameters
|
||||
flash = flash xor true
|
||||
} catch (e: RuntimeException) {
|
||||
// ignore; there's nothing we can do
|
||||
@@ -389,59 +370,39 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun startDecoding() {
|
||||
frameData = null
|
||||
decodingThread = Thread(decodingRunnable)
|
||||
decodingThread?.start()
|
||||
}
|
||||
|
||||
private fun cancelDecoding() {
|
||||
if (decodingThread != null) {
|
||||
decodingThread?.interrupt()
|
||||
try {
|
||||
decodingThread?.join()
|
||||
} catch (e: InterruptedException) {
|
||||
// parent thread was interrupted
|
||||
}
|
||||
decodingThread = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun decodeFrame(): Result? {
|
||||
var fd = frameData
|
||||
fd ?: return null
|
||||
if (preprocessor == null) {
|
||||
preprocessor = Preprocessor(
|
||||
this,
|
||||
frameWidth,
|
||||
frameHeight,
|
||||
frameOrientation
|
||||
)
|
||||
}
|
||||
var pp = preprocessor
|
||||
pp ?: return null
|
||||
pp.process(fd)
|
||||
private fun decodeFrame(
|
||||
frameData: ByteArray?,
|
||||
frameWidth: Int,
|
||||
frameHeight: Int,
|
||||
frameOrientation: Int
|
||||
): Result? {
|
||||
frameData ?: return null
|
||||
invert = invert xor true
|
||||
val pp = preprocessor ?: Preprocessor(
|
||||
this,
|
||||
frameWidth,
|
||||
frameHeight,
|
||||
frameOrientation
|
||||
)
|
||||
pp.process(frameData)
|
||||
preprocessor = pp
|
||||
return zxing.decode(
|
||||
fd,
|
||||
frameData,
|
||||
pp.outWidth,
|
||||
pp.outHeight,
|
||||
invert
|
||||
)
|
||||
}
|
||||
|
||||
private fun found(result: Result) {
|
||||
cancelDecoding()
|
||||
vibrator.vibrate(100)
|
||||
showResult(result)
|
||||
}
|
||||
|
||||
private fun showResult(result: Result) {
|
||||
val rawBytes = getRawBytes(result)
|
||||
|
||||
if (prefs.useHistory) {
|
||||
GlobalScope.launch {
|
||||
db.insertScan(
|
||||
System.currentTimeMillis(),
|
||||
result.text,
|
||||
rawBytes,
|
||||
result.barcodeFormat.toString()
|
||||
)
|
||||
}
|
||||
@@ -459,7 +420,8 @@ class CameraActivity : AppCompatActivity() {
|
||||
MainActivity.getDecodeIntent(
|
||||
this,
|
||||
result.text,
|
||||
result.barcodeFormat
|
||||
result.barcodeFormat,
|
||||
rawBytes
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -478,12 +440,12 @@ fun downsizeIfBigger(bitmap: Bitmap, max: Int): Bitmap {
|
||||
if (bitmap.width > bitmap.height) {
|
||||
height = Math.round(
|
||||
width.toFloat() / bitmap.width.toFloat() *
|
||||
bitmap.height.toFloat()
|
||||
bitmap.height.toFloat()
|
||||
)
|
||||
} else {
|
||||
width = Math.round(
|
||||
height.toFloat() / bitmap.height.toFloat() *
|
||||
bitmap.width.toFloat()
|
||||
bitmap.width.toFloat()
|
||||
)
|
||||
}
|
||||
Bitmap.createScaledBitmap(bitmap, width, height, true)
|
||||
@@ -491,3 +453,14 @@ fun downsizeIfBigger(bitmap: Bitmap, max: Int): Bitmap {
|
||||
bitmap
|
||||
}
|
||||
}
|
||||
|
||||
fun getRawBytes(result: Result): ByteArray? {
|
||||
val metadata = result.resultMetadata ?: return null
|
||||
val segments = metadata[ResultMetadataType.BYTE_SEGMENTS] ?: return null
|
||||
var bytes = ByteArray(0)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
for (seg in segments as Iterable<ByteArray>) {
|
||||
bytes += seg
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import de.markusfisch.android.binaryeye.R
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
|
||||
@@ -36,32 +35,29 @@ class MainActivity : AppCompatActivity() {
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
if (state == null) {
|
||||
var fragment: Fragment
|
||||
if (intent?.hasExtra(HISTORY) == true) {
|
||||
fragment = HistoryFragment()
|
||||
} else if (intent?.hasExtra(ENCODE) == true) {
|
||||
fragment = EncodeFragment.newInstance(
|
||||
setFragment(supportFragmentManager, when {
|
||||
intent?.hasExtra(HISTORY) == true -> HistoryFragment()
|
||||
intent?.hasExtra(ENCODE) == true -> EncodeFragment.newInstance(
|
||||
intent.getStringExtra(ENCODE)
|
||||
)
|
||||
} else if (intent?.hasExtra(DECODE) == true) {
|
||||
fragment = DecodeFragment.newInstance(
|
||||
intent.getStringExtra(DECODE),
|
||||
intent?.hasExtra(DECODED_TEXT) == true -> DecodeFragment.newInstance(
|
||||
intent.getStringExtra(DECODED_TEXT),
|
||||
intent.getSerializableExtra(
|
||||
DECODE_FORMAT
|
||||
) as BarcodeFormat
|
||||
DECODED_FORMAT
|
||||
) as BarcodeFormat,
|
||||
intent.getByteArrayExtra(DECODED_RAW)
|
||||
)
|
||||
} else {
|
||||
fragment = DecodeFragment()
|
||||
}
|
||||
setFragment(supportFragmentManager, fragment)
|
||||
else -> DecodeFragment()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val HISTORY = "history"
|
||||
private const val ENCODE = "encode"
|
||||
private const val DECODE = "decode"
|
||||
private const val DECODE_FORMAT = "decode_format"
|
||||
private const val DECODED_TEXT = "decoded_text"
|
||||
private const val DECODED_FORMAT = "decoded_format"
|
||||
private const val DECODED_RAW = "decoded_raw"
|
||||
|
||||
fun getHistoryIntent(context: Context): Intent {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
@@ -78,9 +74,9 @@ class MainActivity : AppCompatActivity() {
|
||||
intent.putExtra(ENCODE, text)
|
||||
if (isExternal) {
|
||||
intent.addFlags(
|
||||
android.content.Intent.FLAG_ACTIVITY_NO_HISTORY or
|
||||
android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
||||
android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
Intent.FLAG_ACTIVITY_NO_HISTORY or
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
)
|
||||
}
|
||||
return intent
|
||||
@@ -89,11 +85,15 @@ class MainActivity : AppCompatActivity() {
|
||||
fun getDecodeIntent(
|
||||
context: Context,
|
||||
text: String,
|
||||
format: BarcodeFormat
|
||||
format: BarcodeFormat,
|
||||
raw: ByteArray? = null
|
||||
): Intent {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra(DECODE, text)
|
||||
intent.putExtra(DECODE_FORMAT, format)
|
||||
intent.putExtra(DECODED_TEXT, text)
|
||||
intent.putExtra(DECODED_FORMAT, format)
|
||||
if (raw != null) {
|
||||
intent.putExtra(DECODED_RAW, raw)
|
||||
}
|
||||
return intent
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,13 @@ class ScansAdapter(context: Context, cursor: Cursor) :
|
||||
cursor: Cursor
|
||||
) {
|
||||
val holder = getViewHolder(view)
|
||||
val content = cursor.getString(contentIndex)
|
||||
holder.timeView.text = cursor.getString(timeIndex)
|
||||
holder.contentView.text = cursor.getString(contentIndex)
|
||||
holder.contentView.text = if (content.isEmpty()) {
|
||||
context.getString(R.string.binary_data)
|
||||
} else {
|
||||
content
|
||||
}
|
||||
holder.formatView.text = cursor.getString(formatIndex)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import de.markusfisch.android.binaryeye.data.Database
|
||||
import de.markusfisch.android.binaryeye.preference.Preferences
|
||||
|
||||
import android.app.Application
|
||||
import android.support.v8.renderscript.RenderScript
|
||||
|
||||
val db = Database()
|
||||
val prefs = Preferences()
|
||||
@@ -11,6 +12,11 @@ val prefs = Preferences()
|
||||
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()
|
||||
|
||||
db.open(this)
|
||||
prefs.init(this)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentManager
|
||||
import android.support.v4.app.FragmentTransaction
|
||||
@@ -14,6 +15,7 @@ fun addFragment(fm: FragmentManager?, fragment: Fragment) {
|
||||
fm?.let { getTransaction(fm, fragment).addToBackStack(null).commit() }
|
||||
}
|
||||
|
||||
@SuppressLint("CommitTransaction")
|
||||
private fun getTransaction(
|
||||
fm: FragmentManager,
|
||||
fragment: Fragment
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
||||
private val nonPrintable = Pattern.compile("[\\x00-\\x08\\x0e-\\x1f]")
|
||||
|
||||
fun hasNonPrintableCharacters(s: String) = nonPrintable.matcher(s).find()
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.pm.PackageManager
|
||||
import android.support.v4.app.ActivityCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.Manifest
|
||||
|
||||
fun hasCameraPermission(activity: Activity, requestCode: Int): Boolean {
|
||||
return hasPermission(activity, Manifest.permission.CAMERA, requestCode)
|
||||
}
|
||||
|
||||
fun hasWritePermission(activity: Activity, requestCode: Int = 1): Boolean {
|
||||
return hasPermission(
|
||||
activity,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
requestCode
|
||||
)
|
||||
}
|
||||
|
||||
fun hasPermission(
|
||||
activity: Activity,
|
||||
permission: String,
|
||||
requestCode: Int
|
||||
): Boolean {
|
||||
return if (ContextCompat.checkSelfPermission(activity, permission) !=
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
arrayOf(permission),
|
||||
requestCode
|
||||
)
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import de.markusfisch.android.binaryeye.BuildConfig
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.support.v4.content.FileProvider
|
||||
import android.net.Uri
|
||||
|
||||
import java.io.File
|
||||
|
||||
fun shareText(context: Context, text: String, type: String = "text/plain") {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.putExtra(Intent.EXTRA_TEXT, text)
|
||||
intent.type = type
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun shareUri(context: Context, uri: Uri, type: String) {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.type = type
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun shareFile(context: Context, file: File, type: String) {
|
||||
shareUri(context, getUriForFile(context, file), type)
|
||||
}
|
||||
|
||||
fun getUriForFile(context: Context, file: File): Uri {
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
Uri.fromFile(file)
|
||||
} else {
|
||||
FileProvider.getUriForFile(
|
||||
context,
|
||||
BuildConfig.APPLICATION_ID + ".provider",
|
||||
file
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,10 @@ package de.markusfisch.android.binaryeye.app
|
||||
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Point
|
||||
import android.os.Build
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
|
||||
@@ -37,63 +33,16 @@ fun setSystemBarColor(window: Window, color: Int): Boolean {
|
||||
window.navigationBarColor = color
|
||||
window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun getStatusAndToolBarHeight(context: Context): Int {
|
||||
return getStatusBarHeight(context.resources) + getToolBarHeight(context)
|
||||
}
|
||||
|
||||
fun getStatusBarHeight(res: Resources): Int {
|
||||
return getIdentifierDimen(res, "status_bar_height")
|
||||
}
|
||||
|
||||
fun getToolBarHeight(context: Context): Int {
|
||||
val tv = TypedValue()
|
||||
return if (context.theme.resolveAttribute(
|
||||
android.R.attr.actionBarSize,
|
||||
tv,
|
||||
true
|
||||
))
|
||||
TypedValue.complexToDimensionPixelSize(
|
||||
tv.data,
|
||||
context.resources.displayMetrics
|
||||
)
|
||||
else
|
||||
0
|
||||
}
|
||||
|
||||
fun getNavigationBarSize(res: Resources): Point {
|
||||
val size = Point(0, 0)
|
||||
if (!getIdentifierBoolean(res, "config_showNavigationBar")) {
|
||||
return size
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
|
||||
val conf = res.getConfiguration()
|
||||
if (conf.orientation == Configuration.ORIENTATION_LANDSCAPE &&
|
||||
// according to https://developer.android.com/training/multiscreen/screensizes.html#TaskUseSWQuali
|
||||
// only a screen < 600 dp is considered to be a phone
|
||||
// and can move its navigation bar to the side
|
||||
conf.smallestScreenWidthDp < 600) {
|
||||
size.x = getIdentifierDimen(
|
||||
res,
|
||||
"navigation_bar_height_landscape"
|
||||
)
|
||||
return size
|
||||
}
|
||||
}
|
||||
size.y = getIdentifierDimen(res, "navigation_bar_height")
|
||||
return size
|
||||
}
|
||||
|
||||
private fun getIdentifierBoolean(res: Resources, name: String): Boolean {
|
||||
val id = res.getIdentifier(name, "bool", "android")
|
||||
return id > 0 && res.getBoolean(id)
|
||||
}
|
||||
|
||||
private fun getIdentifierDimen(res: Resources, name: String): Int {
|
||||
val id = res.getIdentifier(name, "dimen", "android")
|
||||
return if (id > 0) res.getDimensionPixelSize(id) else 0
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package de.markusfisch.android.binaryeye.data
|
||||
|
||||
import de.markusfisch.android.binaryeye.app.hasNonPrintableCharacters
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import android.text.format.DateFormat
|
||||
@@ -13,7 +16,7 @@ class Database {
|
||||
db = OpenHelper(context).writableDatabase
|
||||
}
|
||||
|
||||
fun getScans() = db.rawQuery(
|
||||
fun getScans(): Cursor? = db.rawQuery(
|
||||
"""SELECT
|
||||
$SCANS_ID,
|
||||
$SCANS_DATETIME,
|
||||
@@ -24,17 +27,23 @@ class Database {
|
||||
""", null
|
||||
)
|
||||
|
||||
fun getScan(id: Long) = db.rawQuery(
|
||||
fun getScan(id: Long): Cursor? = db.rawQuery(
|
||||
"""SELECT
|
||||
$SCANS_DATETIME,
|
||||
$SCANS_CONTENT,
|
||||
$SCANS_RAW,
|
||||
$SCANS_FORMAT
|
||||
FROM $SCANS
|
||||
WHERE $SCANS_ID = ?
|
||||
""", arrayOf("$id")
|
||||
)
|
||||
|
||||
fun insertScan(timestamp: Long, name: String, code: String): Long {
|
||||
fun insertScan(
|
||||
timestamp: Long,
|
||||
content: String,
|
||||
raw: ByteArray?,
|
||||
format: String
|
||||
): Long {
|
||||
val cv = ContentValues()
|
||||
cv.put(
|
||||
SCANS_DATETIME, DateFormat.format(
|
||||
@@ -42,8 +51,13 @@ class Database {
|
||||
timestamp
|
||||
).toString()
|
||||
)
|
||||
cv.put(SCANS_CONTENT, name)
|
||||
cv.put(SCANS_FORMAT, code)
|
||||
if (hasNonPrintableCharacters(content) && raw != null) {
|
||||
cv.put(SCANS_CONTENT, "")
|
||||
cv.put(SCANS_RAW, raw)
|
||||
} else {
|
||||
cv.put(SCANS_CONTENT, content)
|
||||
}
|
||||
cv.put(SCANS_FORMAT, format)
|
||||
return db.insert(SCANS, null, cv)
|
||||
}
|
||||
|
||||
@@ -56,7 +70,7 @@ class Database {
|
||||
}
|
||||
|
||||
private class OpenHelper(context: Context) :
|
||||
SQLiteOpenHelper(context, "history.db", null, 1) {
|
||||
SQLiteOpenHelper(context, "history.db", null, 2) {
|
||||
override fun onCreate(db: SQLiteDatabase) {
|
||||
createScans(db)
|
||||
}
|
||||
@@ -66,6 +80,9 @@ class Database {
|
||||
oldVersion: Int,
|
||||
newVersion: Int
|
||||
) {
|
||||
if (oldVersion < 2) {
|
||||
addRawColumn(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +91,7 @@ class Database {
|
||||
const val SCANS_ID = "_id"
|
||||
const val SCANS_DATETIME = "_datetime"
|
||||
const val SCANS_CONTENT = "content"
|
||||
const val SCANS_RAW = "raw"
|
||||
const val SCANS_FORMAT = "format"
|
||||
|
||||
private fun createScans(db: SQLiteDatabase) {
|
||||
@@ -83,9 +101,14 @@ class Database {
|
||||
$SCANS_ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
$SCANS_DATETIME DATETIME NOT NULL,
|
||||
$SCANS_CONTENT TEXT NOT NULL,
|
||||
$SCANS_RAW BLOB,
|
||||
$SCANS_FORMAT TEXT NOT NULL
|
||||
)"""
|
||||
)
|
||||
}
|
||||
|
||||
private fun addRawColumn(db: SQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_RAW BLOB")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,13 @@ package de.markusfisch.android.binaryeye.fragment
|
||||
|
||||
import com.google.zxing.BarcodeFormat
|
||||
|
||||
import de.markusfisch.android.binaryeye.app.shareFile
|
||||
import de.markusfisch.android.binaryeye.zxing.Zxing
|
||||
import de.markusfisch.android.binaryeye.BuildConfig
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.graphics.Bitmap
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.content.FileProvider
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -41,30 +37,38 @@ class BarcodeFragment : Fragment() {
|
||||
false
|
||||
)
|
||||
|
||||
val args = getArguments()
|
||||
val args = arguments
|
||||
args?.let {
|
||||
val size = args.getInt(SIZE)
|
||||
val bitmap: Bitmap?
|
||||
try {
|
||||
bitmap = Zxing.encodeAsBitmap(
|
||||
args.getString(CONTENT),
|
||||
args.getSerializable(FORMAT) as BarcodeFormat,
|
||||
size,
|
||||
size
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
e.message,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
fragmentManager.popBackStack()
|
||||
return null
|
||||
}
|
||||
view.findViewById<ImageView>(R.id.barcode).setImageBitmap(bitmap)
|
||||
view.findViewById<View>(R.id.share).setOnClickListener { _ ->
|
||||
bitmap?.let {
|
||||
share(bitmap)
|
||||
val content = args.getString(CONTENT)
|
||||
val format = args.getSerializable(FORMAT) as BarcodeFormat?
|
||||
if (content != null && format != null) {
|
||||
val size = args.getInt(SIZE)
|
||||
val bitmap: Bitmap?
|
||||
try {
|
||||
bitmap = Zxing.encodeAsBitmap(
|
||||
content,
|
||||
format,
|
||||
size,
|
||||
size
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
var message = e.message
|
||||
if (message == null || message.isEmpty()) {
|
||||
message = getString(R.string.error_encoding_barcode)
|
||||
}
|
||||
Toast.makeText(
|
||||
activity,
|
||||
message,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
fragmentManager.popBackStack()
|
||||
return null
|
||||
}
|
||||
view.findViewById<ImageView>(R.id.barcode).setImageBitmap(bitmap)
|
||||
view.findViewById<View>(R.id.share).setOnClickListener {
|
||||
bitmap?.let {
|
||||
share(bitmap)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,40 +81,24 @@ class BarcodeFragment : Fragment() {
|
||||
val file = saveBitmap(bitmap)
|
||||
GlobalScope.launch(Main) {
|
||||
file?.let {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.putExtra(Intent.EXTRA_STREAM, getUriForFile(file))
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.setType("image/png")
|
||||
startActivity(intent)
|
||||
shareFile(context, file, "image/png")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveBitmap(bitmap: Bitmap): File? {
|
||||
try {
|
||||
return try {
|
||||
val file = File(
|
||||
context.getExternalCacheDir(),
|
||||
context.externalCacheDir,
|
||||
"shared_barcode.png"
|
||||
)
|
||||
val fos = FileOutputStream(file)
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos)
|
||||
fos.close()
|
||||
return file
|
||||
file
|
||||
} catch (e: IOException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUriForFile(file: File): Uri {
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
Uri.fromFile(file)
|
||||
} else {
|
||||
FileProvider.getUriForFile(
|
||||
context,
|
||||
BuildConfig.APPLICATION_ID + ".provider",
|
||||
file
|
||||
)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +117,7 @@ class BarcodeFragment : Fragment() {
|
||||
args.putSerializable(FORMAT, format)
|
||||
args.putInt(SIZE, size)
|
||||
val fragment = BarcodeFragment()
|
||||
fragment.setArguments(args)
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,22 @@ package de.markusfisch.android.binaryeye.fragment
|
||||
import com.google.zxing.BarcodeFormat
|
||||
|
||||
import de.markusfisch.android.binaryeye.app.addFragment
|
||||
import de.markusfisch.android.binaryeye.app.hasNonPrintableCharacters
|
||||
import de.markusfisch.android.binaryeye.app.hasWritePermission
|
||||
import de.markusfisch.android.binaryeye.app.shareText
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.support.v4.app.Fragment
|
||||
import android.text.ClipboardManager
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
@@ -18,12 +26,22 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URLEncoder
|
||||
|
||||
class DecodeFragment : Fragment() {
|
||||
private lateinit var contentView: EditText
|
||||
private lateinit var formatView: TextView
|
||||
private lateinit var hexView: TextView
|
||||
private lateinit var format: BarcodeFormat
|
||||
|
||||
private var isBinary = false
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
@@ -43,20 +61,73 @@ class DecodeFragment : Fragment() {
|
||||
)
|
||||
|
||||
val content = arguments?.getString(CONTENT) ?: ""
|
||||
isBinary = hasNonPrintableCharacters(content) or content.isEmpty()
|
||||
val raw = arguments?.getByteArray(RAW) ?: content.toByteArray()
|
||||
format = arguments?.getSerializable(FORMAT) as BarcodeFormat? ?: BarcodeFormat.QR_CODE
|
||||
|
||||
contentView = view.findViewById<EditText>(R.id.content)
|
||||
contentView.setText(content)
|
||||
contentView = view.findViewById(R.id.content) as EditText
|
||||
val shareFab = view.findViewById<View>(R.id.share)
|
||||
|
||||
view.findViewById<View>(R.id.share).setOnClickListener { _ ->
|
||||
share(getContent())
|
||||
if (!isBinary) {
|
||||
contentView.setText(content)
|
||||
contentView.addTextChangedListener(object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
updateFormatAndHex(getContent().toByteArray())
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(
|
||||
s: CharSequence?,
|
||||
start: Int,
|
||||
count: Int,
|
||||
after: Int
|
||||
) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(
|
||||
s: CharSequence?,
|
||||
start: Int,
|
||||
before: Int,
|
||||
count: Int
|
||||
) {
|
||||
}
|
||||
})
|
||||
shareFab.setOnClickListener { v ->
|
||||
shareText(v.context, getContent())
|
||||
}
|
||||
} else {
|
||||
contentView.setText(R.string.binary_data)
|
||||
contentView.isEnabled = false
|
||||
(shareFab as ImageView).setImageResource(R.drawable.ic_action_save)
|
||||
shareFab.setOnClickListener {
|
||||
askForFileNameAndSave(raw)
|
||||
}
|
||||
}
|
||||
|
||||
formatView = view.findViewById(R.id.format)
|
||||
hexView = view.findViewById(R.id.hex)
|
||||
|
||||
updateFormatAndHex(raw)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private fun updateFormatAndHex(bytes: ByteArray) {
|
||||
formatView.text = resources.getQuantityString(
|
||||
R.plurals.barcode_info,
|
||||
bytes.size,
|
||||
format.toString(),
|
||||
bytes.size
|
||||
)
|
||||
hexView.text = hexDump(bytes, 33)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.fragment_decode, menu)
|
||||
if (isBinary) {
|
||||
menu.findItem(R.id.copy_to_clipboard).isVisible = false
|
||||
menu.findItem(R.id.open_url).isVisible = false
|
||||
menu.findItem(R.id.create).isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
@@ -81,7 +152,7 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun getContent(): String {
|
||||
return contentView.getText().toString()
|
||||
return contentView.text.toString()
|
||||
}
|
||||
|
||||
private fun copyToClipboard(text: String) {
|
||||
@@ -90,7 +161,7 @@ class DecodeFragment : Fragment() {
|
||||
val cm = activity.getSystemService(
|
||||
Context.CLIPBOARD_SERVICE
|
||||
) as ClipboardManager
|
||||
cm.setText(text)
|
||||
cm.text = text
|
||||
Toast.makeText(
|
||||
activity,
|
||||
R.string.put_into_clipboard,
|
||||
@@ -98,16 +169,25 @@ class DecodeFragment : Fragment() {
|
||||
).show()
|
||||
}
|
||||
|
||||
private fun openUrl(url: String) {
|
||||
private fun openUrl(url: String, googleIfNoUrl: Boolean = true) {
|
||||
if (activity == null || url.isEmpty()) {
|
||||
return
|
||||
}
|
||||
val intent = Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse(url).normalizeScheme()
|
||||
)
|
||||
if (intent.resolveActivity(activity.getPackageManager()) != null) {
|
||||
var uri = Uri.parse(url)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
uri = uri.normalizeScheme()
|
||||
}
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
if (intent.resolveActivity(activity.packageManager) != null) {
|
||||
startActivity(intent)
|
||||
} else if (googleIfNoUrl) {
|
||||
openUrl(
|
||||
"https://www.google.com/search?q=" + URLEncoder.encode(
|
||||
url,
|
||||
"utf-8"
|
||||
),
|
||||
false
|
||||
)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
@@ -117,24 +197,105 @@ class DecodeFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun share(text: String) {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.putExtra(Intent.EXTRA_TEXT, text)
|
||||
intent.setType("text/plain")
|
||||
startActivity(intent)
|
||||
private fun askForFileNameAndSave(raw: ByteArray) {
|
||||
val ac = activity
|
||||
ac ?: return
|
||||
val view = ac.layoutInflater.inflate(R.layout.dialog_save_file, null)
|
||||
val editText = view.findViewById(R.id.file_name) as EditText
|
||||
AlertDialog.Builder(ac)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
if (hasWritePermission(ac)) {
|
||||
val messageId = saveByteArray(
|
||||
editText.text.toString(),
|
||||
raw
|
||||
)
|
||||
if (messageId > 0) {
|
||||
Toast.makeText(ac, messageId, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CONTENT = "content"
|
||||
private const val FORMAT = "format"
|
||||
private const val RAW = "raw"
|
||||
|
||||
fun newInstance(content: String, format: BarcodeFormat): Fragment {
|
||||
fun newInstance(
|
||||
content: String,
|
||||
format: BarcodeFormat,
|
||||
raw: ByteArray? = null
|
||||
): Fragment {
|
||||
val args = Bundle()
|
||||
args.putString(CONTENT, content)
|
||||
args.putSerializable(FORMAT, format)
|
||||
if (raw != null) {
|
||||
args.putByteArray(RAW, raw)
|
||||
}
|
||||
val fragment = DecodeFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun hexDump(bytes: ByteArray, charsPerLine: Int): String {
|
||||
if (charsPerLine < 4 || bytes.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
val dump = StringBuilder()
|
||||
val hex = StringBuilder()
|
||||
val ascii = StringBuilder()
|
||||
val itemsPerLine = (charsPerLine - 1) / 4
|
||||
val len = bytes.size
|
||||
var i = 0
|
||||
while (true) {
|
||||
val ord = bytes[i]
|
||||
hex.append(String.format("%02X ", ord))
|
||||
ascii.append(if (ord > 31) ord.toChar() else " ")
|
||||
|
||||
++i
|
||||
|
||||
val posInLine = i % itemsPerLine
|
||||
val atEnd = i >= len
|
||||
var atLineEnd = posInLine == 0
|
||||
if (atEnd && !atLineEnd) {
|
||||
for (j in posInLine until itemsPerLine) {
|
||||
hex.append(" ")
|
||||
}
|
||||
atLineEnd = true
|
||||
}
|
||||
if (atLineEnd) {
|
||||
dump.append(hex.toString())
|
||||
dump.append(" ")
|
||||
dump.append(ascii.toString())
|
||||
dump.append("\n")
|
||||
hex.setLength(0)
|
||||
ascii.setLength(0)
|
||||
}
|
||||
if (atEnd) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return dump.toString()
|
||||
}
|
||||
|
||||
fun saveByteArray(name: String, raw: ByteArray): Int {
|
||||
return try {
|
||||
val file = File(
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOWNLOADS
|
||||
),
|
||||
name
|
||||
)
|
||||
if (file.exists()) {
|
||||
return R.string.error_file_exists
|
||||
}
|
||||
file.writeBytes(raw)
|
||||
0
|
||||
} catch (e: IOException) {
|
||||
R.string.error_saving_binary_data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,22 +50,20 @@ class EncodeFragment : Fragment() {
|
||||
false
|
||||
)
|
||||
|
||||
formatView = view.findViewById<Spinner>(R.id.format)
|
||||
formatView.setAdapter(
|
||||
ArrayAdapter<String>(
|
||||
activity,
|
||||
android.R.layout.simple_list_item_1,
|
||||
writers.map { it -> it.name }
|
||||
)
|
||||
formatView = view.findViewById(R.id.format)
|
||||
formatView.adapter = ArrayAdapter<String>(
|
||||
activity,
|
||||
android.R.layout.simple_list_item_1,
|
||||
writers.map { it.name }
|
||||
)
|
||||
|
||||
sizeView = view.findViewById<TextView>(R.id.size_display)
|
||||
sizeBarView = view.findViewById<SeekBar>(R.id.size_bar)
|
||||
sizeView = view.findViewById(R.id.size_display)
|
||||
sizeBarView = view.findViewById(R.id.size_bar)
|
||||
initSizeBar()
|
||||
|
||||
val contentView = view.findViewById<EditText>(R.id.content)
|
||||
|
||||
val args = getArguments()
|
||||
val args = arguments
|
||||
args?.let {
|
||||
contentView.setText(args.getString(CONTENT))
|
||||
formatView.setSelection(
|
||||
@@ -76,9 +74,9 @@ class EncodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
view.findViewById<View>(R.id.encode).setOnClickListener { v ->
|
||||
val format = writers.get(formatView.getSelectedItemPosition())
|
||||
var size = getSize(sizeBarView.getProgress())
|
||||
val content = contentView.getText().toString()
|
||||
val format = writers[formatView.selectedItemPosition]
|
||||
val size = getSize(sizeBarView.progress)
|
||||
val content = contentView.text.toString()
|
||||
if (content.isEmpty()) {
|
||||
Toast.makeText(
|
||||
v.context,
|
||||
@@ -101,7 +99,7 @@ class EncodeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun initSizeBar() {
|
||||
updateSize(sizeBarView.getProgress())
|
||||
updateSize(sizeBarView.progress)
|
||||
sizeBarView.setOnSeekBarChangeListener(
|
||||
object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(
|
||||
@@ -120,7 +118,7 @@ class EncodeFragment : Fragment() {
|
||||
|
||||
private fun updateSize(power: Int) {
|
||||
val size = getSize(power)
|
||||
sizeView.setText("${size}x$size")
|
||||
sizeView.text = getString(R.string.width_by_height, size, size)
|
||||
}
|
||||
|
||||
private fun getSize(power: Int) = 128 * (power + 1)
|
||||
@@ -130,7 +128,7 @@ class EncodeFragment : Fragment() {
|
||||
Context.INPUT_METHOD_SERVICE
|
||||
) as InputMethodManager?
|
||||
im?.let {
|
||||
im.hideSoftInputFromWindow(view.getWindowToken(), 0)
|
||||
im.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +144,7 @@ class EncodeFragment : Fragment() {
|
||||
args.putString(CONTENT, content)
|
||||
args.putSerializable(FORMAT, format)
|
||||
val fragment = EncodeFragment()
|
||||
fragment.setArguments(args)
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@ package de.markusfisch.android.binaryeye.fragment
|
||||
import com.google.zxing.BarcodeFormat
|
||||
|
||||
import de.markusfisch.android.binaryeye.adapter.ScansAdapter
|
||||
import de.markusfisch.android.binaryeye.app.db
|
||||
import de.markusfisch.android.binaryeye.app.addFragment
|
||||
import de.markusfisch.android.binaryeye.app.db
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.app.shareText
|
||||
import de.markusfisch.android.binaryeye.data.Database
|
||||
import de.markusfisch.android.binaryeye.fragment.DecodeFragment
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
import android.app.AlertDialog
|
||||
@@ -16,6 +16,9 @@ import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.widget.SwitchCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ListView
|
||||
@@ -27,6 +30,12 @@ import kotlinx.coroutines.launch
|
||||
class HistoryFragment : Fragment() {
|
||||
private lateinit var listView: ListView
|
||||
private lateinit var fab: View
|
||||
private lateinit var progressView: View
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
@@ -56,11 +65,13 @@ class HistoryFragment : Fragment() {
|
||||
true
|
||||
}
|
||||
|
||||
fab = view.findViewById(R.id.clear)
|
||||
fab = view.findViewById(R.id.share)
|
||||
fab.setOnClickListener { v ->
|
||||
askToRemoveAllScans(v.context)
|
||||
pickListSeparatorAndShare(v.context)
|
||||
}
|
||||
|
||||
progressView = view.findViewById(R.id.progress_view)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
@@ -74,6 +85,20 @@ class HistoryFragment : Fragment() {
|
||||
update(context)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.fragment_history, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.clear -> {
|
||||
askToRemoveAllScans(context)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initHistorySwitch(switchView: SwitchCompat) {
|
||||
switchView.setOnCheckedChangeListener { _, isChecked ->
|
||||
prefs.useHistory = isChecked
|
||||
@@ -87,17 +112,19 @@ class HistoryFragment : Fragment() {
|
||||
GlobalScope.launch {
|
||||
val cursor = db.getScans()
|
||||
GlobalScope.launch(Main) {
|
||||
fab.visibility = if (cursor != null && cursor.getCount() > 0) {
|
||||
fab.visibility = if (cursor != null && cursor.count > 0) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
if (listView.adapter == null) {
|
||||
listView.adapter = ScansAdapter(context, cursor)
|
||||
} else {
|
||||
val adapter = listView.adapter as ScansAdapter
|
||||
adapter.changeCursor(cursor)
|
||||
adapter.notifyDataSetChanged()
|
||||
cursor?.let {
|
||||
if (listView.adapter == null) {
|
||||
listView.adapter = ScansAdapter(context, cursor)
|
||||
} else {
|
||||
val adapter = listView.adapter as ScansAdapter
|
||||
adapter.changeCursor(cursor)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,13 +134,15 @@ class HistoryFragment : Fragment() {
|
||||
val cursor = db.getScan(id)
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
val contentIndex = cursor.getColumnIndex(Database.SCANS_CONTENT)
|
||||
val rawIndex = cursor.getColumnIndex(Database.SCANS_RAW)
|
||||
val formatIndex = cursor.getColumnIndex(Database.SCANS_FORMAT)
|
||||
try {
|
||||
addFragment(
|
||||
fragmentManager,
|
||||
DecodeFragment.newInstance(
|
||||
cursor.getString(contentIndex),
|
||||
BarcodeFormat.valueOf(cursor.getString(formatIndex))
|
||||
BarcodeFormat.valueOf(cursor.getString(formatIndex)),
|
||||
cursor.getBlob(rawIndex)
|
||||
)
|
||||
)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
@@ -146,4 +175,46 @@ class HistoryFragment : Fragment() {
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun pickListSeparatorAndShare(context: Context) {
|
||||
val separators = context.resources.getStringArray(
|
||||
R.array.list_separators_values
|
||||
)
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle(R.string.pick_list_separator)
|
||||
.setItems(R.array.list_separators_names) { _, which ->
|
||||
shareScans(separators[which])
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun shareScans(separator: String) {
|
||||
if (progressView.visibility == View.VISIBLE) {
|
||||
return
|
||||
}
|
||||
progressView.visibility = View.VISIBLE
|
||||
GlobalScope.launch {
|
||||
val cursor = db.getScans()
|
||||
cursor?.let {
|
||||
val sb = StringBuilder()
|
||||
if (cursor.moveToFirst()) {
|
||||
val contentIndex = cursor.getColumnIndex(
|
||||
Database.SCANS_CONTENT
|
||||
)
|
||||
do {
|
||||
sb.append(cursor.getString(contentIndex))
|
||||
sb.append(separator)
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
cursor.close()
|
||||
val text = sb.toString()
|
||||
if (text.isNotEmpty()) {
|
||||
GlobalScope.launch(Main) {
|
||||
progressView.visibility = View.GONE
|
||||
shareText(context, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class Preprocessor(
|
||||
context: Context,
|
||||
width: Int,
|
||||
height: Int,
|
||||
val orientation: Int
|
||||
private val orientation: Int
|
||||
) {
|
||||
var outWidth = 0
|
||||
var outHeight = 0
|
||||
@@ -42,7 +42,7 @@ class Preprocessor(
|
||||
Allocation.USAGE_SCRIPT
|
||||
)
|
||||
|
||||
var f = .75f
|
||||
val f = .75f
|
||||
var w = Math.round(width * f)
|
||||
var h = Math.round(height * f)
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class Zxing {
|
||||
)
|
||||
|
||||
val hints = EnumMap<DecodeHintType, Any>(DecodeHintType::class.java)
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats)
|
||||
hints[DecodeHintType.POSSIBLE_FORMATS] = decodeFormats
|
||||
|
||||
multiFormatReader.setHints(hints)
|
||||
}
|
||||
@@ -71,6 +71,42 @@ class Zxing {
|
||||
height,
|
||||
false
|
||||
)
|
||||
return decodeLuminanceSource(source, invert)
|
||||
}
|
||||
|
||||
fun decodePositiveNegative(bitmap: Bitmap): Result? {
|
||||
val result = decode(bitmap, false)
|
||||
if (result != null) {
|
||||
return result
|
||||
}
|
||||
return decode(bitmap, true)
|
||||
}
|
||||
|
||||
fun decode(bitmap: Bitmap, invert: Boolean = false): Result? {
|
||||
val pixels = IntArray(bitmap.width * bitmap.height)
|
||||
return decode(pixels, bitmap, invert)
|
||||
}
|
||||
|
||||
fun decode(
|
||||
pixels: IntArray,
|
||||
bitmap: Bitmap,
|
||||
invert: Boolean = false
|
||||
): Result? {
|
||||
val width = bitmap.width
|
||||
val height = bitmap.height
|
||||
if (bitmap.config != Bitmap.Config.ARGB_8888) {
|
||||
bitmap.copy(Bitmap.Config.ARGB_8888, true)
|
||||
} else {
|
||||
bitmap
|
||||
}.getPixels(pixels, 0, width, 0, 0, width, height)
|
||||
val source = RGBLuminanceSource(width, height, pixels)
|
||||
return decodeLuminanceSource(source, invert)
|
||||
}
|
||||
|
||||
private fun decodeLuminanceSource(
|
||||
source: LuminanceSource,
|
||||
invert: Boolean
|
||||
): Result? {
|
||||
return decodeLuminanceSource(
|
||||
if (invert) {
|
||||
source.invert()
|
||||
@@ -80,23 +116,6 @@ class Zxing {
|
||||
)
|
||||
}
|
||||
|
||||
fun decode(bitmap: Bitmap): Result? {
|
||||
val width = bitmap.getWidth()
|
||||
val height = bitmap.getHeight()
|
||||
val pixels = IntArray(width * height)
|
||||
if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
|
||||
bitmap.copy(Bitmap.Config.ARGB_8888, true)
|
||||
} else {
|
||||
bitmap
|
||||
}.getPixels(pixels, 0, width, 0, 0, width, height)
|
||||
val source = RGBLuminanceSource(width, height, pixels)
|
||||
val result = decodeLuminanceSource(source)
|
||||
if (result != null) {
|
||||
return result
|
||||
}
|
||||
return decodeLuminanceSource(source.invert())
|
||||
}
|
||||
|
||||
private fun decodeLuminanceSource(source: LuminanceSource): Result? {
|
||||
val bitmap = BinaryBitmap(HybridBinarizer(source))
|
||||
return try {
|
||||
@@ -119,19 +138,23 @@ class Zxing {
|
||||
height: Int
|
||||
): Bitmap? {
|
||||
val result = MultiFormatWriter().encode(
|
||||
text, format,
|
||||
width, height, null
|
||||
text,
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
null
|
||||
)
|
||||
val w = result.getWidth()
|
||||
val h = result.getHeight()
|
||||
val w = result.width
|
||||
val h = result.height
|
||||
val pixels = IntArray(w * h)
|
||||
var offset = 0
|
||||
for (y in 0..h - 1) {
|
||||
for (x in 0..w - 1) {
|
||||
pixels[offset + x] = if (result.get(x, y))
|
||||
for (y in 0 until h) {
|
||||
for (x in 0 until w) {
|
||||
pixels[offset + x] = if (result.get(x, y)) {
|
||||
BLACK
|
||||
else
|
||||
} else {
|
||||
WHITE
|
||||
}
|
||||
}
|
||||
offset += w
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="line"
|
||||
android:gravity="center">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/accent"/>
|
||||
</shape>
|
||||
@@ -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="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
|
||||
</vector>
|
||||
@@ -10,8 +10,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:fitsSystemWindows="true"
|
||||
android:background="@drawable/background_scanner">
|
||||
android:fitsSystemWindows="true">
|
||||
<include layout="@layout/toolbar"/>
|
||||
<SeekBar
|
||||
android:id="@+id/zoom"
|
||||
@@ -33,6 +32,7 @@
|
||||
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>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/save_as_file_name"/>
|
||||
<EditText
|
||||
android:id="@+id/file_name"
|
||||
android:inputType="text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/file_name" />
|
||||
</LinearLayout>
|
||||
@@ -5,7 +5,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<ImageView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/barcode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -19,6 +18,7 @@
|
||||
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>
|
||||
|
||||
@@ -4,16 +4,50 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<EditText
|
||||
android:id="@+id/content"
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:gravity="start|top"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textMultiLine"
|
||||
android:typeface="monospace"
|
||||
android:hint="@string/content"/>
|
||||
android:layout_height="match_parent">
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<EditText
|
||||
tools:targetApi="o"
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:gravity="start|top"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textMultiLine"
|
||||
android:typeface="monospace"
|
||||
android:hint="@string/content"
|
||||
android:importantForAutofill="no"/>
|
||||
<TextView
|
||||
android:id="@+id/format"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="end|top"
|
||||
android:textSize="14sp"/>
|
||||
<TextView
|
||||
android:id="@+id/hex"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/format"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:typeface="monospace"
|
||||
android:textSize="12sp"/>
|
||||
</RelativeLayout>
|
||||
</ScrollView>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:id="@+id/share"
|
||||
@@ -23,6 +57,7 @@
|
||||
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>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
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"
|
||||
@@ -51,7 +52,8 @@
|
||||
android:typeface="monospace"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textMultiLine"
|
||||
android:hint="@string/input_content_here"/>
|
||||
android:hint="@string/input_content_here"
|
||||
android:importantForAutofill="no"/>
|
||||
<Button
|
||||
style="@style/Button"
|
||||
android:id="@+id/encode"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
android:choiceMode="singleChoice"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@android:color/transparent"
|
||||
android:divider="@color/separator"
|
||||
android:dividerHeight="1px"/>
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:visibility="gone"
|
||||
@@ -22,13 +22,15 @@
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/clear"
|
||||
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:src="@drawable/ic_action_clear"
|
||||
android:contentDescription="@string/share"
|
||||
android:src="@drawable/ic_action_share"
|
||||
app:elevation="4dp"/>
|
||||
<include layout="@layout/progress_view"/>
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/progress_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background_progress"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone">
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"/>
|
||||
</FrameLayout>
|
||||
@@ -15,6 +15,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:layout_toRightOf="@+id/time"
|
||||
android:layout_toEndOf="@+id/time"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"/>
|
||||
|
||||
+3
-3
@@ -2,8 +2,8 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:material="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/remove_scan"
|
||||
android:title="@string/remove_scan"
|
||||
android:icon="@drawable/ic_action_remove"
|
||||
android:id="@+id/clear"
|
||||
android:title="@string/clear_history"
|
||||
android:icon="@drawable/ic_action_clear"
|
||||
material:showAsAction="ifRoom"/>
|
||||
</menu>
|
||||
@@ -5,22 +5,38 @@
|
||||
<string name="compose_barcode">Barcode erstellen</string>
|
||||
<string name="decode_barcode">Barcode dekodieren</string>
|
||||
<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>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Licht an/ausschalten</string>
|
||||
<string name="share">Teilen</string>
|
||||
<string name="copy_to_clipboard">In die Zwischenablage kopieren</string>
|
||||
<string name="put_into_clipboard">In die Zwischenablage legen</string>
|
||||
<string name="open_url">URL öffnen</string>
|
||||
<string name="cannot_resolve_action">Keine App kann das öffnen</string>
|
||||
<string name="format">Format</string>
|
||||
<string name="size">Größe in Pixeln</string>
|
||||
<string name="width_by_height">%1$d×%2$d</string>
|
||||
<string name="input_content_here">Gib den Inhalt hier ein</string>
|
||||
<string name="encode">KODIEREN</string>
|
||||
<string name="error_no_content">Fehlender Inhalt</string>
|
||||
<string name="error_encoding_barcode">Barcode kann nicht generiert werden</string>
|
||||
<string name="view_barcode">Barcode ansehen</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="switch_camera">Kamera wechseln</string>
|
||||
<string name="history">Gespeicherte Codes</string>
|
||||
<string name="use_history">Codes speichern</string>
|
||||
<string name="remove_scan">Code entfernen</string>
|
||||
<string name="really_remove_scan">Code wirklich entfernen?</string>
|
||||
<string name="really_remove_all_scans">Alle Codes entfernen?</string>
|
||||
<string name="clear_history">Gespeicherte Codes löschen</string>
|
||||
<string name="no_barcode_found">Kein Barcode gefunden</string>
|
||||
<string name="pick_list_separator">Wie sollen die Einträge getrennt werden?</string>
|
||||
<string name="separator_line_break">Zeilenumbruch</string>
|
||||
<string name="separator_ruler">Trennstrich</string>
|
||||
<string name="save_as_file_name">Speichern als?</string>
|
||||
<string name="file_name">Dateiname</string>
|
||||
<string name="error_saving_binary_data">Datei konnte nicht gespeichert werden</string>
|
||||
<string name="error_file_exists">Datei existiert bereits</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<resources>
|
||||
<string name="no_camera_no_fun">Cette application n\'a aucun sens sans accès possible à la caméra. Au revoir.</string>
|
||||
<string name="camera_error">Impossible d\'accéder à la caméra, veuillez réessayer</string>
|
||||
<string name="scan_code">Scanner le code</string>
|
||||
<string name="compose_barcode">Créer un code-barres</string>
|
||||
<string name="decode_barcode">Décoder le code-barres</string>
|
||||
<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>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Toggle flash</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="copy_to_clipboard">Copier dans le presse-papier</string>
|
||||
<string name="put_into_clipboard">Mis dans le presse-papiers</string>
|
||||
<string name="open_url">Ouvrir l\'url</string>
|
||||
<string name="cannot_resolve_action">Aucune application ne peut ouvrir ça</string>
|
||||
<string name="format">Format</string>
|
||||
<string name="size">Taille en pixels</string>
|
||||
<string name="width_by_height">%1$d×%2$d</string>
|
||||
<string name="input_content_here">Entrez votre contenu ici</string>
|
||||
<string name="encode">ENCODER</string>
|
||||
<string name="error_no_content">Contenu manquant</string>
|
||||
<string name="error_encoding_barcode">Barcode cannot be generated</string>
|
||||
<string name="view_barcode">Voir le code barre</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="switch_camera">Changer de camera</string>
|
||||
<string name="history">Historique</string>
|
||||
<string name="use_history">Sauvegarder l\'histoire des scans</string>
|
||||
<string name="really_remove_scan">Supprimer le scan ?</string>
|
||||
<string name="really_remove_all_scans">Supprimer tous les scans ?</string>
|
||||
<string name="clear_history">Clear history</string>
|
||||
<string name="no_barcode_found">Aucun code-barres trouvé</string>
|
||||
<string name="pick_list_separator">How to separate list items?</string>
|
||||
<string name="separator_line_break">Line break</string>
|
||||
<string name="separator_ruler">Ruler</string>
|
||||
<string name="save_as_file_name">Save as file?</string>
|
||||
<string name="file_name">File name</string>
|
||||
<string name="error_saving_binary_data">Cannot save file</string>
|
||||
<string name="error_file_exists">File already exists</string>
|
||||
</resources>
|
||||
@@ -3,24 +3,40 @@
|
||||
<string name="camera_error">Nem lehet hozzáférni a kamerához, próbálja meg újra</string>
|
||||
<string name="scan_code">Kód beolvasása</string>
|
||||
<string name="compose_barcode">Vonalkód létrehozása</string>
|
||||
<string name="decode_barcode">Decode barcode</string>
|
||||
<string name="decode_barcode">Vonalkód visszafejtése</string>
|
||||
<string name="content">Tartalom</string>
|
||||
<string name="binary_data">(binary data)</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>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Vaku be- vagy kikapcsolása</string>
|
||||
<string name="share">Megosztás</string>
|
||||
<string name="copy_to_clipboard">Másolás a vágólapra</string>
|
||||
<string name="put_into_clipboard">Vágólapra helyezés</string>
|
||||
<string name="open_url">URL megnyitása</string>
|
||||
<string name="cannot_resolve_action">Nincs alkalmazás, amely meg tudná nyitni azt</string>
|
||||
<string name="format">Formátum</string>
|
||||
<string name="size">Méret képpontban</string>
|
||||
<string name="width_by_height">%1$d×%2$d</string>
|
||||
<string name="input_content_here">Itt adja meg a tartalmat</string>
|
||||
<string name="encode">KÓDOLÁS</string>
|
||||
<string name="error_no_content">Hiányzó tartalom</string>
|
||||
<string name="error_encoding_barcode">Barcode cannot be generated</string>
|
||||
<string name="view_barcode">Vonalkód megtekintése</string>
|
||||
<string name="info">Információ</string>
|
||||
<string name="switch_camera">Kamera átkapcsolása</string>
|
||||
<string name="history">History</string>
|
||||
<string name="use_history">Save scan history</string>
|
||||
<string name="remove_scan">Remove scan</string>
|
||||
<string name="really_remove_scan">Really remove scan?</string>
|
||||
<string name="really_remove_all_scans">Really remove all scans?</string>
|
||||
<string name="no_barcode_found">No barcode found</string>
|
||||
<string name="history">Előzmények</string>
|
||||
<string name="use_history">Beolvasási előzmények mentése</string>
|
||||
<string name="really_remove_scan">Valóban eltávolítja a beolvasást?</string>
|
||||
<string name="really_remove_all_scans">Valóban eltávolítja az összes beolvasását?</string>
|
||||
<string name="clear_history">Előzmények törlése</string>
|
||||
<string name="no_barcode_found">Nem található vonalkód</string>
|
||||
<string name="pick_list_separator">How to separate list items?</string>
|
||||
<string name="separator_line_break">Line break</string>
|
||||
<string name="separator_ruler">Ruler</string>
|
||||
<string name="save_as_file_name">Save as file?</string>
|
||||
<string name="file_name">File name</string>
|
||||
<string name="error_saving_binary_data">Cannot save file</string>
|
||||
<string name="error_file_exists">File already exists</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<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="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">(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>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Flash</string>
|
||||
<string name="share">Condividi</string>
|
||||
<string name="copy_to_clipboard">Copia negli appunti</string>
|
||||
<string name="put_into_clipboard">Metti negli appunti</string>
|
||||
<string name="open_url">Apri URL</string>
|
||||
<string name="cannot_resolve_action">Nessuna app può aprirlo</string>
|
||||
<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="encode">CODIFICA</string>
|
||||
<string name="error_no_content">Contenuto mancante</string>
|
||||
<string name="error_encoding_barcode">Barcode cannot be generated</string>
|
||||
<string name="view_barcode">Vedi codice a barre</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="switch_camera">Cambia camera</string>
|
||||
<string name="history">Cronologia</string>
|
||||
<string name="use_history">Salva cronologia delle scansioni</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="separator_line_break">Interruzione di linea</string>
|
||||
<string name="separator_ruler">Righello</string>
|
||||
<string name="save_as_file_name">Save as file?</string>
|
||||
<string name="file_name">File name</string>
|
||||
<string name="error_saving_binary_data">Cannot save file</string>
|
||||
<string name="error_file_exists">File already exists</string>
|
||||
</resources>
|
||||
@@ -5,22 +5,38 @@
|
||||
<string name="compose_barcode">Scan een barcode</string>
|
||||
<string name="decode_barcode">Decode barcode</string>
|
||||
<string name="content">Inhoud</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>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Toggle flash</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="copy_to_clipboard">Kopiëren naar klembord</string>
|
||||
<string name="put_into_clipboard">Kopieer de inhoud naar het klembord</string>
|
||||
<string name="open_url">URL openen</string>
|
||||
<string name="cannot_resolve_action">Er is geen app aangetroffen die dit kan openen</string>
|
||||
<string name="format">Formaat</string>
|
||||
<string name="size">Grootte, in pixels</string>
|
||||
<string name="width_by_height">%1$d×%2$d</string>
|
||||
<string name="input_content_here">Voer hier de inhoud in</string>
|
||||
<string name="encode">CODEREN</string>
|
||||
<string name="error_no_content">Inhoud ontbreekt</string>
|
||||
<string name="error_encoding_barcode">Barcode cannot be generated</string>
|
||||
<string name="view_barcode">Barcode bekijken</string>
|
||||
<string name="info">Informatie</string>
|
||||
<string name="switch_camera">Camera wisselen</string>
|
||||
<string name="history">History</string>
|
||||
<string name="use_history">Save scan history</string>
|
||||
<string name="remove_scan">Remove scan</string>
|
||||
<string name="really_remove_scan">Really remove scan?</string>
|
||||
<string name="really_remove_all_scans">Really remove all scans?</string>
|
||||
<string name="clear_history">Clear history</string>
|
||||
<string name="no_barcode_found">No barcode found</string>
|
||||
<string name="pick_list_separator">How to separate list items?</string>
|
||||
<string name="separator_line_break">Line break</string>
|
||||
<string name="separator_ruler">Ruler</string>
|
||||
<string name="save_as_file_name">Save as file?</string>
|
||||
<string name="file_name">File name</string>
|
||||
<string name="error_saving_binary_data">Cannot save file</string>
|
||||
<string name="error_file_exists">File already exists</string>
|
||||
</resources>
|
||||
|
||||
@@ -6,5 +6,7 @@
|
||||
<color name="accent">#b6d46f</color>
|
||||
<color name="accent_dark">#a6c45f</color>
|
||||
<color name="background_color">#111</color>
|
||||
<color name="background_progress">#8000</color>
|
||||
<color name="button_text">#fff</color>
|
||||
<color name="separator">#333</color>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<resources>
|
||||
<string-array name="list_separators_names">
|
||||
<item>@string/separator_line_break</item>
|
||||
<item>@string/separator_ruler</item>
|
||||
</string-array>
|
||||
<string-array name="list_separators_values">
|
||||
<item>\n</item>
|
||||
<item>\n---\n</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -5,22 +5,38 @@
|
||||
<string name="compose_barcode">Compose barcode</string>
|
||||
<string name="decode_barcode">Decode barcode</string>
|
||||
<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>
|
||||
</plurals>
|
||||
<string name="toggle_flash">Toggle flash</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="copy_to_clipboard">Copy to clipboard</string>
|
||||
<string name="put_into_clipboard">Put into clipboard</string>
|
||||
<string name="open_url">Open url</string>
|
||||
<string name="cannot_resolve_action">No application can open that</string>
|
||||
<string name="format">Format</string>
|
||||
<string name="size">Size in pixels</string>
|
||||
<string name="width_by_height">%1$d×%2$d</string>
|
||||
<string name="input_content_here">Input content here</string>
|
||||
<string name="encode">ENCODE</string>
|
||||
<string name="error_no_content">Missing content</string>
|
||||
<string name="error_encoding_barcode">Barcode cannot be generated</string>
|
||||
<string name="view_barcode">View barcode</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="switch_camera">Switch camera</string>
|
||||
<string name="history">History</string>
|
||||
<string name="use_history">Save scan history</string>
|
||||
<string name="remove_scan">Remove scan</string>
|
||||
<string name="really_remove_scan">Really remove scan?</string>
|
||||
<string name="really_remove_all_scans">Really remove all scans?</string>
|
||||
<string name="clear_history">Clear history</string>
|
||||
<string name="no_barcode_found">No barcode found</string>
|
||||
<string name="pick_list_separator">How to separate list items?</string>
|
||||
<string name="separator_line_break">Line break</string>
|
||||
<string name="separator_ruler">Ruler</string>
|
||||
<string name="save_as_file_name">Save as file?</string>
|
||||
<string name="file_name">File name</string>
|
||||
<string name="error_saving_binary_data">Cannot save file</string>
|
||||
<string name="error_file_exists">File already exists</string>
|
||||
</resources>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
name="Button"
|
||||
parent="@android:style/Widget.Button">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">36dp</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
<item name="android:layout_gravity">center_horizontal</item>
|
||||
<item name="android:background">@drawable/button_raised</item>
|
||||
<item name="android:textColor">@color/button_text</item>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma version(1)
|
||||
#pragma rs java_package_name(de.markusfisch.android.binaryeye.renderscript)
|
||||
#pragma rs_fp_relaxed
|
||||
|
||||
rs_allocation inImage;
|
||||
int inWidth;
|
||||
|
||||
+4
-9
@@ -1,22 +1,17 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.21'
|
||||
ext.tools_version = '3.3.2'
|
||||
ext.kotlin_version = '1.3.31'
|
||||
ext.tools_version = '3.4.1'
|
||||
ext.build_tools_version = '28.0.3'
|
||||
ext.sdk_version = 28
|
||||
ext.support_version = '25.3.1'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:$tools_version"
|
||||
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.10'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
@@ -27,8 +22,8 @@ plugins {
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
jcenter()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Wed Apr 10 15:27:10 PDT 2013
|
||||
#Tue May 07 14:37:45 CEST 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@@ -6,47 +6,6 @@
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
@@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
@@ -90,7 +89,7 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
@@ -114,6 +113,7 @@ fi
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
@@ -154,11 +154,19 @@ if $cygwin ; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
Vendored
+4
-10
@@ -8,14 +8,14 @@
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
@@ -46,10 +46,9 @@ echo location of your Java installation.
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
@@ -60,11 +59,6 @@ set _SKIP=2
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="google_play_icon.svg"
|
||||
inkscape:export-filename="/Users/markus/app_icon.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.80761719"
|
||||
inkscape:cx="-59.743651"
|
||||
inkscape:cy="256"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
showguides="false" />
|
||||
<defs
|
||||
id="defs4" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-540.36218)">
|
||||
<rect
|
||||
style="opacity:1;fill:#b6d46f;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4145"
|
||||
width="512"
|
||||
height="512"
|
||||
x="0"
|
||||
y="540.36218"
|
||||
rx="0"
|
||||
ry="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:8.60725021;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 259.47183,657.46384 c -36.63695,0 -73.27309,13.80545 -101.20422,41.42278 -55.86225,55.2346 -55.68941,144.72925 0,200.13856 l 193.69605,192.72152 202.57936,4.825 L 554.16705,891.40531 360.67609,698.88662 C 332.83155,671.18195 296.10884,657.46389 259.47188,657.46384 Z"
|
||||
id="path5462"
|
||||
sodipodi:nodetypes="ssscccss" />
|
||||
<circle
|
||||
r="141.46466"
|
||||
cy="799.18176"
|
||||
cx="258.80164"
|
||||
id="circle5467"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="circle5451"
|
||||
cx="254.77118"
|
||||
cy="803.87579"
|
||||
r="77.382751" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="circle5455"
|
||||
cx="307.03757"
|
||||
cy="747.37183"
|
||||
r="50.853714" />
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3776"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(5.4385115,0,0,5.4385115,-615.98708,-4631.8746)"><flowRegion
|
||||
id="flowRegion3778"><rect
|
||||
id="rect3780"
|
||||
width="29"
|
||||
height="71"
|
||||
x="52"
|
||||
y="60" /></flowRegion><flowPara
|
||||
id="flowPara3782" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:217.54046631px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="24816.699"
|
||||
y="13685.234"
|
||||
id="text5084"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5086"
|
||||
x="24816.699"
|
||||
y="13685.234" /></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3776-6"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(5.4385115,0,0,5.4385115,2280.8097,-4663.4521)"><flowRegion
|
||||
id="flowRegion3778-7"><rect
|
||||
id="rect3780-2"
|
||||
width="29"
|
||||
height="71"
|
||||
x="52"
|
||||
y="60" /></flowRegion><flowPara
|
||||
id="flowPara3782-0" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:217.54046631px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="27713.496"
|
||||
y="13653.656"
|
||||
id="text5084-0"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5086-1"
|
||||
x="27713.496"
|
||||
y="13653.656" /></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3776-8"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(5.4385115,0,0,5.4385115,2962.7932,-4497.8264)"><flowRegion
|
||||
id="flowRegion3778-4"><rect
|
||||
id="rect3780-5"
|
||||
width="29"
|
||||
height="71"
|
||||
x="52"
|
||||
y="60" /></flowRegion><flowPara
|
||||
id="flowPara3782-2" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:217.54046631px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="28395.479"
|
||||
y="13819.282"
|
||||
id="text5084-3"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5086-18"
|
||||
x="28395.479"
|
||||
y="13819.282" /></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3776-2"
|
||||
style="font-style:normal;font-weight:normal;font-size:4.31339216px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(5.4385115,0,0,5.4385115,-615.98708,-4631.8746)"><flowRegion
|
||||
id="flowRegion3778-41"><rect
|
||||
id="rect3780-54"
|
||||
width="3.1272094"
|
||||
height="7.6562715"
|
||||
x="32.001694"
|
||||
y="919.38837" /></flowRegion><flowPara
|
||||
id="flowPara3782-28" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:23.45843315px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="2270.0874"
|
||||
y="2308.2637"
|
||||
id="text5084-7"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5086-8"
|
||||
x="2270.0874"
|
||||
y="2308.2637" /></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3776-6-6"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(0.83313297,0,0,0.83313363,76.628678,129.4161)"><flowRegion
|
||||
id="flowRegion3778-9"><rect
|
||||
id="rect3780-6"
|
||||
width="29"
|
||||
height="71"
|
||||
x="52"
|
||||
y="60" /></flowRegion><flowPara
|
||||
id="flowPara3782-8" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.32533264px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="3972.6985"
|
||||
y="2935.4377"
|
||||
id="text5084-3-4"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5086-9"
|
||||
x="3972.6985"
|
||||
y="2935.4377" /></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3776-0"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(0.83313297,0,0,0.83313363,-535.58967,134.25349)"><flowRegion
|
||||
id="flowRegion3778-6"><rect
|
||||
id="rect3780-9"
|
||||
width="29"
|
||||
height="71"
|
||||
x="52"
|
||||
y="60" /></flowRegion><flowPara
|
||||
id="flowPara3782-3" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.32533264px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="3360.4797"
|
||||
y="2940.2754"
|
||||
id="text5084-9"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5086-96"
|
||||
x="3360.4797"
|
||||
y="2940.2754" /></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot5144"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(0.90032116,0,0,0.90032187,-704.04381,822.02136)"><flowRegion
|
||||
id="flowRegion5146"><rect
|
||||
id="rect5148"
|
||||
width="29"
|
||||
height="71"
|
||||
x="52"
|
||||
y="60" /></flowRegion><flowPara
|
||||
id="flowPara5150" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:36.01285934px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="3506.2246"
|
||||
y="3854.3357"
|
||||
id="text5152"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5154"
|
||||
x="3506.2246"
|
||||
y="3854.3357" /></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot5388"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(1.1287608,0,0,1.1287617,-518.09387,856.33891)"><flowRegion
|
||||
id="flowRegion5390"><rect
|
||||
id="rect5392"
|
||||
width="29"
|
||||
height="71"
|
||||
x="52"
|
||||
y="60" /></flowRegion><flowPara
|
||||
id="flowPara5394" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:45.15045166px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="4760.4517"
|
||||
y="4658.0464"
|
||||
id="text5396"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5398"
|
||||
x="4760.4517"
|
||||
y="4658.0464" /></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3776-2-9"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.32533264px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion
|
||||
id="flowRegion3778-7-9"><rect
|
||||
id="rect3780-0"
|
||||
width="24.160856"
|
||||
height="59.152489"
|
||||
x="920.29907"
|
||||
y="14.729361" /></flowRegion><flowPara
|
||||
id="flowPara3782-5" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.32533264px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="4773.0464"
|
||||
y="2770.7634"
|
||||
id="text5084-7-9"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5086-0"
|
||||
x="4773.0464"
|
||||
y="2770.7634" /></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
Reference in New Issue
Block a user