Skip to content

Commit

Permalink
Adding app module
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-ampire committed Aug 16, 2021
1 parent 47a711a commit 15cb292
Show file tree
Hide file tree
Showing 22 changed files with 351 additions and 0 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ android {

dependencies {

implementation(project(":util"))

implementation(Libs.activity_compose)
implementation(Libs.navigation_compose)
implementation(Libs.core_ktx)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
Original file line number Diff line number Diff line change
@@ -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()
}
}
1 change: 1 addition & 0 deletions i18n/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
11 changes: 11 additions & 0 deletions i18n/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id("com.android.library")
id("kotlin-android")
}

android {
compileSdk = Apps.compileSdk
defaultConfig {
minSdk = Apps.minSdk
}
}
Empty file added i18n/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions i18n/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions i18n/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="org.zxconnect.android.beserve.i18n">

</manifest>
37 changes: 37 additions & 0 deletions i18n/src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
@@ -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>
7 changes: 7 additions & 0 deletions i18n/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -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>
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ dependencyResolutionManagement {
}
rootProject.name = "android-study-case"
include(":app")
include(":util")
include(":i18n")
1 change: 1 addition & 0 deletions util/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
48 changes: 48 additions & 0 deletions util/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -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)
}
Empty file added util/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions util/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions util/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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
40 changes: 40 additions & 0 deletions util/src/main/java/org/zxconnect/android/beserve/util/Event.kt
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
40 changes: 40 additions & 0 deletions util/src/main/java/org/zxconnect/android/beserve/util/Result.kt
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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>>
}
Loading

0 comments on commit 15cb292

Please sign in to comment.