Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62d3fd7e94 | ||
|
|
acdac4ca30 | ||
|
|
221cf11576 | ||
|
|
d34fceb48f | ||
|
|
4cc4cef4ca | ||
|
|
969ffd3d0a | ||
|
|
81a505c752 | ||
|
|
eafcf0dba6 | ||
|
|
0539468d3d | ||
|
|
5e9361ac77 | ||
|
|
54fb31d6a5 | ||
|
|
0f7da91e77 | ||
|
|
13bbb3e435 |
@@ -1,5 +1,10 @@
|
||||
# Change Log
|
||||
|
||||
## 1.30.1
|
||||
* Improve usability of cropping limiter
|
||||
* Draw round corners around region of interest
|
||||
* Update Indonesian translation
|
||||
|
||||
## 1.30.0
|
||||
* Add a handle to define a region of interest
|
||||
* Add a setting to show/hide cropping limiter
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ android {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion sdk_version
|
||||
|
||||
versionCode 66
|
||||
versionName '1.30.0'
|
||||
versionCode 67
|
||||
versionName '1.30.1'
|
||||
|
||||
// it's recommended to set this value to the lowest API level
|
||||
// able to provide all the functionality
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.hardware.Camera
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Vibrator
|
||||
import android.support.design.widget.FloatingActionButton
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.support.v8.renderscript.RSRuntimeException
|
||||
@@ -28,6 +29,7 @@ import de.markusfisch.android.binaryeye.graphics.Mapping
|
||||
import de.markusfisch.android.binaryeye.graphics.frameToView
|
||||
import de.markusfisch.android.binaryeye.graphics.isPortrait
|
||||
import de.markusfisch.android.binaryeye.rs.Preprocessor
|
||||
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
|
||||
import de.markusfisch.android.binaryeye.widget.DetectorView
|
||||
import de.markusfisch.android.binaryeye.widget.toast
|
||||
import de.markusfisch.android.binaryeye.zxing.Zxing
|
||||
@@ -53,7 +55,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
private lateinit var cameraView: CameraView
|
||||
private lateinit var detectorView: DetectorView
|
||||
private lateinit var zoomBar: SeekBar
|
||||
private lateinit var flashFab: View
|
||||
private lateinit var flashFab: FloatingActionButton
|
||||
|
||||
private var preprocessor: Preprocessor? = null
|
||||
private var nativeMapping: Mapping? = null
|
||||
@@ -110,13 +112,13 @@ class CameraActivity : AppCompatActivity() {
|
||||
cameraView = findViewById(R.id.camera_view) as CameraView
|
||||
detectorView = findViewById(R.id.detector_view) as DetectorView
|
||||
zoomBar = findViewById(R.id.zoom) as SeekBar
|
||||
flashFab = findViewById(R.id.flash)
|
||||
flashFab.setOnClickListener { toggleTorchMode() }
|
||||
flashFab = findViewById(R.id.flash) as FloatingActionButton
|
||||
|
||||
initCameraView()
|
||||
initZoomBar()
|
||||
restoreZoom()
|
||||
detectorView.updateRoi = { recreatePreprocessor = true }
|
||||
detectorView.setPaddingFromWindowInsets()
|
||||
|
||||
if (intent?.action == Intent.ACTION_SEND &&
|
||||
intent.type == "text/plain"
|
||||
@@ -193,7 +195,7 @@ class CameraActivity : AppCompatActivity() {
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.create -> {
|
||||
startActivity(MainActivity.getEncodeIntent(this))
|
||||
createBarcode()
|
||||
true
|
||||
}
|
||||
R.id.history -> {
|
||||
@@ -228,6 +230,10 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBarcode() {
|
||||
startActivity(MainActivity.getEncodeIntent(this))
|
||||
}
|
||||
|
||||
private fun switchCamera() {
|
||||
closeCamera()
|
||||
frontFacing = frontFacing xor true
|
||||
@@ -412,11 +418,13 @@ class CameraActivity : AppCompatActivity() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateFlashFab(available: Boolean) {
|
||||
flashFab.visibility = if (available) {
|
||||
View.GONE
|
||||
private fun updateFlashFab(unavailable: Boolean) {
|
||||
if (unavailable) {
|
||||
flashFab.setImageResource(R.drawable.ic_action_create)
|
||||
flashFab.setOnClickListener { createBarcode() }
|
||||
} else {
|
||||
View.VISIBLE
|
||||
flashFab.setImageResource(R.drawable.ic_action_flash)
|
||||
flashFab.setOnClickListener { toggleTorchMode() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package de.markusfisch.android.binaryeye.graphics
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.DashPathEffect
|
||||
import android.graphics.Paint
|
||||
import android.support.v4.content.ContextCompat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
fun Context.getDashedBorderPaint() = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
val dp = resources.displayMetrics.density
|
||||
color = ContextCompat.getColor(applicationContext, R.color.crop_bound)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = dp * 2f
|
||||
pathEffect = DashPathEffect(floatArrayOf(10f * dp, 10f * dp), 0f)
|
||||
}
|
||||
+2
-2
@@ -7,14 +7,14 @@ import android.graphics.Point
|
||||
import android.support.v4.content.ContextCompat
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
|
||||
class Candidates(context: Context) {
|
||||
class Dots(context: Context) {
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val radius = 8f * context.resources.displayMetrics.density
|
||||
|
||||
init {
|
||||
paint.color = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.candidate
|
||||
R.color.dot
|
||||
)
|
||||
paint.style = Paint.Style.FILL
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package de.markusfisch.android.binaryeye.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import android.util.AttributeSet
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.graphics.Candidates
|
||||
import de.markusfisch.android.binaryeye.graphics.Dots
|
||||
import de.markusfisch.android.binaryeye.graphics.getDashedBorderPaint
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class CropImageView(context: Context, attr: AttributeSet) :
|
||||
@@ -14,25 +16,20 @@ class CropImageView(context: Context, attr: AttributeSet) :
|
||||
|
||||
var onScan: (() -> List<Point>?)? = null
|
||||
|
||||
private val candidates = Candidates(context)
|
||||
private val boundsPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val dots = Dots(context)
|
||||
private val boundsPaint = context.getDashedBorderPaint()
|
||||
private val lastMappedRect = RectF()
|
||||
private val dp = context.resources.displayMetrics.density
|
||||
private val padding: Int = (dp * 24f).roundToInt()
|
||||
private val padding: Int = (24f * context.resources.displayMetrics.density).roundToInt()
|
||||
private val onScanRunnable = Runnable {
|
||||
onScan?.invoke()?.let {
|
||||
candidatePoints = it
|
||||
resultPoints = it
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private var candidatePoints: List<Point>? = null
|
||||
private var resultPoints: List<Point>? = null
|
||||
|
||||
init {
|
||||
boundsPaint.color = ContextCompat.getColor(context, R.color.crop_bound)
|
||||
boundsPaint.style = Paint.Style.STROKE
|
||||
boundsPaint.strokeWidth = dp * 2f
|
||||
boundsPaint.pathEffect = DashPathEffect(floatArrayOf(dp * 10f, dp * 10f), 0f)
|
||||
scaleType = ScaleType.CENTER_CROP
|
||||
}
|
||||
|
||||
@@ -85,10 +82,10 @@ class CropImageView(context: Context, attr: AttributeSet) :
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
canvas.drawRect(bounds, boundsPaint)
|
||||
candidatePoints?.let {
|
||||
candidates.draw(canvas, it)
|
||||
resultPoints?.let {
|
||||
dots.draw(canvas, it)
|
||||
}
|
||||
candidatePoints = null
|
||||
resultPoints = null
|
||||
val mr = mappedRect ?: return
|
||||
if (mr != lastMappedRect) {
|
||||
removeCallbacks(onScanRunnable)
|
||||
|
||||
@@ -4,16 +4,18 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.os.Build
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.prefs
|
||||
import de.markusfisch.android.binaryeye.graphics.Candidates
|
||||
import de.markusfisch.android.binaryeye.graphics.Dots
|
||||
import de.markusfisch.android.binaryeye.graphics.getBitmapFromDrawable
|
||||
import de.markusfisch.android.binaryeye.graphics.getDashedBorderPaint
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
import kotlin.math.round
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class DetectorView : View {
|
||||
@@ -21,34 +23,42 @@ class DetectorView : View {
|
||||
|
||||
var updateRoi: (() -> Unit)? = null
|
||||
|
||||
private val candidates = Candidates(context)
|
||||
private val dots = Dots(context)
|
||||
private val invalidateRunnable: Runnable = Runnable {
|
||||
marks = null
|
||||
invalidate()
|
||||
}
|
||||
private val roiPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val roiPaint = context.getDashedBorderPaint()
|
||||
private val handleBitmap = resources.getBitmapFromDrawable(
|
||||
R.drawable.ic_crop_handle
|
||||
R.drawable.button_crop
|
||||
)
|
||||
private val handleXRadius = handleBitmap.width / 2
|
||||
private val handleYRadius = handleBitmap.height / 2
|
||||
private val distToFull: Float
|
||||
private val handleHome = Point()
|
||||
private val handlePos = Point(-1, -1)
|
||||
private val center = Point()
|
||||
private val touchDown = Point()
|
||||
private val distToFull: Int
|
||||
private val minMoveThresholdSq: Int
|
||||
private val cornerRadius: Int
|
||||
private val fabHeight: Int
|
||||
private val padding: Int
|
||||
|
||||
private var marks: List<Point>? = null
|
||||
private var center = PointF()
|
||||
private var handlePos = PointF()
|
||||
private var orientation = resources.configuration.orientation
|
||||
private var handleGrabbed = false
|
||||
private var handleMoved = false
|
||||
private var shadeColor = 0
|
||||
|
||||
init {
|
||||
val dp = context.resources.displayMetrics.density
|
||||
distToFull = 24f * dp
|
||||
roiPaint.apply {
|
||||
style = Paint.Style.STROKE
|
||||
color = 0xffffffff.toInt()
|
||||
strokeWidth = 2f * dp
|
||||
pathEffect = DashPathEffect(floatArrayOf(10f, 20f), 0f)
|
||||
}
|
||||
distToFull = (24f * dp).roundToInt()
|
||||
val minMoveThreshold = (8f * dp).roundToInt()
|
||||
minMoveThresholdSq = minMoveThreshold * minMoveThreshold
|
||||
cornerRadius = (8f * dp).roundToInt()
|
||||
fabHeight = (92f * dp).roundToInt()
|
||||
padding = (20f * dp).roundToInt()
|
||||
isSaveEnabled = true
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) :
|
||||
@@ -64,14 +74,46 @@ class DetectorView : View {
|
||||
postDelayed(invalidateRunnable, 500)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(): Parcelable? {
|
||||
if (!handleMoved) {
|
||||
return super.onSaveInstanceState()
|
||||
}
|
||||
return SavedState(super.onSaveInstanceState()).apply {
|
||||
savedHandlePos.set(handlePos)
|
||||
savedOrientation = orientation
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(state: Parcelable) {
|
||||
super.onRestoreInstanceState(
|
||||
if (state is SavedState) {
|
||||
if (state.savedOrientation == orientation) {
|
||||
handlePos.set(state.savedHandlePos)
|
||||
} else {
|
||||
handlePos.set(
|
||||
state.savedHandlePos.y,
|
||||
state.savedHandlePos.x
|
||||
)
|
||||
}
|
||||
handleMoved = true
|
||||
state.superState
|
||||
} else {
|
||||
state
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||
event ?: return super.onTouchEvent(event)
|
||||
val x = event.x.roundToInt()
|
||||
val y = event.y.roundToInt()
|
||||
return when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
if (prefs.showCropHandle) {
|
||||
handleGrabbed = abs(event.x - handlePos.x) < handleXRadius &&
|
||||
abs(event.y - handlePos.y) < handleYRadius
|
||||
touchDown.set(x, y)
|
||||
handleGrabbed = abs(x - handlePos.x) < handleXRadius &&
|
||||
abs(y - handlePos.y) < handleYRadius
|
||||
handleGrabbed
|
||||
} else {
|
||||
false
|
||||
@@ -79,7 +121,10 @@ class DetectorView : View {
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (handleGrabbed) {
|
||||
handlePos.set(event.x, event.y)
|
||||
handlePos.set(x, y)
|
||||
if (distSq(handlePos, touchDown) > minMoveThresholdSq) {
|
||||
handleMoved = true
|
||||
}
|
||||
invalidate()
|
||||
true
|
||||
} else {
|
||||
@@ -88,14 +133,23 @@ class DetectorView : View {
|
||||
}
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
if (handleGrabbed) {
|
||||
snap(event.x, event.y)
|
||||
snap(x, y)
|
||||
handleGrabbed = false
|
||||
}
|
||||
false
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
if (handleGrabbed) {
|
||||
snap(event.x, event.y)
|
||||
if (!handleMoved) {
|
||||
handlePos.set(
|
||||
(center.x * 1.5f).roundToInt(),
|
||||
(center.y * 1.25f).roundToInt()
|
||||
)
|
||||
handleMoved = true
|
||||
invalidate()
|
||||
} else {
|
||||
snap(x, y)
|
||||
}
|
||||
updateRoi?.invoke()
|
||||
handleGrabbed = false
|
||||
}
|
||||
@@ -105,13 +159,12 @@ class DetectorView : View {
|
||||
}
|
||||
}
|
||||
|
||||
private fun snap(x: Float, y: Float) {
|
||||
if (abs(x - center.x) < distToFull) {
|
||||
handlePos.x = center.x
|
||||
invalidate()
|
||||
}
|
||||
if (abs(y - center.y) < distToFull) {
|
||||
handlePos.y = center.y
|
||||
private fun snap(x: Int, y: Int) {
|
||||
if (abs(x - center.x) < distToFull ||
|
||||
abs(y - center.y) < distToFull
|
||||
) {
|
||||
handlePos.set(handleHome)
|
||||
handleMoved = false
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
@@ -121,62 +174,153 @@ class DetectorView : View {
|
||||
val width = right - left
|
||||
val height = bottom - top
|
||||
center.set(
|
||||
(left + (width / 2)).toFloat(),
|
||||
(top + (height / 2)).toFloat()
|
||||
left + (width / 2),
|
||||
top + (height / 2)
|
||||
)
|
||||
if (width > height) {
|
||||
handlePos.set(round(right * .75f), center.y)
|
||||
} else {
|
||||
handlePos.set(center.x, round(bottom * .75f))
|
||||
handleHome.set(
|
||||
width - handleXRadius - paddingRight - padding,
|
||||
height - handleYRadius - paddingBottom - fabHeight
|
||||
)
|
||||
if (handlePos.x < 0) {
|
||||
handlePos.set(handleHome)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
canvas.drawColor(0, PorterDuff.Mode.CLEAR)
|
||||
updateClipRect()
|
||||
if (roi.height() > 0 && roi.width() > 0) {
|
||||
// canvas.clipRect() doesn't work reliably below KITKAT
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
canvas.save()
|
||||
canvas.clipOutRectCompat(roi)
|
||||
canvas.drawColor(shadeColor, PorterDuff.Mode.SRC)
|
||||
canvas.restore()
|
||||
} else {
|
||||
canvas.drawRect(roi, roiPaint)
|
||||
}
|
||||
if (handleMoved) {
|
||||
drawClip(canvas)
|
||||
}
|
||||
marks?.let {
|
||||
candidates.draw(canvas, it)
|
||||
dots.draw(canvas, it)
|
||||
}
|
||||
if (prefs.showCropHandle) {
|
||||
canvas.drawBitmap(
|
||||
handleBitmap,
|
||||
handlePos.x - handleXRadius,
|
||||
handlePos.y - handleYRadius,
|
||||
(handlePos.x - handleXRadius).toFloat(),
|
||||
(handlePos.y - handleYRadius).toFloat(),
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateClipRect() {
|
||||
private fun drawClip(canvas: Canvas) {
|
||||
val minDist = updateClipRect()
|
||||
if (minDist < 1) {
|
||||
return
|
||||
}
|
||||
// canvas.clipRect() doesn't work reliably below KITKAT
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
val radius = min(minDist / 2, cornerRadius).toFloat()
|
||||
canvas.save()
|
||||
canvas.clipOutPathCompat(
|
||||
calculateRoundedRectPath(
|
||||
roi.left.toFloat(),
|
||||
roi.top.toFloat(),
|
||||
roi.right.toFloat(),
|
||||
roi.bottom.toFloat(),
|
||||
radius,
|
||||
radius
|
||||
)
|
||||
)
|
||||
canvas.drawColor(shadeColor, PorterDuff.Mode.SRC)
|
||||
canvas.restore()
|
||||
} else {
|
||||
canvas.drawRect(roi, roiPaint)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateClipRect(): Int {
|
||||
val dx = abs(handlePos.x - center.x)
|
||||
val dy = abs(handlePos.y - center.y)
|
||||
val d = min(dx, dy)
|
||||
shadeColor = (min(1f, d / distToFull) * 128f).toInt() shl 24
|
||||
shadeColor = (min(
|
||||
1f,
|
||||
d.toFloat() / distToFull.toFloat()
|
||||
) * 128f).toInt() shl 24
|
||||
roi.set(
|
||||
(center.x - dx).roundToInt(),
|
||||
(center.y - dy).roundToInt(),
|
||||
(center.x + dx).roundToInt(),
|
||||
(center.y + dy).roundToInt()
|
||||
center.x - dx,
|
||||
center.y - dy,
|
||||
center.x + dx,
|
||||
center.y + dy
|
||||
)
|
||||
return d
|
||||
}
|
||||
|
||||
internal class SavedState : BaseSavedState {
|
||||
val savedHandlePos = Point()
|
||||
|
||||
var savedOrientation = 0
|
||||
|
||||
constructor(superState: Parcelable?) : super(superState)
|
||||
|
||||
private constructor(parcel: Parcel) : super(parcel) {
|
||||
savedHandlePos.set(
|
||||
parcel.readInt(),
|
||||
parcel.readInt()
|
||||
)
|
||||
savedOrientation = parcel.readInt()
|
||||
}
|
||||
|
||||
override fun writeToParcel(out: Parcel, flags: Int) {
|
||||
super.writeToParcel(out, flags)
|
||||
out.writeInt(savedHandlePos.x)
|
||||
out.writeInt(savedHandlePos.y)
|
||||
out.writeInt(savedOrientation)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val CREATOR = object : Parcelable.Creator<SavedState> {
|
||||
override fun createFromParcel(source: Parcel) = SavedState(source)
|
||||
override fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Canvas.clipOutRectCompat(rect: Rect) {
|
||||
private fun distSq(a: Point, b: Point): Int {
|
||||
val dx = a.x - b.x
|
||||
val dy = a.y - b.y
|
||||
return dx * dx + dy * dy
|
||||
}
|
||||
|
||||
private fun Point.set(point: Point) {
|
||||
x = point.x
|
||||
y = point.y
|
||||
}
|
||||
|
||||
private fun Canvas.clipOutPathCompat(path: Path) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
clipOutRect(rect)
|
||||
clipOutPath(path)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
clipRect(rect, Region.Op.DIFFERENCE)
|
||||
clipPath(path, Region.Op.DIFFERENCE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateRoundedRectPath(
|
||||
left: Float,
|
||||
top: Float,
|
||||
right: Float,
|
||||
bottom: Float,
|
||||
rx: Float,
|
||||
ry: Float
|
||||
): Path {
|
||||
val width = right - left
|
||||
val height = bottom - top
|
||||
val widthMinusCorners = width - 2 * rx
|
||||
val heightMinusCorners = height - 2 * ry
|
||||
return Path().apply {
|
||||
moveTo(right, top + ry)
|
||||
rQuadTo(0f, -ry, -rx, -ry)
|
||||
rLineTo(-widthMinusCorners, 0f)
|
||||
rQuadTo(-rx, 0f, -rx, ry)
|
||||
rLineTo(0f, heightMinusCorners)
|
||||
rQuadTo(0f, ry, rx, ry)
|
||||
rLineTo(widthMinusCorners, 0f)
|
||||
rQuadTo(rx, 0f, rx, -ry)
|
||||
rLineTo(0f, -heightMinusCorners)
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<string name="switch_camera">Kamera wechseln</string>
|
||||
<string name="history">Gespeicherte Codes</string>
|
||||
<string name="preferences">Einstellungen</string>
|
||||
<string name="show_crop_handle">Ausschnittseinschränker anzeigen</string>
|
||||
<string name="show_crop_handle">Bereich verkleinern anzeigen</string>
|
||||
<string name="zoom_by_swiping">Hoch/Runter streichen um zu zoomen</string>
|
||||
<string name="auto_rotate">Vertikale Erkennung von 1D Barcodes</string>
|
||||
<string name="try_harder">Suche länger und gründlicher nach Barcodes</string>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<string name="binary_data">(data biner)</string>
|
||||
<plurals name="barcode_info">
|
||||
<item quantity="other">%1$s, %2$d karakter</item>
|
||||
|
||||
</plurals>
|
||||
<string name="error_correction_level">Level koreksi kesalahan</string>
|
||||
<string name="issue_number">Nomor pemindaian</string>
|
||||
@@ -37,9 +38,9 @@
|
||||
<string name="switch_camera">Ganti kamera</string>
|
||||
<string name="history">Riwayat</string>
|
||||
<string name="preferences">Preferensi</string>
|
||||
<string name="show_crop_handle">Show cropping limiter</string>
|
||||
<string name="show_crop_handle">Tampilkan pembatas pemotongan</string>
|
||||
<string name="zoom_by_swiping">Perbesar kamera dengan menggeser ke atas/bawah</string>
|
||||
<string name="auto_rotate">Recognize 1D barcodes vertically</string>
|
||||
<string name="auto_rotate">Kenali barcode 1D secara vertikal</string>
|
||||
<string name="try_harder">Optimalkan akurasi, bukan kecepatan</string>
|
||||
<string name="vibrate">Bergetar saat mendeteksi</string>
|
||||
<string name="use_history">Simpan riwayat pemindaian</string>
|
||||
@@ -50,9 +51,9 @@
|
||||
<string name="open_with_url">Buka data tak dikenal dengan URL</string>
|
||||
<string name="really_remove_scan">Yakin menghapus pemindaian?</string>
|
||||
<string name="really_remove_all_scans">Yakin menghapus semua pemindaian?</string>
|
||||
<string name="really_remove_selected_scans">Really remove selected scans?</string>
|
||||
<string name="really_remove_selected_scans">Yakin menghapus semua pemindaian?</string>
|
||||
<string name="clear_history">Hapus riwayat</string>
|
||||
<string name="copy_scan">Copy scan</string>
|
||||
<string name="copy_scan">Salin pemindaian</string>
|
||||
<string name="edit_scan">Sunting label</string>
|
||||
<string name="remove_scan">Buang pindaian</string>
|
||||
<string name="enter_name">Masukkan keterangan pemindaian</string>
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
<color name="selected_row">#222</color>
|
||||
<color name="separator">#333</color>
|
||||
<color name="crop_bound">#fff</color>
|
||||
<color name="candidate">#80b6d46f</color>
|
||||
<color name="dot">#80b6d46f</color>
|
||||
</resources>
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
buildscript {
|
||||
ext {
|
||||
kotlin_version = '1.3.72'
|
||||
tools_version = '3.6.3'
|
||||
tools_version = '4.0.0'
|
||||
build_tools_version = '29.0.3'
|
||||
sdk_version = 29
|
||||
support_version = '25.3.1'
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Tue May 07 14:37:45 CEST 2019
|
||||
#Sun May 31 13:11:56 CEST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||
|
||||
|
Before Width: | Height: | Size: 885 B After Width: | Height: | Size: 885 B |
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg height="48px" viewBox="0 0 48 48" width="48px" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle style="fill: rgb(182, 212, 111);" cx="24" cy="24" r="24"/>
|
||||
<path d="M 29 27 L 31 27 L 31 19 C 31 17.9 30.1 17 29 17 L 21 17 L 21 19 L 29 19 L 29 27 Z M 19 29 L 19 13 L 17 13 L 17 17 L 13 17 L 13 19 L 17 19 L 17 29 C 17 30.1 17.9 31 19 31 L 29 31 L 29 35 L 31 35 L 31 31 L 35 31 L 35 29 L 19 29 Z" style="fill: rgb(255, 255, 255);"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 478 B |
Reference in New Issue
Block a user