Skip to content

Commit

Permalink
Merge branch 'release/0.5.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
G00fY2 committed Jan 26, 2021
2 parents c83671b + a5c1d27 commit ae46548
Show file tree
Hide file tree
Showing 18 changed files with 93 additions and 70 deletions.
18 changes: 18 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
The MIT License (MIT)

Copyright (C) 2021 Thomas Wirth

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
<img width="345" height="120" src="https://raw.githubusercontent.com/G00fY2/Quickie/gh-pages/media/logo.png">
</p>

**quickie** is a Quick Response (QR) Code scanning library for Android that is based on CameraX and ML Kit on-device barcode detection. It's an alternative to ZXing and written in Kotlin. quickie features:
- Easy API for launching the QR scanner and receiving results by using the AndroidX Activity Result API
**quickie** is a Quick Response (QR) Code scanning library for Android that is based on CameraX and ML Kit on-device barcode detection. It's an alternative to ZXing based libraries and written in Kotlin. quickie features:
- Easy API for launching the QR scanner and receiving results by using the new Activity Result API
- Modern design, edge-to-edge scanning view with multilingual user hint
- Android Jetpack CameraX for communicating with the camera and showing the preview
- ML Kit on-device barcode recognition and decoding (no network connection required)
- ML Kit Vision API for best, fully on-device barcode recognition and decoding

## Download [![Download](https://img.shields.io/maven-metadata/v?label=quickie-bundled&metadataUrl=https%3A%2F%2Fbintray.com%2Fg00fy2%2Fmaven%2Fdownload_file%3Ffile_path%3Dcom%252Fg00fy2%252Fquickie%252Fquickie-unbundled%252Fmaven-metadata.xml)](https://bintray.com/g00fy2/maven/quickie-bundled) [![Download](https://img.shields.io/maven-metadata/v?label=quickie-unbundled&metadataUrl=https%3A%2F%2Fbintray.com%2Fg00fy2%2Fmaven%2Fdownload_file%3Ffile_path%3Dcom%252Fg00fy2%252Fquickie%252Fquickie-bundled%252Fmaven-metadata.xml)](https://bintray.com/g00fy2/maven/quickie-unbundled)
There are two different flavors available on `jcenter()`:

| Bundled | Unbundled |
| ----------------------------------- | ------------------------------------------------- |
| ML Kit model is bundled inside app (independed of Google Services) | ML Kit model will be automatically downloaded via Play Services (after app install) |
| ML Kit model is bundled inside app (independent of Google Services) | ML Kit model will be automatically downloaded via Play Services (after app install) |
| additional 1.1 MB size per ABI (you should use AAB or ABI splitting) | smaller app size |
| V2 barcode model is used (possibly faster, more accurate) | currently V1 will be downloaded
```kotlin
Expand All @@ -25,7 +25,7 @@ implementation("com.g00fy2.quickie:quickie-unbundled:0.5.2")
```

