Adding app module
This commit is contained in:
@@ -74,6 +74,8 @@ android {
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(project(":util"))
|
||||
|
||||
implementation(Libs.activity_compose)
|
||||
implementation(Libs.navigation_compose)
|
||||
implementation(Libs.core_ktx)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:name=".app.App"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.AndroidStudyCase">
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.ericampire.android.androidstudycase.app
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class App : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,11 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("kotlin-android")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = Apps.compileSdk
|
||||
defaultConfig {
|
||||
minSdk = Apps.minSdk
|
||||
}
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.kts.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="org.zxconnect.android.beserve.i18n">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="notification_tabs">
|
||||
<item>Commandes</item>
|
||||
<item>Tout</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="notification_channel_names">
|
||||
<item>Nouveau fournisseur</item>
|
||||
<item>Promotions</item>
|
||||
<item>Commandes</item>
|
||||
<item>Nouvelle mise à jour</item>
|
||||
<item>Globale</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="notification_channel_ids">
|
||||
<item>stores</item>
|
||||
<item>products</item>
|
||||
<item>orders</item>
|
||||
<item>global</item>
|
||||
<item>default</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="notification_channel_descriptions">
|
||||
<item>Être notifié lorsqu\'un nouveau fournisseur est disponible sur Be Served.</item>
|
||||
<item>Être notifié lorsqu\'il y a de nouvelles promotions.</item>
|
||||
<item>Être notifié lorsque l\'état de votre commande change.</item>
|
||||
<item>Être notifié lorsqu\'une nouvelle version de l\'application est disponible.</item>
|
||||
<item>Autres notifications.</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="history_items">
|
||||
<item>En cours</item>
|
||||
<item>Refusée</item>
|
||||
<item>Historique</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">Study case</string>
|
||||
<string name="app_channel_name">Be Served Channel</string>
|
||||
|
||||
</resources>
|
||||
@@ -16,3 +16,5 @@ dependencyResolutionManagement {
|
||||
}
|
||||
rootProject.name = "android-study-case"
|
||||
include(":app")
|
||||
include(":util")
|
||||
include(":i18n")
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,48 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("kotlin-android")
|
||||
kotlin("kapt")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = Apps.compileSdk
|
||||
buildToolsVersion = Apps.buildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdk = Apps.minSdk
|
||||
targetSdk = Apps.targetSdk
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
api(project(":i18n"))
|
||||
implementation(Libs.core_ktx)
|
||||
|
||||
api(platform(Libs.kotlin_coroutine_bom))
|
||||
api(Libs.kotlin_coroutine_core)
|
||||
|
||||
testImplementation(Libs.junit_jupiter_api)
|
||||
testImplementation(Libs.junit_jupiter_engine)
|
||||
|
||||
testImplementation(Libs.mockk_core)
|
||||
|
||||
api(Libs.hilt_android)
|
||||
kapt(Libs.hilt_android_compiler)
|
||||
|
||||
api(Libs.timber)
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.zxconnect.android.beserve.util">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.zxconnect.android.beserve.util
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class DefaultDispatcher
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class IoDispatcher
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class MainDispatcher
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class MainImmediateDispatcher
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ApplicationScope
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.zxconnect.android.beserve.util
|
||||
|
||||
import androidx.lifecycle.Observer
|
||||
|
||||
open class Event<out T>(private val content: T) {
|
||||
|
||||
var hasBeenHandled = false
|
||||
private set // Allow external read but not write
|
||||
|
||||
/**
|
||||
* Returns the content and prevents its use again.
|
||||
*/
|
||||
fun getContentIfNotHandled(): T? {
|
||||
return if (hasBeenHandled) {
|
||||
null
|
||||
} else {
|
||||
hasBeenHandled = true
|
||||
content
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content, even if it's already been handled.
|
||||
*/
|
||||
fun peekContent(): T = content
|
||||
}
|
||||
|
||||
/**
|
||||
* An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has
|
||||
* already been handled.
|
||||
*
|
||||
* [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled.
|
||||
*/
|
||||
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
|
||||
override fun onChanged(event: Event<T>?) {
|
||||
event?.getContentIfNotHandled()?.let { value ->
|
||||
onEventUnhandledContent(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.zxconnect.android.beserve.util
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
||||
sealed class Result<out R> {
|
||||
|
||||
data class Success<out T>(val data: T) : Result<T>()
|
||||
data class Error(val exception: Exception) : Result<Nothing>()
|
||||
object Loading : Result<Nothing>()
|
||||
|
||||
override fun toString(): String {
|
||||
return when (this) {
|
||||
is Success<*> -> "Success[data=$data]"
|
||||
is Error -> "Error[exception=$exception]"
|
||||
Loading -> "Loading"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `true` if [Result] is of type [Success] & hoxlds non-null [Success.data].
|
||||
*/
|
||||
val Result<*>.succeeded
|
||||
get() = this is Result.Success && data != null
|
||||
|
||||
fun <T> Result<T>.successOr(fallback: T): T {
|
||||
return (this as? Result.Success<T>)?.data ?: fallback
|
||||
}
|
||||
|
||||
val <T> Result<T>.data: T?
|
||||
get() = (this as? Result.Success)?.data
|
||||
|
||||
/**
|
||||
* Updates value of [liveData] if [Result] is of type [Success]
|
||||
*/
|
||||
inline fun <reified T> Result<T>.updateOnSuccess(liveData: MutableLiveData<T>) {
|
||||
if (this is Result.Success) {
|
||||
liveData.value = data
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.zxconnect.android.beserve.util.usecase
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.zxconnect.android.beserve.util.Result
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
abstract class CoroutineUseCase<in P, R>(private val coroutineDispatcher: CoroutineDispatcher) {
|
||||
|
||||
/** Executes the use case asynchronously and returns a [Result].
|
||||
*
|
||||
* @return a [Result].
|
||||
*
|
||||
* @param parameters the input parameters to run the use case with
|
||||
*/
|
||||
suspend operator fun invoke(parameters: P): Result<R> {
|
||||
return try {
|
||||
// Moving all use case's executions to the injected dispatcher
|
||||
// In production code, this is usually the Default dispatcher (background thread)
|
||||
// In tests, this becomes a TestCoroutineDispatcher
|
||||
withContext(coroutineDispatcher) {
|
||||
execute(parameters).let {
|
||||
Result.Success(it)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.d(e)
|
||||
Result.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to set the code to be executed.
|
||||
*/
|
||||
@Throws(RuntimeException::class)
|
||||
protected abstract suspend fun execute(parameters: P): R
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.zxconnect.android.beserve.util.usecase
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import org.zxconnect.android.beserve.util.Result
|
||||
|
||||
/**
|
||||
* Executes business logic in its execute method and keep posting updates to the result as
|
||||
* [Result<R>].
|
||||
* Handling an exception (emit [Result.Error] to the result) is the subclasses's responsibility.
|
||||
*/
|
||||
abstract class FlowUseCase<in P, R>(private val coroutineDispatcher: CoroutineDispatcher) {
|
||||
operator fun invoke(parameters: P): Flow<Result<R>> = execute(parameters)
|
||||
.catch { e -> emit(Result.Error(Exception(e))) }
|
||||
.flowOn(coroutineDispatcher)
|
||||
|
||||
protected abstract fun execute(parameters: P): Flow<Result<R>>
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.zxconnect.android.beserve.util
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user