## Quick Start
To use the QR scanner simply register the `ScanQRCode()` ActivityResultContract together with a callback during `initialization` or in the `onCreate()` lifecycle of your Activity/Fragment and call `launch(null)` anywhere to start it:
To use the QR scanner simply register the `ScanQRCode()` ActivityResultContract together with a callback during `init` or `onCreate()` lifecycle of your Activity/Fragment and use the returned ActivityResultLauncher to launch the QR scanner activity.
```kotlin
val scanQrCode = registerForActivityResult(ScanQRCode(), ::handleResult)

Expand All @@ -38,50 +38,52 @@ override fun onCreate(savedInstanceState: Bundle?) {
fun handleResult(result: QRResult) {
```
⚠️ **You can't register the ActivityResultContract inside the OnClickListener lambda. This will fail since the code get's executed after the onCreate lifecycle!**
⚠️ **You can't register the ActivityResultContract inside the OnClickListener lambda. This will fail since the code gets executed after the onCreate lifecycle!**
Check out the [samples](https://github.com/G00fY2/quickie/tree/develop/sample) inside this repo or visit the [Activity Result API documentation](https://developer.android.com/training/basics/intents/result) for more information.
#### Responses
The callback you add to the `registerForActivityResult` will receive an instance of the sealed `QRResult` class:
The callback you add to the `registerForActivityResult` will receive a subclass of the sealed `QRResult` class:
1. `QRSuccess` when ML Kit successfully detected a QR code
1. wraps a `QRContent` object
* wraps a `QRContent` object
1. `QRUserCanceled` when the activity got canceled by the user
1. `QRMissingPermission` when the user didn't accept the camera permission
1. `QRError` when CameraX or ML kit threw an exception
1. wraps the `exception`
* wraps the `exception`

#### Content
**quickie** wraps the content type of the QR code detected by ML Kit inside an sealed `QRContent` class. All of them provide the `rawValue`.
The content type of the QR code detected by ML Kit is wrapped inside a subclass of the sealed `QRContent` class which always provides a `rawValue`.

Currently supported types are:
Currently, supported subtypes are:
`Plain`, `Wifi`, `Url`, `Sms`, `GeoPoint`, `Email`, `Phone`, `ContactInfo`, `CalendarEvent`

See the ML Kit [Barcode documentation](https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode#nested-class-summary) for further details.

### Customization
The library is designed to behave and look as generic as possible. Currently it's not possible to change the UI, but there are plans to add customizations in future releases.
The library is designed to behave and look as generic as possible while matching Material Design guidelines. Currently, it's not possible to change the UI, but there are plans to add customizations in future releases.
## Screenshots / Sample App
You can find the sample app APKs inside the [release](https://github.com/G00fY2/quickie/releases) assets.
### Screenshots
![Image](https://raw.githubusercontent.com/G00fY2/Quickie/gh-pages/media/quickie-device-demo.png)
## Release state
**quickie** relies on Google Jetpack libraries which are in pre-release state. CameraX has no stable release version yet and the Activity Result API is part of the latest AndroidX Activity and Fragment release candidates. Here is what Google says about this release state:
* A release candidate is a prospective stable release.
* It may contain critical last-minute fixes.
You should consider **quickie** to be in pre-release state too. I will raise the version to 1.0 once all dependent libraries hit stable.
Even though **quickie** is battle-tested you should consider this library to be in pre-release state too. This will change once the dependent libraries hit stable.
## Requirements
* AndroidX
* Min SDK 21+
* (Google Play Services available on the end device if using `quickie-unbundled`)
## License
The MIT License (MIT)
The MIT License (MIT)
Copyright (C) 2020 Thomas Wirth
Copyright (C) 2021 Thomas Wirth
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
Expand Down
14 changes: 4 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ subprojects {
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
allWarningsAsErrors = true
freeCompilerArgs = listOf("-progressive")
val arguments = mutableListOf("-progressive")
if (!this@subprojects.name.contains("sample")) arguments += "-Xexplicit-api=strict"
freeCompilerArgs = arguments
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
Expand All @@ -34,15 +36,7 @@ subprojects {

tasks.named("dependencyUpdates", DependencyUpdatesTask::class.java).configure {
gradleReleaseChannel = "current"
resolutionStrategy {
componentSelection {
all {
if (Utils.isNonStable(candidate.version) && !Utils.isNonStable(currentVersion)) {
reject("Release candidate")
}
}
}
}
rejectVersionIf { Utils.isNonStable(candidate.version) && !Utils.isNonStable(currentVersion) }
}

repositories {
Expand Down
6 changes: 3 additions & 3 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
object Versions {

const val androidGradle = "4.1.1"
const val androidGradle = "4.1.2"
const val kotlin = "1.4.21"

const val ktlintPlugin = "9.4.1"
Expand All @@ -20,6 +20,6 @@ object Versions {

const val materialDesign = "1.2.1"

const val barcodeScanning = "16.1.0"
const val barcodeScanningGms = "16.1.3"
const val barcodeScanning = "16.1.1"
const val barcodeScanningGms = "16.1.4"
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 1 addition & 1 deletion quickie/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ dependencies {
}

group = "com.g00fy2.quickie"
version = "0.5.2"
version = "0.5.3"

tasks.register<Jar>("androidJavadocJar") {
archiveClassifier.set("javadoc")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.g00fy2.quickie.utils

import android.app.Activity

object PlayServicesValidator {
internal object PlayServicesValidator {

@Suppress("UNUSED_PARAMETER")
fun handleGooglePlayServicesError(activity: Activity, exception: Exception) = false // always false when bundled
Expand Down
5 changes: 2 additions & 3 deletions quickie/src/main/kotlin/com/g00fy2/quickie/QROverlayView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.FrameLayout
import androidx.annotation.Px
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
import com.g00fy2.quickie.databinding.QuickieTextviewBinding
Expand Down Expand Up @@ -117,9 +116,9 @@ internal class QROverlayView @JvmOverloads constructor(
}
}

private fun View.updateTopMargin(@Px top: Int) {
private fun View.updateTopMargin(topPx: Int) {
val params = layoutParams as MarginLayoutParams
params.topMargin = top
params.topMargin = topPx
layoutParams = params
}

Expand Down
10 changes: 5 additions & 5 deletions quickie/src/main/kotlin/com/g00fy2/quickie/QRResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@ package com.g00fy2.quickie

import com.g00fy2.quickie.content.QRContent

sealed class QRResult {
public sealed class QRResult {

/**
* MLKit successfully detected a QR code.
*
* @property content the wrapped MLKit response.
*/
data class QRSuccess(val content: QRContent) : QRResult()
public data class QRSuccess internal constructor(val content: QRContent) : QRResult()

/**
* Activity got cancelled by the user.
*/
object QRUserCanceled : QRResult()
public object QRUserCanceled : QRResult()

/**
* Camera permission was not granted.
*/
object QRMissingPermission : QRResult()
public object QRMissingPermission : QRResult()

/**
* Error while setting up CameraX or while MLKit analysis.
*
* @property exception the cause why the Activity was finished.
*/
data class QRError(val exception: Exception) : QRResult()
public data class QRError internal constructor(val exception: Exception) : QRResult()
}
2 changes: 1 addition & 1 deletion quickie/src/main/kotlin/com/g00fy2/quickie/ScanQRCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import com.g00fy2.quickie.QRScannerActivity.Companion.RESULT_MISSING_PERMISSION
import com.g00fy2.quickie.extensions.getRootException
import com.g00fy2.quickie.extensions.toQuickieContentType

class ScanQRCode : ActivityResultContract<Nothing?, QRResult>() {
public class ScanQRCode : ActivityResultContract<Nothing?, QRResult>() {

override fun createIntent(context: Context, input: Nothing?): Intent =
Intent(context, QRScannerActivity::class.java)
Expand Down
50 changes: 30 additions & 20 deletions quickie/src/main/kotlin/com/g00fy2/quickie/content/QRContent.kt
Original file line number Diff line number Diff line change
@@ -1,65 +1,75 @@
package com.g00fy2.quickie.content

@Suppress("unused")
sealed class QRContent(val rawValue: String) {
public sealed class QRContent(public val rawValue: String) {

override fun toString() = rawValue
override fun toString(): String = rawValue

/**
* Plain text or unknown content QR Code type.
*/
data class Plain(private val _rawValue: String) : QRContent(_rawValue)
public data class Plain internal constructor(private val _rawValue: String) : QRContent(_rawValue)

/**
* Wi-Fi access point details from a 'WIFI:' or similar QR Code type.
*/
data class Wifi(private val _rawValue: String, val encryptionType: Int, val password: String, val ssid: String) :
QRContent(_rawValue)
public data class Wifi internal constructor(
private val _rawValue: String,
val encryptionType: Int,
val password: String,
val ssid: String
) : QRContent(_rawValue)

/**
* A URL or URL bookmark from a 'MEBKM:' or similar QR Code type.
*/
data class Url(private val _rawValue: String, val title: String, val url: String) : QRContent(_rawValue)
public data class Url internal constructor(private val _rawValue: String, val title: String, val url: String) :
QRContent(_rawValue)

/**
* An SMS message from an 'SMS:' or similar QR Code type.
*/
data class Sms(private val _rawValue: String, val message: String, val phoneNumber: String) : QRContent(_rawValue)
public data class Sms internal constructor(
private val _rawValue: String,
val message: String,
val phoneNumber: String
) : QRContent(_rawValue)

/**
* GPS coordinates from a 'GEO:' or similar QR Code type.
*/
data class GeoPoint(private val _rawValue: String, val lat: Double, val lng: Double) : QRContent(_rawValue)
public data class GeoPoint internal constructor(private val _rawValue: String, val lat: Double, val lng: Double) :
QRContent(_rawValue)

/**
* An email message from a 'MAILTO:' or similar QR Code type.
*/
data class Email(
public data class Email internal constructor(
private val _rawValue: String,
val address: String,
val body: String,
val subject: String,
val type: EmailType
) :
QRContent(_rawValue) {
enum class EmailType {
) : QRContent(_rawValue) {
public enum class EmailType {
UNKNOWN, WORK, HOME
}
}

/**
* A phone number from a 'TEL:' or similar QR Code type.
*/
data class Phone(private val _rawValue: String, val number: String, val type: PhoneType) : QRContent(_rawValue) {
enum class PhoneType {
public data class Phone internal constructor(private val _rawValue: String, val number: String, val type: PhoneType) :
QRContent(_rawValue) {
public enum class PhoneType {
UNKNOWN, WORK, HOME, FAX, MOBILE
}
}

/**
* A person's or organization's business card.
*/
data class ContactInfo(
public data class ContactInfo internal constructor(
private val _rawValue: String,
val addresses: List<Address>,
val emails: List<Email>,
Expand All @@ -70,13 +80,13 @@ sealed class QRContent(val rawValue: String) {
val urls: List<String>
) : QRContent(_rawValue) {

data class Address(val addressLines: List<String>, val type: AddressType) {
enum class AddressType {
public data class Address internal constructor(val addressLines: List<String>, val type: AddressType) {
public enum class AddressType {
UNKNOWN, WORK, HOME
}
}

data class PersonName(
public data class PersonName internal constructor(
val first: String,
val formattedName: String,
val last: String,
Expand All @@ -90,7 +100,7 @@ sealed class QRContent(val rawValue: String) {
/**
* A calendar event extracted from a QR Code.
*/
data class CalendarEvent(
public data class CalendarEvent internal constructor(
private val _rawValue: String,
val description: String,
val end: CalendarDateTime,
Expand All @@ -101,7 +111,7 @@ sealed class QRContent(val rawValue: String) {
val summary: String
) : QRContent(_rawValue) {

data class CalendarDateTime(
public data class CalendarDateTime internal constructor(
val day: Int,
val hours: Int,
val minutes: Int,
Expand Down
2 changes: 1 addition & 1 deletion quickie/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<resources>

<style name="QuickieScannerActivity" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:statusBarColor">@color/quickie_transparent</item>
Expand Down
Loading

0 comments on commit ae46548

Please sign in to comment.