18 |
19 | companion object {
20 | @SuppressLint("StaticFieldLeak")
21 | var context: Context? = null
22 | }
23 |
24 | override fun onCreate() {
25 | super.onCreate()
26 | startKoin {
27 | androidContext(applicationContext)
28 | modules(modules.toList())
29 | androidLogger(Level.INFO)
30 | }
31 | ApplicationContext.set(applicationContext)
32 | }
33 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/pattern/navigation/BaseNavigation.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.pattern.navigation
5 |
6 | interface BaseNavigation {
7 | fun goBack()
8 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/pattern/navigation/Portal.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha + Joseph Sanjaya.
3 | */
4 | package com.singularity_code.core.common.pattern.navigation
5 |
6 | interface Portal
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/pattern/navigation/Space.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha + Joseph Sanjaya.
3 | */
4 | package com.singularity_code.core.common.pattern.navigation
5 |
6 | import androidx.activity.result.contract.ActivityResultContract
7 |
8 | interface Space {
9 | fun getLauncher(): ActivityResultContract
10 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/pattern/navigation/SpaceStation.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.pattern.navigation
5 |
6 | interface SpaceStation
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/pattern/viewmodel/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.pattern.viewmodel
5 |
6 | import arrow.core.Either
7 | import com.singularity_code.core.common.pattern.ClearAble
8 | import com.singularity_code.core.common.pattern.Payload
9 | import com.singularity_code.core.common.model.VmError
10 |
11 | interface BaseViewModel : ClearAble {
12 | fun
createState(
13 | block: suspend (payload: P) -> Either
14 | ): BaseViewModelAbs.State
15 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/pattern/viewmodel/BaseViewModelAbs.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.pattern.viewmodel
5 |
6 | import android.util.Log
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.runtime.collectAsState
9 | import androidx.lifecycle.ViewModel
10 | import androidx.lifecycle.viewModelScope
11 | import arrow.core.Either
12 | import com.singularity_code.core.common.pattern.Payload
13 | import com.singularity_code.core.common.util.viewmodel.Default
14 | import com.singularity_code.core.common.util.viewmodel.Failed
15 | import com.singularity_code.core.common.util.viewmodel.Loading
16 | import com.singularity_code.core.common.util.viewmodel.Success
17 | import com.singularity_code.core.common.model.VmError
18 | import com.singularity_code.core.common.util.viewmodel.RequestState
19 | import kotlinx.coroutines.*
20 | import kotlinx.coroutines.flow.MutableStateFlow
21 | import kotlin.coroutines.CoroutineContext
22 |
23 | abstract class BaseViewModelAbs : ViewModel(), BaseViewModel {
24 |
25 | abstract inner class State :
26 | com.singularity_code.core.common.pattern.State {
27 | private val state = MutableStateFlow>(Default())
28 | private var job: Job? = null
29 |
30 | private val streamSuperVisor = SupervisorJob()
31 | private val handler: (onError: ((c: CoroutineContext, e: Throwable) -> Unit)?) -> CoroutineExceptionHandler =
32 | {
33 | CoroutineExceptionHandler { coroutineContext, throwable ->
34 | it?.invoke(coroutineContext, throwable)
35 | ?: run {
36 | Log.e(
37 | "${coroutineContext::class.simpleName}",
38 | "launchJob: ${throwable.localizedMessage}"
39 | )
40 | }
41 | }
42 | }
43 |
44 | private val streamScope = CoroutineScope(
45 | streamSuperVisor
46 | + Dispatchers.IO
47 | + handler { c, e ->
48 | state.value = Failed(
49 | VmError(
50 | message = e.message.toString(),
51 | code = 0
52 | )
53 | )
54 | })
55 |
56 | @Composable
57 | override fun collectAsState() = state.collectAsState()
58 |
59 | /**
60 | * warning: this function trigger recomposition
61 | */
62 | @Composable
63 | override fun value() = collectAsState().value
64 |
65 | override fun requestUpdate(payload: P) {
66 | state.value = Loading()
67 | job?.cancel()
68 | job = viewModelScope.launch(
69 | streamSuperVisor +
70 | Dispatchers.IO +
71 | handler { c, e ->
72 | state.value = Failed(
73 | VmError(
74 | message = e.message.toString(),
75 | code = 0
76 | )
77 | )
78 | }
79 | ) {
80 | state.value = operator(payload).fold(
81 | ifLeft = { Failed(it) },
82 | ifRight = { Success(it) }
83 | )
84 | }
85 | }
86 |
87 | @Deprecated("Semantic correction. Soon be deleted.", ReplaceWith("requestUpdate(payload)"))
88 | override fun request(payload: P) {
89 | requestUpdate(payload)
90 | }
91 |
92 | override fun resetClear() {
93 | job?.cancel()
94 | state.value = Default()
95 | }
96 |
97 | /**
98 | * Operator will handle state update request
99 | * @param payload : Payload.
100 | */
101 | abstract override val operator: suspend (payload: P) -> Either
102 | }
103 |
104 | override fun createState(
105 | block: suspend (payload: P) -> Either
106 | ): State {
107 | return object : State() {
108 | override val operator: suspend (payload: P) -> Either
109 | get() = { block.invoke(it) }
110 | }
111 | }
112 |
113 | abstract override fun clear()
114 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Aliases.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | typealias StringJson = String
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Apollo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.common.util
6 |
7 | import arrow.core.Either
8 | import com.apollographql.apollo3.ApolloCall
9 | import com.apollographql.apollo3.api.Operation
10 | import com.singularity_code.core.common.model.VmError
11 |
12 |
13 | suspend fun ApolloCall.getOrError()
14 | : Either {
15 |
16 | val response = this.execute()
17 |
18 | return when (val data = response.data) {
19 | null -> Either.Left(
20 | VmError(
21 | code = null,
22 | message = response.errors
23 | ?.toString() ?: "Data null"
24 | )
25 | )
26 | else -> Either.Right(
27 | data
28 | )
29 | }
30 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.common.util
6 |
7 | import arrow.core.Either
8 | import com.singularity_code.core.common.pattern.Payload
9 | import com.singularity_code.core.common.pattern.viewmodel.BaseViewModelAbs
10 | import com.singularity_code.core.common.model.VmError
11 |
12 | @Deprecated(
13 | "Semantic correction. Soon be deleted",
14 | ReplaceWith("createStateHolder(operator)")
15 | )
16 | fun BaseViewModelAbs.stateCreator(
17 | operator: suspend (P) -> Either
18 | ): BaseViewModelAbs.State {
19 | return createStateHolder(operator)
20 | }
21 |
22 | fun BaseViewModelAbs.createStateHolder(
23 | updateOperator: suspend (P) -> Either
24 | ): BaseViewModelAbs.State = object : BaseViewModelAbs.State() {
25 | override val operator = updateOperator
26 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Coroutine.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | import kotlinx.coroutines.CoroutineScope
7 | import kotlinx.coroutines.Dispatchers
8 | import kotlinx.coroutines.launch
9 |
10 | fun LaunchInIO(block: suspend CoroutineScope.() -> Unit) {
11 | CoroutineScope(Dispatchers.IO).launch { block.invoke(this) }
12 | }
13 |
14 | fun LaunchInMain(block: suspend CoroutineScope.() -> Unit) {
15 | CoroutineScope(Dispatchers.Main).launch { block.invoke(this) }
16 | }
17 |
18 | fun LaunchInDefault(block: suspend CoroutineScope.() -> Unit) {
19 | CoroutineScope(Dispatchers.Default).launch { block.invoke(this) }
20 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Date.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | import java.text.SimpleDateFormat
7 | import java.time.Instant
8 | import java.time.LocalDateTime
9 | import java.time.ZoneId
10 | import java.util.*
11 |
12 | fun String.toDateFormat(): String? {
13 | val formatted = SimpleDateFormat("dd/MM/yyyy")
14 | return this.isoFormatToDate()?.let {
15 | formatted.format(it)
16 | }
17 | }
18 |
19 | fun String.toTimeFormat(): String? {
20 | val formatted = SimpleDateFormat("HH.mm")
21 | return this.isoFormatToDate()?.let {
22 | formatted.format(it)
23 | }
24 | }
25 |
26 | fun String.isoFormatToDate(): Date? {
27 | val converted = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
28 | return if (this.isNotEmpty()) converted.parse(this) else Date()
29 | }
30 |
31 | fun Long.toInstant(): Instant {
32 | return Instant.ofEpochMilli(this)
33 | }
34 |
35 | fun Long.toLocalDateTime(): LocalDateTime {
36 | return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault())
37 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Json.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.common.util
2 |
3 | import com.google.gson.Gson
4 | import com.google.gson.GsonBuilder
5 | import com.singularity_code.core.common.pattern.JsonConvertible
6 |
7 |
8 | inline fun String.toObject(): T = Gson().fromJson(this, T::class.java)
9 |
10 | fun String.toObject(type: Class): T {
11 | val gson = GsonBuilder().create()
12 | return gson.fromJson(this, type)
13 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Launcher.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | import android.content.Context
7 | import android.content.Intent
8 | import androidx.activity.result.ActivityResultCallback
9 | import androidx.activity.result.ActivityResultLauncher
10 | import com.singularity_code.core.common.pattern.Payload
11 | import com.singularity_code.core.common.pattern.activity.LauncherAbs
12 | import com.singularity_code.core.common.pattern.JsonConvertible
13 | import com.singularity_code.core.common.pattern.activity.BaseActivityAbs
14 | import com.singularity_code.core.common.pattern.navigation.Space
15 |
16 | fun createLauncher(
17 | activity: Class<*>,
18 | outputType: Class
19 | ): LauncherAbs {
20 | return object : LauncherAbs
() {
21 | override val intent: (c: Context) -> Intent
22 | get() = { c -> Intent(c, activity) }
23 | override val outputType: Class
24 | get() = outputType
25 | }
26 | }
27 |
28 | fun BaseActivityAbs.createLauncher(
29 | space: Space
,
30 | callback: ActivityResultCallback
31 | ): ActivityResultLauncher {
32 | return registerForActivityResult(space.getLauncher(), callback)
33 | }
34 |
35 | /**
36 | * @param S for Space
37 | * @param P for Payload
38 | * @param R for Result
39 | */
40 | class Launcher, P : Payload, R>(
41 | private val space: S,
42 | private val activity: BaseActivityAbs
43 | ) {
44 | /**
45 | * Override this value for callback action
46 | */
47 | var resultCallback: ((R) -> Unit)? = null
48 |
49 | private val launcher = activity.createLauncher(space) {
50 | if (it != null)
51 | resultCallback?.invoke(it)
52 | }
53 |
54 | fun launch(
55 | payload: P
56 | ) {
57 | launcher.launch(payload)
58 | }
59 | }
60 |
61 | /**
62 | * @param S for Space
63 | * @param P for Payload
64 | * @param R for Result
65 | * @param space for Space
66 | */
67 | fun , P : Payload, R> BaseActivityAbs.launcher(
68 | space: S
69 | ) = Launcher(
70 | space = space,
71 | activity = this
72 | )
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/List.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | fun List?.refineList() =
7 | this?.filterNotNull() ?: listOf()
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Log.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | import android.util.Log
7 |
8 | fun Any.logDebug(msg: String) {
9 | Log.d(this.javaClass.simpleName, msg)
10 | }
11 |
12 | fun logDebug(msg: String) {
13 | Log.d("NOWHERE", msg)
14 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Long.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | fun Long.toTimeFormatted(
7 | showHour: Boolean = true,
8 | showMinute: Boolean = true,
9 | showSecond: Boolean = true
10 | ): String {
11 | var s = this / 1000
12 | val h = s / 3600
13 | s -= (h * 3600)
14 | val m = s / 60
15 | s -= (m * 60)
16 |
17 | return with(StringBuilder()) {
18 |
19 | if (showHour) {
20 | if (h < 10) {
21 | append("0")
22 | }
23 | append(h)
24 | }
25 |
26 | if (showMinute) {
27 | if (showHour) {
28 | append(":")
29 | }
30 |
31 | if (m < 10) {
32 | append("0")
33 | }
34 | append(m)
35 | }
36 |
37 | if (showSecond) {
38 | if (showHour || showMinute) {
39 | append(":")
40 | }
41 |
42 | if (s < 10) {
43 | append("0")
44 | }
45 | append(s)
46 | }
47 |
48 | toString()
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Null.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | fun withNotNull(entity: T?, block: (T) -> Unit) {
7 | entity?.apply {
8 | block.invoke(this)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Readme.md:
--------------------------------------------------------------------------------
1 | Util should only contain functions.
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/State.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.common.util
6 |
7 | import androidx.compose.runtime.Composable
8 | import com.singularity_code.core.common.model.VmError
9 | import com.singularity_code.core.common.pattern.State
10 | import com.singularity_code.core.common.util.viewmodel.Default
11 | import com.singularity_code.core.common.util.viewmodel.Failed
12 | import com.singularity_code.core.common.util.viewmodel.Loading
13 | import com.singularity_code.core.common.util.viewmodel.Success
14 |
15 | /**
16 | * Be careful this function trigger recomposition.
17 | * Use this if you only need to handle a state one time only.
18 | * This function wil map state value to given response type.
19 | */
20 |
21 | @Deprecated("Warning: this method arguments is not yet immutable arguments, so becareful when using it.")
22 | @Composable
23 | fun State.mapState(
24 | default: () -> R,
25 | loading: () -> R,
26 | failed: (e: VmError) -> R,
27 | success: (d: T) -> R
28 | ): R {
29 | return when (val v = value()) {
30 | is Default -> default.invoke()
31 | is Failed -> failed.invoke(v.e)
32 | is Loading -> loading.invoke()
33 | is Success -> success.invoke(v.value)
34 | }
35 | }
36 |
37 | /**
38 | * Be careful this function trigger recomposition.
39 | * Use this if you only need to handle a state one time only.
40 | * This function will handle each state by emitting a composable function.
41 | */
42 | @Composable
43 | fun State.onState(
44 | default: @Composable () -> Unit,
45 | loading: @Composable () -> Unit,
46 | failed: @Composable (e: VmError) -> Unit,
47 | success: @Composable (d: T) -> Unit,
48 | ) {
49 | return when (val v = value()) {
50 | is Default -> default()
51 | is Failed -> failed(v.e)
52 | is Loading -> loading()
53 | is Success -> success(v.value)
54 | }
55 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/Toast.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | import android.widget.Toast.makeText
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.platform.LocalContext
9 | import com.singularity_code.core.common.model.Toast
10 |
11 | @Composable
12 | fun MakeToast(payload: Toast) = makeText(
13 | LocalContext.current.applicationContext,
14 | payload.message,
15 | if (payload.longToast)
16 | android.widget.Toast.LENGTH_LONG
17 | else android.widget.Toast.LENGTH_SHORT
18 | ).show()
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/application/ApplicationContext.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util.application
5 |
6 | import android.annotation.SuppressLint
7 | import android.content.Context
8 |
9 | @SuppressLint("StaticFieldLeak")
10 | object ApplicationContext {
11 | private var context: Context? = null
12 | fun set(context: Context) {
13 | ApplicationContext.context = context
14 | }
15 |
16 | fun get(): Context {
17 | return context!!
18 | }
19 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/injection/Koin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | import org.koin.core.component.KoinComponent
7 | import org.koin.core.component.inject
8 |
9 | inline fun get(): T {
10 | val koinObj = object : KoinComponent {
11 | val instance: T by inject()
12 | }
13 | return koinObj.instance
14 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/network/RetrofitUtil.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util
5 |
6 | import androidx.annotation.NonNull
7 | import arrow.retrofit.adapter.either.EitherCallAdapterFactory
8 | import okhttp3.OkHttpClient
9 | import retrofit2.Retrofit
10 | import retrofit2.converter.gson.GsonConverterFactory
11 |
12 | /**
13 | * Create retrofit service
14 | * @author stefanus.ayudha@gmail.com
15 | * @param I Retrofit interface
16 | * @param service Class of the given Retrofit interface
17 | * @param httpClient OkHttp client, if you are using my codebase all u need is injecting it by parsing get() as it's param in koin module injection configuration, once you inject the core modules configuration to the Application
18 | * @param baseUrl Base Url of the web api
19 | * @return Retrofit service of the given interface
20 | */
21 | fun createRetrofitService(
22 | @NonNull service: Class,
23 | httpClient: OkHttpClient,
24 | baseUrl: String,
25 | ): I = Retrofit.Builder()
26 | .client(httpClient)
27 | .baseUrl(baseUrl)
28 | .addCallAdapterFactory(EitherCallAdapterFactory())
29 | .addConverterFactory(GsonConverterFactory.create())
30 | .build()
31 | .create(service)
--------------------------------------------------------------------------------
/core/common/src/main/java/com/singularity_code/core/common/util/viewmodel/RequestState.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 | package com.singularity_code.core.common.util.viewmodel
5 |
6 | import com.singularity_code.core.common.model.VmError
7 |
8 | sealed class RequestState
9 | class Default : RequestState()
10 | class Loading : RequestState()
11 | class Success(var value: T) : RequestState()
12 | class Failed(val e: VmError) : RequestState()
--------------------------------------------------------------------------------
/core/common/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Singularity Software
3 |
--------------------------------------------------------------------------------
/core/common/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/core/common/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/core/common/src/test/java/com/singularity_code/core/common/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.common
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/core/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/consumer-rules.pro
--------------------------------------------------------------------------------
/core/network/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /.cxx/
3 |
--------------------------------------------------------------------------------
/core/network/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2021 Designed and developed by Joseph Sanjaya, S.T., M.Kom., All
2 | # Rights Reserved.
3 | # @Github (https://github.com/JosephSanjaya),
4 | # @LinkedIn (https://www.linkedin.com/in/josephsanjaya/))
5 |
6 | # For more information about using CMake with Android Studio, read the
7 | # documentation: https://d.android.com/studio/projects/add-native-code.html
8 |
9 | # Sets the minimum version of CMake required to build the native library.
10 |
11 | cmake_minimum_required(VERSION 3.4.1)
12 |
13 | # Creates and names a library, sets it as either STATIC
14 | # or SHARED, and provides the relative paths to its source code.
15 | # You can define multiple libraries, and CMake builds them for you.
16 | # Gradle automatically packages shared libraries with your APK.
17 |
18 | add_library( # Sets the name of the library.
19 | dev-url
20 |
21 | # Sets the library as a shared library.
22 | SHARED
23 |
24 | # Provides a relative path to your source file(s).
25 | src/main/cpp/dev-url.cpp)
26 |
27 | add_library( # Sets the name of the library.
28 | stage-url
29 |
30 | # Sets the library as a shared library.
31 | SHARED
32 |
33 | # Provides a relative path to your source file(s).
34 | src/main/cpp/stage-url.cpp)
35 |
36 | add_library( # Sets the name of the library.
37 | prod-url
38 |
39 | # Sets the library as a shared library.
40 | SHARED
41 |
42 | # Provides a relative path to your source file(s).
43 | src/main/cpp/prod-url.cpp)
44 |
45 | # Searches for a specified prebuilt library and stores the path as a
46 | # variable. Because CMake includes system libraries in the search path by
47 | # default, you only need to specify the name of the public NDK library
48 | # you want to add. CMake verifies that the library exists before
49 | # completing its build.
50 |
51 | find_library( # Sets the name of the path variable.
52 | log-lib
53 |
54 | # Specifies the name of the NDK library that
55 | # you want CMake to locate.
56 | log)
57 |
58 | # Specifies libraries CMake should link to your target library. You
59 | # can link multiple libraries, such as libraries you define in this
60 | # build script, prebuilt third-party libraries, or system libraries.
61 |
62 | target_link_libraries( # Specifies the target library.
63 | dev-url
64 |
65 | # Links the target library to the log library
66 | # included in the NDK.
67 | ${log-lib})
68 | target_link_libraries( # Specifies the target library.
69 | stage-url
70 |
71 | # Links the target library to the log library
72 | # included in the NDK.
73 | ${log-lib})
74 | target_link_libraries( # Specifies the target library.
75 | prod-url
76 |
77 | # Links the target library to the log library
78 | # included in the NDK.
79 | ${log-lib})
--------------------------------------------------------------------------------
/core/network/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.apollographql.apollo3").version("3.1.0")
3 | }
4 |
5 | android {
6 | externalNativeBuild {
7 | cmake {
8 | path("CMakeLists.txt")
9 | }
10 | }
11 | }
12 |
13 | dependencies {
14 | api(project(":core:common"))
15 | }
16 |
17 | apollo {
18 | packageName.set("com.singularity_code.core.network")
19 | }
--------------------------------------------------------------------------------
/core/network/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/network/consumer-rules.pro
--------------------------------------------------------------------------------
/core/network/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/core/network/src/androidTest/java/com/singularity_code/core/network/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.network
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.singularity_code.core.network.test", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/core/network/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/network/src/main/cpp/dev-url.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Stefanus Ayudha on 18/04/2022.
3 | // email: stefanus.ayudha@gmail.com
4 | //
5 |
6 | #include
7 | #include
8 |
9 | extern "C"
10 | JNIEXPORT jstring JNICALL
11 | Java_com_singularity_1code_core_network_util_SecuredDev_getBaseUrl(JNIEnv *env, jobject thiz) {
12 | return env->NewStringUTF("https://jsonplaceholder.typicode.com/");
13 | }
14 | extern "C"
15 | JNIEXPORT jstring JNICALL
16 | Java_com_singularity_1code_core_network_util_SecuredDev_getBasePokemonUrl(JNIEnv *env, jobject thiz) {
17 | return env->NewStringUTF("https://beta.pokeapi.co/graphql/v1beta");
18 | }
--------------------------------------------------------------------------------
/core/network/src/main/cpp/prod-url.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Stefanus Ayudha on 18/04/2022.
3 | // email: stefanus.ayudha@gmail.com
4 | //
5 |
6 | #include
7 | #include
8 |
9 | extern "C"
10 | JNIEXPORT jstring JNICALL
11 | Java_com_singularity_1code_core_network_util_SecuredProd_getBaseUrl(JNIEnv *env, jobject thiz) {
12 | return env->NewStringUTF("https://jsonplaceholsssssder.typicode.com/");
13 | }
14 | extern "C"
15 | JNIEXPORT jstring JNICALL
16 | Java_com_singularity_1code_core_network_util_SecuredProd_getBasePokemonUrl(JNIEnv *env,
17 | jobject thiz) {
18 | return env->NewStringUTF("https://beta.pokeapi.co/graphql/v1beta");
19 | }
--------------------------------------------------------------------------------
/core/network/src/main/cpp/stage-url.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Stefanus Ayudha on 18/04/2022.
3 | // email: stefanus.ayudha@gmail.com
4 | //
5 |
6 | #include
7 | #include
8 |
9 | extern "C"
10 | JNIEXPORT jstring JNICALL
11 | Java_com_singularity_1code_core_network_util_SecuredStaging_getBaseUrl(JNIEnv *env, jobject thiz) {
12 | return env->NewStringUTF("https://jsonplaceholder.typicode.com/");
13 | }
14 | extern "C"
15 | JNIEXPORT jstring JNICALL
16 | Java_com_singularity_1code_core_network_util_SecuredStaging_getBasePokemonUrl(JNIEnv *env,
17 | jobject thiz) {
18 | return env->NewStringUTF("https://beta.pokeapi.co/graphql/v1beta");
19 | }
--------------------------------------------------------------------------------
/core/network/src/main/graphql/GetPokemonById.graphql:
--------------------------------------------------------------------------------
1 | query GetPokemonById(
2 | $id: Int!
3 | ) {
4 | pokemon_v2_pokemon(
5 | where: {
6 | id: {
7 | _eq: $id
8 | }
9 | }
10 | ) {
11 | id
12 | name
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/core/network/src/main/graphql/GetPokemonList.graphql:
--------------------------------------------------------------------------------
1 | query GetPokemonList(
2 | $limit: Int!,
3 | $offset: Int!
4 | ) {
5 | pokemon_v2_pokemon(
6 | limit: $limit,
7 | offset: $offset
8 | ) {
9 | id
10 | name
11 | }
12 | }
--------------------------------------------------------------------------------
/core/network/src/main/java/com/singularity_code/core/network/DI.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.network
6 |
7 | import org.koin.core.module.Module
8 |
9 | val coreNetworkModules = arrayOf()
--------------------------------------------------------------------------------
/core/network/src/main/java/com/singularity_code/core/network/data/Secured.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.network.data
6 |
7 | // use to store base URL securely by android NDK
8 | interface SecuredUseCase {
9 | fun getBaseUrl(): String
10 | fun getBasePokemonUrl(): String
11 | }
--------------------------------------------------------------------------------
/core/network/src/main/java/com/singularity_code/core/network/util/Apollo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.network.util
6 |
7 | import com.apollographql.apollo3.ApolloClient
8 | import com.apollographql.apollo3.network.okHttpClient
9 |
10 | fun apolloClient(
11 | url: String
12 | ): ApolloClient =
13 | ApolloClient.Builder()
14 | .serverUrl(url)
15 | .okHttpClient(
16 | defaultOkhttp()
17 | )
18 | .build()
--------------------------------------------------------------------------------
/core/network/src/main/java/com/singularity_code/core/network/util/Okhttp.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.network.util
6 |
7 | import com.iddevops.core.network.BuildConfig.BUILD_TYPE
8 | import com.singularity_code.core.network.util.interceptor.chuckerInterceptor
9 | import okhttp3.OkHttpClient
10 |
11 | fun defaultOkhttp() = OkHttpClient.Builder()
12 | .apply {
13 | if (BUILD_TYPE != "release")
14 | addInterceptor(chuckerInterceptor)
15 | }
16 | .build()
--------------------------------------------------------------------------------
/core/network/src/main/java/com/singularity_code/core/network/util/Secured.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.network.util
2 |
3 | import com.iddevops.core.network.BuildConfig
4 | import com.singularity_code.core.network.data.SecuredUseCase
5 |
6 |
7 | object SecuredDev : SecuredUseCase {
8 | init {
9 | System.loadLibrary("dev-url")
10 | }
11 |
12 | external override fun getBaseUrl(): String
13 | external override fun getBasePokemonUrl(): String
14 | }
15 |
16 | object SecuredStaging: SecuredUseCase {
17 | init {
18 | System.loadLibrary("stage-url")
19 | }
20 |
21 | external override fun getBaseUrl(): String
22 | external override fun getBasePokemonUrl(): String
23 | }
24 |
25 | object SecuredProd: SecuredUseCase {
26 | init {
27 | System.loadLibrary("prod-url")
28 | }
29 |
30 | external override fun getBaseUrl(): String
31 | external override fun getBasePokemonUrl(): String
32 | }
33 |
34 | val Secured: SecuredUseCase by lazy {
35 | when (BuildConfig.BUILD_TYPE) {
36 | "debug" -> SecuredDev
37 | "staging" -> SecuredStaging
38 | else -> SecuredProd
39 | }
40 | }
--------------------------------------------------------------------------------
/core/network/src/main/java/com/singularity_code/core/network/util/interceptor/ChuckerInterceptor.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.network.util.interceptor
6 |
7 | import com.chuckerteam.chucker.api.ChuckerCollector
8 | import com.chuckerteam.chucker.api.ChuckerInterceptor
9 | import com.chuckerteam.chucker.api.RetentionManager
10 | import com.singularity_code.core.common.util.application.ApplicationContext
11 |
12 | val chuckerCollector by lazy {
13 | ChuckerCollector(
14 | context = ApplicationContext.get(),
15 | // Toggles visibility of the notification
16 | showNotification = true,
17 | // Allows to customize the retention period of collected data
18 | retentionPeriod = RetentionManager.Period.ONE_HOUR
19 | )
20 | }
21 |
22 | val chuckerInterceptor by lazy {
23 | ChuckerInterceptor.Builder(context = ApplicationContext.get())
24 | // The previously created Collector
25 | .collector(chuckerCollector)
26 | // The max body content length in bytes, after this responses will be truncated.
27 | .maxContentLength(250_000L)
28 | // List of headers to replace with ** in the Chucker UI
29 | // .redactHeaders("Auth-Token", "Bearer")
30 | // Read the whole response body even when the client does not consume the response completely.
31 | // This is useful in case of parsing errors or when the response body
32 | // is closed before being read like in Retrofit with Void and Unit types.
33 | .alwaysReadResponseBody(true)
34 | // Use decoder when processing request and response bodies. When multiple decoders are installed they
35 | // are applied in an order they were added.
36 | // .addBodyDecoder(decoder)
37 | // Controls Android shortcut creation. Available in SNAPSHOTS versions only at the moment
38 | // .createShortcut(true)
39 | .build()
40 | }
--------------------------------------------------------------------------------
/core/network/src/test/java/com/singularity_code/core/network/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.network
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/core/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/ui/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/ui/build.gradle.kts:
--------------------------------------------------------------------------------
1 | android {
2 | kotlinOptions {
3 | jvmTarget = "1.8"
4 | }
5 | buildFeatures {
6 | compose = true
7 | }
8 | composeOptions {
9 | kotlinCompilerExtensionVersion = "1.1.1"
10 | }
11 | }
12 |
13 | dependencies {
14 | api(project(":core:common"))
15 | }
--------------------------------------------------------------------------------
/core/ui/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/consumer-rules.pro
--------------------------------------------------------------------------------
/core/ui/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/core/ui/src/androidTest/java/com/singularity_code/core/ui/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.singularity_code.core.ui.test", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/core/ui/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/DI.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022. Stefanus Ayudha.
3 | */
4 |
5 | package com.singularity_code.core.ui
6 |
7 | import org.koin.core.module.Module
8 |
9 | val coreUIModules = arrayOf()
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/util/ContentThemeWrapper.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui.theme
2 |
3 | import androidx.compose.foundation.isSystemInDarkTheme
4 | import androidx.compose.material3.MaterialTheme
5 | import androidx.compose.material3.Surface
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import com.singularity_code.core.ui.util.material3.BaseComposeTheme
9 |
10 | @Composable
11 | fun ContentThemeWrapper(
12 | modifier: Modifier = Modifier,
13 | forceDark: Boolean = isSystemInDarkTheme(),
14 | content: @Composable () -> Unit
15 | ) {
16 | BaseComposeTheme(
17 | darkTheme = forceDark
18 | ) {
19 | // A surface container using the 'background' color from the theme
20 | Surface(
21 | modifier = modifier,
22 | color = MaterialTheme.colorScheme.background,
23 | content = content
24 | )
25 | }
26 | }
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/util/Dimen.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui.util
2 |
3 | import androidx.compose.ui.unit.Dp
4 | import androidx.compose.ui.unit.TextUnit
5 | import androidx.compose.ui.unit.dp
6 | import androidx.compose.ui.unit.sp
7 |
8 | object ScreenSpec {
9 | var scale = 1f
10 | var isTablet = false
11 | }
12 |
13 | /**
14 | * In case you wanted to scale the "dp" and "sp" unit to fit your screen.
15 | * Example case: sometime the design system is build for a specific kind of devices like tablet.
16 | * Most of the time, the component sizes, text elements and others custom elements won't fit in.
17 | *
18 | * Notes: use "toDp" and "toSp" instead of built in "dp" and "sp",
19 | * these extensions designed to scale respect to ScreenSpec configuration.
20 | */
21 | fun setupScreenSize(scaleScreen: Float = 1f) {
22 | ScreenSpec.scale = scaleScreen
23 | ScreenSpec.isTablet = false
24 | }
25 |
26 | /**
27 | * these extensions design to automatically scale it self, respect to
28 | * ScreenSpec configuration.
29 | * @see com.singularity_code.core.ui.ScreenSpec
30 | */
31 | val Int.toDp: Dp
32 | get() = if (ScreenSpec.isTablet) this.dp * ScreenSpec.scale else this.dp
33 |
34 | /**
35 | * these extensions design to automatically scale it self, respect to
36 | * ScreenSpec configuration.
37 | * @see com.singularity_code.core.ui.ScreenSpec
38 | */
39 | val Int.toSp: TextUnit
40 | get() = if (ScreenSpec.isTablet) this.sp * ScreenSpec.scale else this.sp
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/util/material3/Color.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui.util.material3
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val SafetyOrange00 = Color(0xFF000000)
6 | val SafetyOrange10 = Color(0xFF331600)
7 | val SafetyOrange20 = Color(0xFF662c00)
8 | val SafetyOrange30 = Color(0xFF994200)
9 | val SafetyOrange40 = Color(0xFFcc5800)
10 | val SafetyOrange50 = Color(0xFFff6e00)
11 | val SafetyOrange60 = Color(0xFFff8b33)
12 | val SafetyOrange70 = Color(0xFFffa866)
13 | val SafetyOrange80 = Color(0xFFffc599)
14 | val SafetyOrange90 = Color(0xFFffe2cc)
15 | val SafetyOrange100 = Color(0xFFFFFFFF)
16 |
17 | val DodgerBlue00 = Color(0xFF000000)
18 | val DodgerBlue10 = Color(0xFF001d33)
19 | val DodgerBlue20 = Color(0xFF003a66)
20 | val DodgerBlue30 = Color(0xFF005799)
21 | val DodgerBlue40 = Color(0xFF0074cc)
22 | val DodgerBlue50 = Color(0xFF0091ff)
23 | val DodgerBlue60 = Color(0xFF33a7ff)
24 | val DodgerBlue70 = Color(0xFF66bdff)
25 | val DodgerBlue80 = Color(0xFF99d3ff)
26 | val DodgerBlue90 = Color(0xFFcce9ff)
27 | val DodgerBlue100 = Color(0xFFFFFFFF)
28 |
29 | val Neutral00 = Color(0xFF000000)
30 | val Neutral10 = Color(0xFF1a1a1a)
31 | val Neutral20 = Color(0xFF333333)
32 | val Neutral25 = Color(0xFF404040)
33 | val Neutral30 = Color(0xFF4d4d4d)
34 | val Neutral40 = Color(0xFF666666)
35 | val Neutral50 = Color(0xFF808080)
36 | val Neutral60 = Color(0xFF999999)
37 | val Neutral70 = Color(0xFFb2b2b2)
38 | val Neutral80 = Color(0xFFcccccc)
39 | val Neutral90 = Color(0xFFe5e5e5)
40 | val Neutral95 = Color(0xFFf2f2f2)
41 | val Neutral97 = Color(0xFFf7f7f7)
42 | val Neutral98 = Color(0xfffafafa)
43 | val Neutral100 = Color(0xFFFFFFFF)
44 |
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/util/material3/Dimens.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui.util.material3
2 |
3 | import com.singularity_code.core.ui.util.toDp
4 | import com.singularity_code.core.ui.util.toSp
5 |
6 | val dp0 = 0.toDp
7 | val dp1 = 1.toDp
8 | val dp2 = 2.toDp
9 | val dp4 = 4.toDp
10 | val dp8 = 8.toDp
11 | val dp10 = 10.toDp
12 | val dp12 = 12.toDp
13 | val dp16 = 16.toDp
14 | val dp20 = 20.toDp
15 | val dp24 = 24.toDp
16 | val dp28 = 28.toDp
17 | val dp32 = 32.toDp
18 | val dp48 = 48.toDp
19 | val dp52 = 52.toDp
20 | val dp56 = 56.toDp
21 | val dp64 = 64.toDp
22 | val dp72 = 72.toDp
23 | val dp88 = 88.toDp
24 | val dp90 = 90.toDp
25 | val dp100 = 100.toDp
26 | val dp120 = 120.toDp
27 | val dp156 = 156.toDp
28 | val dp200 = 200.toDp
29 | val dp260 = 260.toDp
30 | val dp440 = 440.toDp
31 |
32 | val sp10 = 10.toSp
33 | val sp12 = 12.toSp
34 | val sp13 = 13.toSp
35 | val sp14 = 14.toSp
36 | val sp16 = 16.toSp
37 | val sp18 = 18.toSp
38 | val sp20 = 20.toSp
39 | val sp24 = 24.toSp
40 | val sp26 = 26.toSp
41 | val sp32 = 32.toSp
42 | val sp36 = 36.toSp
43 | val sp52 = 52.toSp
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/util/material3/FontFamily.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui.util.material3
2 |
3 | import androidx.compose.ui.text.font.Font
4 | import androidx.compose.ui.text.font.FontFamily
5 | import androidx.compose.ui.text.font.FontWeight
6 | import com.iddevops.core.ui.R
7 |
8 | val InterLight = FontFamily(
9 | Font(
10 | resId = R.font.inter_regular,
11 | weight = FontWeight(300)
12 | )
13 | )
14 |
15 | val InterRegular = FontFamily(
16 | Font(
17 | resId = R.font.inter_regular,
18 | weight = FontWeight(400)
19 | )
20 | )
21 |
22 | val InterMedium = FontFamily(
23 | Font(
24 | resId = R.font.inter_regular,
25 | weight = FontWeight(500)
26 | )
27 | )
28 |
29 | val InterSemiBold = FontFamily(
30 | Font(
31 | resId = R.font.inter_regular,
32 | weight = FontWeight(600)
33 | )
34 | )
35 |
36 | val InterBold = FontFamily(
37 | Font(
38 | resId = R.font.inter_regular,
39 | weight = FontWeight(700)
40 | )
41 | )
42 |
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/util/material3/Shape.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui.util.material3
2 |
3 | import androidx.compose.foundation.shape.RoundedCornerShape
4 |
5 | val rounded4 = RoundedCornerShape(dp4)
6 | val rounded8 = RoundedCornerShape(dp8)
7 | val rounded16 = RoundedCornerShape(dp16)
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/util/material3/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui.util.material3
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.os.Build
6 | import androidx.compose.foundation.isSystemInDarkTheme
7 | import androidx.compose.material3.*
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.SideEffect
10 | import androidx.compose.ui.graphics.toArgb
11 | import androidx.compose.ui.platform.LocalContext
12 | import androidx.compose.ui.platform.LocalView
13 | import androidx.core.view.ViewCompat
14 |
15 | private val LightColorScheme = lightColorScheme(
16 | primary = SafetyOrange50,
17 | onPrimary = Neutral98,
18 | secondary = DodgerBlue50,
19 | onSecondary = Neutral10,
20 | background = Neutral98,
21 | onBackground = Neutral10,
22 | surface = Neutral95,
23 | onSurface = Neutral10,
24 | surfaceVariant = Neutral90,
25 | onSurfaceVariant = Neutral10
26 | )
27 |
28 | private val DarkColorScheme = darkColorScheme(
29 | primary = SafetyOrange50,
30 | onPrimary = Neutral10,
31 | secondary = DodgerBlue50,
32 | onSecondary = Neutral10,
33 | background = Neutral10,
34 | onBackground = Neutral90,
35 | surface = Neutral20,
36 | onSurface = Neutral90,
37 | surfaceVariant = Neutral25,
38 | onSurfaceVariant = Neutral90
39 | )
40 |
41 | @Composable
42 | fun BaseComposeTheme(
43 | darkTheme: Boolean = isSystemInDarkTheme(),
44 | // Dynamic color is available on Android 12+
45 | dynamicColor: Boolean = true,
46 | content: @Composable () -> Unit
47 | ) {
48 | val colorScheme = when {
49 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
50 | val context = LocalContext.current
51 | if (darkTheme)
52 | // DarkColorScheme
53 | dynamicDarkColorScheme(context)
54 | else
55 | // LightColorScheme
56 | dynamicLightColorScheme(context)
57 | }
58 | darkTheme -> DarkColorScheme
59 | else -> LightColorScheme
60 | }
61 | val view = LocalView.current
62 | if (!view.isInEditMode) {
63 | SideEffect {
64 | (view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb()
65 | ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme
66 | }
67 | }
68 |
69 | MaterialTheme(
70 | colorScheme = colorScheme,
71 | typography = Typography,
72 | content = content
73 | )
74 | }
--------------------------------------------------------------------------------
/core/ui/src/main/java/com/singularity_code/core/ui/util/material3/Type.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui.util.material3
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.text.style.TextDecoration
8 | import androidx.compose.ui.unit.sp
9 |
10 | // Set of Material typography styles to start with
11 | val Typography = Typography(
12 | bodyLarge = TextStyle(
13 | fontFamily = FontFamily.Default,
14 | fontWeight = FontWeight.Normal,
15 | fontSize = 16.sp,
16 | lineHeight = 24.sp,
17 | letterSpacing = 0.5.sp
18 | )
19 | )
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ic_singularity_logo.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
17 |
22 |
27 |
32 |
37 |
42 |
47 |
48 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ic_singularity_logo_circle.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
47 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/font/inter_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/font/inter_regular.ttf
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/core/ui/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/core/ui/src/test/java/com/singularity_code/core/ui/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.core.ui
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
24 | android.enableJetifier=true
25 | org.gradle.unsafe.configuration-cache=true
26 | android.experimental.cacheCompileLibResources=true
27 | org.gradle.caching=true
28 | org.gradle.parallel=true
29 | org.gradle.daemon=true
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | ## gradle
3 | gradle-plugin = "7.2.1"
4 | kotlin = "1.6.10"
5 |
6 | ## core
7 | core = "1.8.0"
8 | lifecycle = "2.5.1"
9 | work = "2.7.1"
10 |
11 | ### test
12 | junit = "4.13.2"
13 | test-ext = "1.1.3"
14 | test-espresso = "3.4.0"
15 | testng = "7.6.1"
16 |
17 | ### compose
18 | activity-compose = "1.5.1"
19 | compose = "1.1.1"
20 | compose-material = "1.0.0-alpha15"
21 | compose-navigation = "2.5.1"
22 | #### compose tooling preview is buggy so we wil use android custom view tooling preview
23 | custom-view = "1.2.0-alpha01"
24 | custom-view-pooling-container = "1.0.0"
25 |
26 | ### accompanist animation
27 | accompanist = "0.23.0"
28 |
29 | ## arrow
30 | arrow = "1.1.4-alpha.17"
31 |
32 | ## injection koin
33 | koin = "3.1.5"
34 |
35 | ## retrofit
36 | retrofit = "2.9.0"
37 |
38 | ## apollo
39 | apollo = "3.1.0"
40 |
41 | ## think logic
42 | think-logic = "1.2.1"
43 |
44 | ## armadillo
45 | armadillo = "1.0.0"
46 |
47 | ## gson
48 | gson = "2.9.0"
49 |
50 | ## chucker
51 | chucker = "3.5.2"
52 |
53 | ## coil
54 | coil = "2.2.0"
55 |
56 | ## androidx camera
57 | androidx-camera = "1.1.0"
58 | androidx-camera-view = "1.2.0-beta01"
59 |
60 | ## google
61 | maps = "18.1.0"
62 | play-service = "2.7.0"
63 |
64 | [libraries]
65 | ## core
66 | androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "core" }
67 | androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }
68 | androidx-work-runtime = { module = "androidx.work:work-runtime", version.ref = "work" }
69 |
70 | ### test
71 | junit = { module = "junit:junit", version.ref = "junit" }
72 | testng = { module = "org.testng:testng", version.ref = "testng" }
73 |
74 | ### android test
75 | androidx-test-ext = { module = "androidx.test.ext:junit", version.ref = "test-ext" }
76 | androidx-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "test-espresso" }
77 |
78 | ### compose
79 | activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" }
80 | compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
81 | compose-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
82 | compose-material = { module = "androidx.compose.material3:material3", version.ref = "compose-material" }
83 | compose-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "compose-navigation" }
84 |
85 | #### debug
86 | custom-view-debug = { module = "androidx.customview:customview", version.ref = "custom-view" }
87 | custom-view-debug-pooling-container = { module = "androidx.customview:customview-poolingcontainer", version.ref = "custom-view-pooling-container" }
88 | compose-debug-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
89 | compose-debug-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "compose" }
90 |
91 | #### android test
92 | compose-android-test-junit = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose" }
93 |
94 | ## accompanist animation
95 | accompanist-pager = { module = "com.google.accompanist:accompanist-pager", version.ref = "accompanist" }
96 | accompanist-pager-indicators = { module = "com.google.accompanist:accompanist-pager-indicators", version.ref = "accompanist" }
97 | accompanist-animation-animation = { module = "com.google.accompanist:accompanist-navigation-animation", version.ref = "accompanist" }
98 | accompanist-system-ui-controller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
99 |
100 | ## arrow
101 | arrow-core = { module = "io.arrow-kt:arrow-core", version.ref = "arrow" }
102 | arrow-core-retrofit = { module = "io.arrow-kt:arrow-core-retrofit", version.ref = "arrow" }
103 |
104 | ## injection koin
105 | koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
106 | koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
107 | koin-android-work-manager = { module = "io.insert-koin:koin-androidx-workmanager", version.ref = "koin" }
108 | koin-android-navigation = { module = "io.insert-koin:koin-androidx-navigation", version.ref = "koin" }
109 | koin-android-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" }
110 |
111 | ## retrofit
112 | retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
113 | retrofit-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
114 |
115 | ## apollo
116 | apollo = { module = "com.apollographql.apollo3:apollo-runtime", version.ref = "apollo" }
117 |
118 | ## think logic
119 | think-logic-builder = { module = "com.thinkinglogic.builder:kotlin-builder-annotation", version.ref = "think-logic" }
120 |
121 | ## armadillo
122 | armadillo = { module = "at.favre.lib:armadillo", version.ref = "armadillo" }
123 |
124 | ## gson
125 | gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
126 |
127 | ## chucker
128 | chucker-debug = { module = "com.github.chuckerteam.chucker:library", version.ref = "chucker" }
129 | chucker-release = { module = "com.github.chuckerteam.chucker:library-no-op", version.ref = "chucker" }
130 |
131 | ## coil
132 | coil = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
133 |
134 | ## camera
135 | androidx-camera = { module = "androidx.camera:camera-camera2", version.ref = "androidx-camera" }
136 | androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "androidx-camera" }
137 | androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "androidx-camera-view" }
138 |
139 | ## google
140 | play-service = { module = "com.google.android.gms:play-services-maps", version.ref = "play-service" }
141 |
142 | ### maps
143 | maps = { module = "com.google.maps.android:maps-compose", version.ref = "maps" }
144 |
145 | [bundles]
146 | core = [
147 | "androidx.core.ktx",
148 | "androidx.lifecycle.runtime.ktx",
149 | "androidx.work.runtime"
150 | ]
151 |
152 | core-test = [
153 | "junit",
154 | "testng"
155 | ]
156 |
157 | core-android-test = [
158 | "androidx.test.ext",
159 | "androidx.test.espresso",
160 | ]
161 |
162 | kotlin-arrow = [
163 | "arrow.core",
164 | "arrow.core.retrofit"
165 | ]
166 |
167 | compose = [
168 | "activity.compose",
169 | "compose.ui",
170 | "compose.tooling.preview",
171 | "compose.material",
172 | "compose.navigation"
173 | ]
174 |
175 | compose-test = [
176 |
177 | ]
178 |
179 | compose-android-test = [
180 | "compose.android.test.junit"
181 | ]
182 |
183 | compose-debug = [
184 | "custom.view.debug",
185 | "custom.view.debug.pooling.container",
186 | "compose.debug.ui.tooling",
187 | "compose.debug.ui.test.manifest"
188 | ]
189 |
190 | accompanist = [
191 | "accompanist.pager",
192 | "accompanist.pager.indicators",
193 | "accompanist.animation.animation",
194 | "accompanist.system.ui.controller"
195 | ]
196 |
197 | koin = [
198 | "koin.core",
199 | "koin.android",
200 | "koin.android.work.manager",
201 | "koin.android.navigation",
202 | "koin.android.compose"
203 | ]
204 |
205 | retrofit = [
206 | "retrofit",
207 | "retrofit.converter.gson",
208 | ]
209 |
210 | apollo = [
211 | "apollo"
212 | ]
213 |
214 | builder-kapt = [
215 | "think.logic.builder"
216 | ]
217 |
218 | preference = [
219 | "armadillo"
220 | ]
221 |
222 | serialization = [
223 | "gson"
224 | ]
225 |
226 | chucker-debug = [
227 | "chucker.debug"
228 | ]
229 |
230 | chucker-release = [
231 | "chucker.release"
232 | ]
233 |
234 | image-loader = [
235 | "coil"
236 | ]
237 |
238 | androidx-camera = [
239 | "androidx.camera",
240 | "androidx.camera.lifecycle",
241 | "androidx.camera.view"
242 | ]
243 |
244 | [plugins]
245 | android-application = { id = "com.android.application", version.ref = "gradle-plugin" }
246 | android-library = { id = "com.android.library", version.ref = "gradle-plugin" }
247 | kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
248 | kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
249 | apollo-graph-ql = { id= "com.apollographql.apollo3", version.ref = "apollo" }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Sep 22 17:05:54 WIB 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/keystore.properties.example:
--------------------------------------------------------------------------------
1 | ## remove "example" in this file suffix
2 | ## create a key with value like the followings
3 | ## name your key "testsignature"
4 | ## put your key in root project directory
5 | ## rebuild the project and you are ready
6 |
7 | storePassword=testsignature
8 | keyPassword=testsignature
9 | keyAlias=testsignature
10 | storeFile=../testsignature
11 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat Mar 04 20:22:56 WIB 2023
8 | sdk.dir=/Users/steve/Library/Android/sdk
9 |
--------------------------------------------------------------------------------
/modsample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/modsample/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.BaseExtension
2 | import com.singularity_code.plugins.defaultLibraryConfig
3 | import com.singularity_code.plugins.getKeyStoreProperties
4 |
5 | plugins {
6 | id("java-platform")
7 | }
8 |
9 | group = "android"
10 | version = "1.0.0"
11 |
12 | val keystoreProperties = getKeyStoreProperties(
13 | "${rootDir.absolutePath}/keystore.properties"
14 | )
15 |
16 | subprojects {
17 | apply(plugin = "com.android.library")
18 | apply(plugin = "org.jetbrains.kotlin.android")
19 | apply(plugin = "kotlin-android")
20 | apply(plugin = "kotlin-parcelize")
21 | apply(plugin = "kotlin-kapt")
22 |
23 | plugins.withType(BasePlugin::class.java).configureEach {
24 | configure {
25 | defaultLibraryConfig(
26 | versionCode = 1,
27 | versionName = "1.0",
28 | keystoreProperties = keystoreProperties
29 | )
30 | }
31 | }
32 |
33 | }
34 |
35 | dependencies {
36 | constraints {
37 | api(project(":modsample:pokemon"))
38 | api(project(":modsample:splash"))
39 | api(project(":modsample:todolist"))
40 | api(project(":modsample:mmdexample"))
41 | }
42 | }
--------------------------------------------------------------------------------
/modsample/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/modsample/consumer-rules.pro
--------------------------------------------------------------------------------
/modsample/mmdexample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/modsample/mmdexample/build.gradle.kts:
--------------------------------------------------------------------------------
1 | android {
2 | kotlinOptions {
3 | jvmTarget = "1.8"
4 | }
5 | buildFeatures {
6 | compose = true
7 | }
8 | composeOptions {
9 | kotlinCompilerExtensionVersion = "1.1.1"
10 | }
11 | }
12 |
13 | dependencies {
14 | api(project(":control:provider"))
15 | kapt(libs.bundles.builder.kapt)
16 | }
--------------------------------------------------------------------------------
/modsample/mmdexample/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/modsample/mmdexample/consumer-rules.pro
--------------------------------------------------------------------------------
/modsample/mmdexample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/modsample/mmdexample/src/androidTest/java/com/singularity_code/modsample/mmdexample/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.mmdexample
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.singularity_code.modsample.mmdexample.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/java/com/singularity_code/mmdexample/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.mmdexample
2 |
3 | import com.singularity_code.mmdexample.ui.uiModule
4 |
5 | val modMMDSampleModules = arrayOf(
6 | uiModule
7 | )
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/java/com/singularity_code/mmdexample/ui/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.mmdexample.ui
2 |
3 | import com.singularity_code.control.provider.sample.mmdexample.MMDExampleSpace
4 | import com.singularity_code.mmdexample.ui.activity.MMDExampleActivitySpace
5 | import org.koin.dsl.module
6 |
7 | val uiModule = module {
8 | factory {
9 | MMDExampleActivitySpace()
10 | }
11 | }
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/java/com/singularity_code/mmdexample/ui/activity/MMDExampleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.mmdexample.ui.activity
2 |
3 | import androidx.compose.runtime.Composable
4 | import com.singularity_code.core.common.pattern.activity.BaseActivityAbs
5 | import com.singularity_code.core.ui.theme.ContentThemeWrapper
6 | import com.singularity_code.mmdexample.ui.screen.home.HomeScreen
7 |
8 | class MMDExampleActivity : BaseActivityAbs() {
9 | override val content = @Composable {
10 | ContentThemeWrapper() {
11 | HomeScreen()
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/java/com/singularity_code/mmdexample/ui/activity/MMDExampleActivitySpace.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.mmdexample.ui.activity
2 |
3 | import com.singularity_code.control.provider.sample.mmdexample.MMDExampleSpace
4 | import com.singularity_code.core.common.util.createLauncher
5 |
6 | class MMDExampleActivitySpace : MMDExampleSpace {
7 | override fun getLauncher() =
8 | createLauncher(
9 | activity = MMDExampleActivity::class.java,
10 | outputType = MMDExampleSpace.Result::class.java
11 | )
12 | }
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/java/com/singularity_code/mmdexample/ui/screen/home/HomeScreen.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.mmdexample.ui.screen.home
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.material3.Card
5 | import androidx.compose.material3.MaterialTheme
6 | import androidx.compose.material3.Text
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.lifecycle.viewmodel.compose.viewModel
10 | import com.singularity_code.core.common.util.mapState
11 | import com.singularity_code.core.ui.util.toDp
12 | import com.singularity_code.mmdexample.ui.screen.viewmodel.HomeViewModel
13 |
14 | @Composable
15 | fun HomeScreen(
16 | vm: HomeViewModel = viewModel()
17 | ) = Box(
18 | modifier = Modifier.fillMaxSize()
19 | ) {
20 |
21 | Column(
22 | modifier = Modifier
23 | .fillMaxWidth()
24 | .padding(16.toDp)
25 | ) {
26 |
27 | Text(
28 | text = "Module to Module Dependency Example",
29 | style = MaterialTheme.typography.titleLarge
30 | )
31 | Spacer(
32 | modifier = Modifier.height(32.toDp)
33 | )
34 | Card(
35 | modifier = Modifier
36 | .fillMaxWidth()
37 | ) {
38 | Column(
39 | modifier = Modifier
40 | .padding(16.toDp)
41 | ) {
42 | Text(
43 | text = "This Data From Pokemon Space Station",
44 | style = MaterialTheme.typography.headlineMedium
45 | )
46 | Spacer(
47 | modifier = Modifier
48 | .height(16.toDp)
49 | )
50 | Text(
51 | text = vm.pokemonState
52 | .mapState(
53 | { "" },
54 | { "Loading.." },
55 | { "Error: ${it.message}" },
56 | { "id: ${it.id} \nname: ${it.name}" },
57 | )
58 | )
59 | }
60 |
61 | }
62 |
63 | }
64 | }
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/java/com/singularity_code/mmdexample/ui/screen/viewmodel/HomeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.mmdexample.ui.screen.viewmodel
2 |
3 | import com.singularity_code.control.provider.sample.pokemon.PokemonSpaceStation
4 | import com.singularity_code.control.provider.sample.pokemon.model.PokemonGem
5 | import com.singularity_code.control.provider.sample.pokemon.payload.GetPokemonByIdSPLD
6 | import com.singularity_code.core.common.pattern.viewmodel.BaseViewModelAbs
7 | import com.singularity_code.core.common.util.createStateHolder
8 | import com.singularity_code.core.common.util.get
9 |
10 | class HomeViewModel(
11 | private val pokemonSpaceStation: PokemonSpaceStation = get()
12 | ) : BaseViewModelAbs(), HomeViewModelUseCase {
13 |
14 | override val pokemonState = createStateHolder {
15 | pokemonSpaceStation.getPokemonById(it)
16 | }
17 |
18 | override fun updatePokemonState(
19 | payload: GetPokemonByIdSPLD
20 | ) {
21 | pokemonState.requestUpdate(
22 | payload
23 | )
24 | }
25 |
26 | override fun clear() {
27 | TODO("Not yet implemented")
28 | }
29 |
30 | init {
31 | updatePokemonState(
32 | GetPokemonByIdSPLD(
33 | id = 1
34 | )
35 | )
36 | }
37 | }
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/java/com/singularity_code/mmdexample/ui/screen/viewmodel/HomeViewModelUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.mmdexample.ui.screen.viewmodel
2 |
3 | import com.singularity_code.mmdexample.ui.screen.viewmodel.usecase.PokemonViewModelUseCase
4 |
5 | interface HomeViewModelUseCase :
6 | PokemonViewModelUseCase
--------------------------------------------------------------------------------
/modsample/mmdexample/src/main/java/com/singularity_code/mmdexample/ui/screen/viewmodel/usecase/PokemonViewModelUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.mmdexample.ui.screen.viewmodel.usecase
2 |
3 | import com.singularity_code.control.provider.sample.pokemon.model.PokemonGem
4 | import com.singularity_code.control.provider.sample.pokemon.payload.GetPokemonByIdSPLD
5 | import com.singularity_code.core.common.pattern.State
6 |
7 | interface PokemonViewModelUseCase {
8 | val pokemonState: State
9 | fun updatePokemonState(payload: GetPokemonByIdSPLD)
10 | }
--------------------------------------------------------------------------------
/modsample/mmdexample/src/test/java/com/singularity_code/modsample/mmdexample/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.mmdexample
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/modsample/pokemon/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/modsample/pokemon/build.gradle.kts:
--------------------------------------------------------------------------------
1 | android {
2 | kotlinOptions {
3 | jvmTarget = "1.8"
4 | }
5 | buildFeatures {
6 | compose = true
7 | }
8 | composeOptions {
9 | kotlinCompilerExtensionVersion = "1.1.1"
10 | }
11 | }
12 |
13 | dependencies {
14 | api(project(":control:provider"))
15 | kapt(libs.bundles.builder.kapt)
16 | }
--------------------------------------------------------------------------------
/modsample/pokemon/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/modsample/pokemon/consumer-rules.pro
--------------------------------------------------------------------------------
/modsample/pokemon/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/modsample/pokemon/src/androidTest/java/com/singularity_code/modsample/pokemon/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.singularity_code.modsample.pokemon.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon
2 |
3 | import com.singularity_code.modsample.pokemon.station.stationModule
4 | import com.singularity_code.modsample.pokemon.ui.uiModule
5 |
6 | val modPokemonModules = arrayOf(
7 | uiModule,
8 | stationModule,
9 | )
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/data/PokemonRepository.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.data
2 |
3 | import arrow.core.Either
4 | import com.singularity_code.core.common.model.VmError
5 | import com.singularity_code.core.network.GetPokemonByIdQuery
6 | import com.singularity_code.core.network.GetPokemonListQuery
7 | import com.singularity_code.modsample.pokemon.data.payload.GPBIPLD
8 | import com.singularity_code.modsample.pokemon.data.payload.GPLPLD
9 | import com.singularity_code.modsample.pokemon.data.src.web.getPokemonByIdWeb
10 | import com.singularity_code.modsample.pokemon.data.src.web.getPokemonListWeb
11 |
12 | suspend fun getPokemonList(
13 | payload: GPLPLD
14 | ): Either =
15 | getPokemonListWeb(
16 | payload
17 | )
18 |
19 | suspend fun getPokemonById(
20 | payload: GPBIPLD
21 | ): Either =
22 | getPokemonByIdWeb(
23 | payload
24 | )
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/data/payload/GetPokemonByIdPld.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.data.payload
2 |
3 | import com.singularity_code.core.common.pattern.Payload
4 |
5 | /**
6 | * sort for GetPokemonByIdPld
7 | */
8 | typealias GPBIPLD = GetPokemonByIdPld
9 |
10 | data class GetPokemonByIdPld(
11 | val id: Int
12 | ) : Payload
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/data/payload/GetPokemonListPld.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.data.payload
2 |
3 | import com.singularity_code.core.common.pattern.Payload
4 |
5 | /**
6 | * sort for GetPokemonListPld
7 | */
8 | typealias GPLPLD = GetPokemonListPld
9 |
10 | data class GetPokemonListPld(
11 | val limit: Int = 10,
12 | val offset: Int = 0
13 | ) : Payload
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/data/src/web/WebApi.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.data.src.web
2 |
3 | import arrow.core.Either
4 | import com.singularity_code.core.common.model.VmError
5 | import com.singularity_code.core.common.util.getOrError
6 | import com.singularity_code.core.network.GetPokemonByIdQuery
7 | import com.singularity_code.core.network.GetPokemonListQuery
8 | import com.singularity_code.core.network.util.Secured
9 | import com.singularity_code.core.network.util.apolloClient
10 | import com.singularity_code.modsample.pokemon.data.payload.GPBIPLD
11 | import com.singularity_code.modsample.pokemon.data.payload.GPLPLD
12 |
13 | private val apiClient by lazy { apolloClient(Secured.getBasePokemonUrl()) }
14 |
15 | suspend fun getPokemonListWeb(
16 | payload: GPLPLD
17 | ): Either =
18 | apiClient
19 | .query(
20 | GetPokemonListQuery(
21 | payload.limit,
22 | payload.offset
23 | )
24 | )
25 | .getOrError()
26 |
27 | suspend fun getPokemonByIdWeb(
28 | payload: GPBIPLD
29 | ): Either =
30 | apiClient.query(
31 | GetPokemonByIdQuery(
32 | payload.id
33 | )
34 | ).getOrError()
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/station/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.station
2 |
3 | import com.singularity_code.control.provider.sample.pokemon.PokemonSpaceStation
4 | import org.koin.dsl.module
5 |
6 | val stationModule = module {
7 | factory {
8 | SpaceStation()
9 | }
10 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/station/SpaceStation.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.station
2 |
3 | import arrow.core.Either
4 | import com.singularity_code.control.provider.sample.pokemon.PokemonSpaceStation
5 | import com.singularity_code.control.provider.sample.pokemon.model.PokemonGem
6 | import com.singularity_code.control.provider.sample.pokemon.payload.GetPokemonByIdSPLD
7 | import com.singularity_code.core.common.model.VmError
8 |
9 | class SpaceStation : PokemonSpaceStation {
10 | override suspend fun getPokemonById(
11 | payload: GetPokemonByIdSPLD
12 | ): Either {
13 |
14 | val pld = com.singularity_code
15 | .modsample
16 | .pokemon
17 | .data
18 | .payload
19 | .GPBIPLD(payload.id)
20 |
21 | return com.singularity_code
22 | .modsample
23 | .pokemon
24 | .data
25 | .getPokemonById(
26 | pld
27 | )
28 | .map {
29 | it.pokemon_v2_pokemon[0]
30 | .let {
31 | PokemonGem(
32 | id = it.id.toString(),
33 | name = it.name
34 | )
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/ui/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.ui
2 |
3 | import com.singularity_code.control.provider.sample.pokemon.PokemonSpace
4 | import com.singularity_code.modsample.pokemon.ui.activity.PokemonActivitySpace
5 | import org.koin.dsl.module
6 |
7 | val uiModule = module {
8 | factory {
9 | PokemonActivitySpace()
10 | }
11 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/ui/activity/PokemonActivity.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.ui.activity
2 |
3 | import androidx.compose.runtime.Composable
4 | import com.singularity_code.core.common.pattern.activity.BaseActivityAbs
5 | import com.singularity_code.core.ui.theme.ContentThemeWrapper
6 | import com.singularity_code.modsample.pokemon.ui.screen.home.HomeScreen
7 |
8 | class PokemonActivity : BaseActivityAbs() {
9 | override val content = @Composable {
10 | ContentThemeWrapper {
11 | HomeScreen()
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/ui/activity/PokemonActivitySpace.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.ui.activity
2 |
3 | import com.singularity_code.control.provider.sample.pokemon.PokemonSpace
4 | import com.singularity_code.core.common.util.createLauncher
5 |
6 | class PokemonActivitySpace : PokemonSpace {
7 | override fun getLauncher() =
8 | createLauncher(
9 | activity = PokemonActivity::class.java,
10 | outputType = PokemonSpace.Result::class.java
11 | )
12 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/ui/screen/home/HomeScreen.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.ui.screen.home
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.foundation.lazy.LazyColumn
5 | import androidx.compose.material3.Button
6 | import androidx.compose.material3.CircularProgressIndicator
7 | import androidx.compose.material3.Text
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Alignment
10 | import androidx.compose.ui.Modifier
11 | import androidx.lifecycle.viewmodel.compose.viewModel
12 | import com.singularity_code.core.common.model.VmError
13 | import com.singularity_code.core.common.util.onState
14 | import com.singularity_code.core.network.GetPokemonListQuery
15 | import com.singularity_code.core.ui.util.toDp
16 | import com.singularity_code.modsample.pokemon.ui.screen.home.viewmodel.HomeViewModel
17 |
18 | @Composable
19 | fun HomeScreen(
20 | vm: HomeViewModel = viewModel(),
21 | modifier: Modifier = Modifier
22 | ) = Box(
23 | modifier = Modifier
24 | .fillMaxSize()
25 | .then(modifier)
26 | ) {
27 |
28 | vm.pokemonListState
29 | .onState(
30 | default = {
31 | Iddle()
32 | },
33 | loading = {
34 | LoadingPage()
35 | },
36 | failed = {
37 | Error(it)
38 | },
39 | success = {
40 | SuccessPage(it)
41 | }
42 | )
43 | }
44 |
45 | @Composable
46 | fun Iddle() {
47 |
48 | }
49 |
50 | @Composable
51 | fun BoxScope.LoadingPage() {
52 | CircularProgressIndicator(
53 | modifier = Modifier.align(
54 | Alignment.Center
55 | )
56 | )
57 | }
58 |
59 | @Composable
60 | fun SuccessPage(
61 | data: GetPokemonListQuery.Data
62 | ) {
63 | LazyColumn(
64 | modifier = Modifier.padding(16.toDp)
65 | ) {
66 | data.pokemon_v2_pokemon.map { data ->
67 | item(
68 | key = data.id
69 | ) {
70 | Button(
71 | onClick = {
72 |
73 | },
74 | modifier = Modifier
75 | .fillMaxWidth()
76 | ) {
77 | Text(text = data.name)
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
84 | @Composable
85 | fun Error(
86 | e: VmError
87 | ) {
88 | Text(text = e.message.toString())
89 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/ui/screen/home/viewmodel/HomeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.ui.screen.home.viewmodel
2 |
3 | import com.singularity_code.core.common.pattern.viewmodel.BaseViewModelAbs
4 | import com.singularity_code.core.common.util.createStateHolder
5 | import com.singularity_code.core.network.GetPokemonListQuery
6 | import com.singularity_code.modsample.pokemon.data.getPokemonList
7 | import com.singularity_code.modsample.pokemon.data.payload.GPLPLD
8 |
9 | class HomeViewModel : BaseViewModelAbs(), HomeViewModelUseCase {
10 |
11 | override val pokemonListState =
12 | createStateHolder {
13 | getPokemonList(it)
14 | }
15 |
16 | override fun updatePokemonListState(
17 | payload: GPLPLD
18 | ) {
19 | pokemonListState.requestUpdate(
20 | payload
21 | )
22 | }
23 |
24 | override fun clear() {
25 | TODO("Not yet implemented")
26 | }
27 |
28 | init {
29 | updatePokemonListState(
30 | GPLPLD(
31 | limit = 30
32 | )
33 | )
34 | }
35 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/main/java/com/singularity_code/modsample/pokemon/ui/screen/home/viewmodel/HomeViewModelUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon.ui.screen.home.viewmodel
2 |
3 | import com.singularity_code.core.common.pattern.State
4 | import com.singularity_code.core.network.GetPokemonListQuery
5 | import com.singularity_code.modsample.pokemon.data.payload.GPLPLD
6 |
7 | interface HomeViewModelUseCase {
8 | val pokemonListState: State
9 | fun updatePokemonListState(payload: GPLPLD)
10 | }
--------------------------------------------------------------------------------
/modsample/pokemon/src/test/java/com/singularity_code/modsample/pokemon/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.pokemon
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/modsample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/modsample/splash/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/modsample/splash/build.gradle.kts:
--------------------------------------------------------------------------------
1 | android {
2 | kotlinOptions {
3 | jvmTarget = "1.8"
4 | }
5 | buildFeatures {
6 | compose = true
7 | }
8 | composeOptions {
9 | kotlinCompilerExtensionVersion = "1.1.1"
10 | }
11 | }
12 |
13 | dependencies {
14 | api(project(":control:provider"))
15 | kapt(libs.bundles.builder.kapt)
16 | }
--------------------------------------------------------------------------------
/modsample/splash/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/modsample/splash/consumer-rules.pro
--------------------------------------------------------------------------------
/modsample/splash/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/modsample/splash/src/androidTest/java/com/singularity_code/modsample/splash/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.splash
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.singularity_code.modsample.splash.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/modsample/splash/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/modsample/splash/src/main/java/com/singularity_code/modsample/splash/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.splash
--------------------------------------------------------------------------------
/modsample/splash/src/main/java/com/singularity_code/modsample/splash/ui/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.splash.ui
--------------------------------------------------------------------------------
/modsample/splash/src/main/java/com/singularity_code/modsample/splash/ui/activity/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.splash.ui.activity
2 |
3 | import android.annotation.SuppressLint
4 | import androidx.compose.runtime.Composable
5 | import com.singularity_code.control.provider.sample.mmdexample.MMDExampleSpace
6 | import com.singularity_code.control.provider.sample.pokemon.PokemonSpace
7 | import com.singularity_code.control.provider.sample.todolist.TodoSpace
8 | import com.singularity_code.core.common.pattern.activity.BaseActivityAbs
9 | import com.singularity_code.core.common.util.launcher
10 | import com.singularity_code.core.ui.theme.ContentThemeWrapper
11 | import com.singularity_code.core.ui.util.setupScreenSize
12 | import com.singularity_code.modsample.splash.ui.screen.splash.SplashScreen
13 | import org.koin.android.ext.android.get
14 |
15 | @SuppressLint("CustomSplashScreen")
16 | class SplashActivity : BaseActivityAbs(), SplashActivityUseCase {
17 |
18 | override val todoLauncher = launcher(get())
19 | override val pokemonLauncher = launcher(get())
20 | override val mmdExampleLauncher = launcher(get())
21 |
22 | override val content = @Composable {
23 | setupScreenSize(1f)
24 | ContentThemeWrapper() {
25 | SplashScreen(
26 | portal = this
27 | )
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/modsample/splash/src/main/java/com/singularity_code/modsample/splash/ui/activity/SplashActivityUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.splash.ui.activity
2 |
3 | import com.singularity_code.modsample.splash.ui.navigation.SplashPortal
4 |
5 | interface SplashActivityUseCase :
6 | SplashPortal
--------------------------------------------------------------------------------
/modsample/splash/src/main/java/com/singularity_code/modsample/splash/ui/navigation/SplashPortal.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.splash.ui.navigation
2 |
3 | import com.singularity_code.control.provider.sample.mmdexample.MMDExampleSpace
4 | import com.singularity_code.control.provider.sample.pokemon.PokemonSpace
5 | import com.singularity_code.control.provider.sample.todolist.TodoSpace
6 | import com.singularity_code.core.common.util.Launcher
7 |
8 | interface SplashPortal {
9 | val todoLauncher: Launcher
10 | fun goToTodoList(
11 | payload: TodoSpace.Pld,
12 | result: ((TodoSpace.Result) -> Unit)? = null
13 | ) {
14 | todoLauncher.resultCallback = result
15 | todoLauncher.launch(payload)
16 | }
17 |
18 | val pokemonLauncher: Launcher
19 | fun goToPokemonHome(
20 | payload: PokemonSpace.Pld,
21 | result: ((PokemonSpace.Result) -> Unit)? = null
22 | ) {
23 | pokemonLauncher.resultCallback = result
24 | pokemonLauncher.launch(payload)
25 | }
26 |
27 | val mmdExampleLauncher: Launcher
28 | fun goToMMDExample(
29 | payload: MMDExampleSpace.Pld,
30 | result: ((MMDExampleSpace.Result) -> Unit)? = null
31 | ) {
32 | mmdExampleLauncher.resultCallback = result
33 | mmdExampleLauncher.launch(payload)
34 | }
35 | }
--------------------------------------------------------------------------------
/modsample/splash/src/main/java/com/singularity_code/modsample/splash/ui/screen/splash/SplashScreen.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.splash.ui.screen.splash
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.*
5 | import androidx.compose.material.icons.Icons
6 | import androidx.compose.material.icons.rounded.ArrowForward
7 | import androidx.compose.material3.Button
8 | import androidx.compose.material3.Card
9 | import androidx.compose.material3.MaterialTheme
10 | import androidx.compose.material3.Text
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.graphics.Color
15 | import androidx.compose.ui.graphics.ColorFilter
16 | import androidx.compose.ui.tooling.preview.Preview
17 | import com.singularity_code.control.provider.sample.mmdexample.MMDExampleSpace
18 | import com.singularity_code.control.provider.sample.pokemon.PokemonSpace
19 | import com.singularity_code.control.provider.sample.todolist.TodoSpace
20 | import com.singularity_code.core.common.util.logDebug
21 | import com.singularity_code.core.ui.theme.ContentThemeWrapper
22 | import com.singularity_code.core.ui.util.toDp
23 | import com.singularity_code.modsample.splash.ui.navigation.SplashPortal
24 |
25 | @Composable
26 | fun SplashScreen(
27 | name: String = "Splash",
28 | portal: SplashPortal? = null,
29 | modifier: Modifier = Modifier
30 | ) = Box(
31 | modifier = Modifier
32 | .padding(16.toDp)
33 | .fillMaxSize()
34 | ) {
35 | Card(
36 | modifier = Modifier
37 | .height(200.toDp)
38 | .align(Alignment.BottomCenter)
39 | ) {
40 | Box(
41 | modifier = Modifier
42 | .fillMaxSize()
43 | .then(modifier)
44 | .padding(16.toDp)
45 | ) {
46 |
47 | Column(
48 | horizontalAlignment = Alignment.CenterHorizontally,
49 | modifier = Modifier.align(
50 | Alignment.BottomCenter
51 | )
52 | ) {
53 |
54 | ArrowButton(
55 | text = "Go to Todo List"
56 | ) {
57 | portal?.goToTodoList(
58 | TodoSpace.Pld()
59 | ) {
60 | logDebug("Back from Todo List trip $it")
61 | }
62 | }
63 |
64 | Spacer(
65 | modifier = Modifier
66 | .height(16.toDp)
67 | )
68 |
69 | ArrowButton(
70 | text = "Go to Pokemon Home"
71 | ) {
72 | portal?.goToPokemonHome(
73 | PokemonSpace.Pld()
74 | ) {
75 | logDebug("Back from Pokemon trip $it")
76 | }
77 | }
78 |
79 | Spacer(
80 | modifier = Modifier
81 | .height(16.toDp)
82 | )
83 |
84 | ArrowButton(
85 | text = "Go to MMD Example"
86 | ) {
87 | portal?.goToMMDExample(
88 | MMDExampleSpace.Pld()
89 | )
90 | }
91 |
92 | Spacer(
93 | modifier = Modifier
94 | .height(16.toDp)
95 | )
96 | }
97 | }
98 | }
99 | }
100 |
101 | @Composable
102 | fun ArrowButton(
103 | text: String,
104 | onClick: () -> Unit
105 | ) = Button(
106 | onClick = onClick,
107 | modifier = Modifier.fillMaxWidth()
108 | ) {
109 | Row(
110 | verticalAlignment = Alignment.CenterVertically
111 | ) {
112 | Text(text = text)
113 | Spacer(
114 | modifier = Modifier
115 | .width(8.toDp)
116 | )
117 | Image(
118 | imageVector = Icons.Rounded.ArrowForward,
119 | contentDescription = "Navigate",
120 | colorFilter = ColorFilter.tint(
121 | color = MaterialTheme.colorScheme.onPrimary
122 | )
123 | )
124 | }
125 | }
126 |
127 | @Composable
128 | @Preview(showSystemUi = true)
129 | fun Preview() {
130 | ContentThemeWrapper {
131 | SplashScreen()
132 | }
133 | }
--------------------------------------------------------------------------------
/modsample/splash/src/test/java/com/singularity_code/modsample/splash/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.splash
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/modsample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/modsample/todolist/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/modsample/todolist/build.gradle.kts:
--------------------------------------------------------------------------------
1 | android {
2 | kotlinOptions {
3 | jvmTarget = "1.8"
4 | }
5 | buildFeatures {
6 | compose = true
7 | }
8 | composeOptions {
9 | kotlinCompilerExtensionVersion = "1.1.1"
10 | }
11 | }
12 |
13 | dependencies {
14 | api(project(":control:provider"))
15 | kapt(libs.bundles.builder.kapt)
16 | }
--------------------------------------------------------------------------------
/modsample/todolist/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanusayudha/base-android-compose/663d4d4ef63f43b2d14233a71c04605539998403/modsample/todolist/consumer-rules.pro
--------------------------------------------------------------------------------
/modsample/todolist/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/modsample/todolist/src/androidTest/java/com/singularity_code/modsample/todolist/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.singularity_code.modsample.todolist.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist
2 |
3 | import com.singularity_code.modsample.todolist.ui.uiModule
4 |
5 | val modTodoListModules = arrayOf(
6 | uiModule
7 | )
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/data/TodoRepository.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.data
2 |
3 | import arrow.core.Either
4 | import com.singularity_code.core.common.model.VmError
5 | import com.singularity_code.modsample.todolist.data.model.TDMDL
6 | import com.singularity_code.modsample.todolist.data.payload.GetTodoByIdPld
7 | import com.singularity_code.modsample.todolist.data.payload.GetTodoListPld
8 | import com.singularity_code.modsample.todolist.data.src.web.todoListWebApi
9 |
10 | suspend fun getTodoList(
11 | payload: GetTodoListPld
12 | ): Either> {
13 |
14 | return todoListWebApi
15 | .getTodoList(
16 | payload.getQueryMap()
17 | )
18 | .let { res ->
19 |
20 | // you can handler request code here if you want
21 | // since you may need to handle http error and result error different way.
22 | // http error will only emmit message and http code,
23 | // while result error can contain more stuff depend to your api design.
24 |
25 | // this is example for general. by assuming that api error will only emit error message
26 | res.body
27 | .mapLeft {
28 | VmError(
29 | code = res.code,
30 | message = it
31 | )
32 | }
33 | }
34 | }
35 |
36 | suspend fun getTodoById(
37 | payload: GetTodoByIdPld
38 | ): Either {
39 | return todoListWebApi
40 | .getTodoById(
41 | payload.id
42 | )
43 | .let { res ->
44 | res.body
45 | .mapLeft {
46 | VmError(
47 | code = res.code,
48 | message = it
49 | )
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/data/model/TodoMdl.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.data.model
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | /**
6 | * sort for TodoMdl
7 | */
8 | typealias TDMDL = TodoMdl
9 |
10 | data class TodoMdl(
11 | @field:SerializedName("id")
12 | val id: Int? = null,
13 |
14 | @field:SerializedName("completed")
15 | val completed: Boolean? = null,
16 |
17 | @field:SerializedName("title")
18 | val title: String? = null,
19 |
20 | @field:SerializedName("userId")
21 | val userId: String? = null
22 | ) {
23 | companion object {
24 | val MOCK_LIST = (1..10).map {
25 | TDMDL(
26 | id = it,
27 | completed = it % 3 == 0,
28 | title = "Todo Number $it",
29 | userId = "User $it"
30 | )
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/data/payload/GetTodoByIdPld.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.data.payload
2 |
3 | import com.singularity_code.core.common.pattern.Payload
4 |
5 | data class GetTodoByIdPld(
6 | val id: String = ""
7 | ) : Payload {
8 | override fun getQueryMap() = hashMapOf()
9 | .apply {
10 | // No query payload
11 | }
12 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/data/payload/GetTodoListPld.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.data.payload
2 |
3 | import com.singularity_code.core.common.pattern.Payload
4 |
5 | data class GetTodoListPld(
6 | val id: String = ""
7 | ) : Payload {
8 | override fun getQueryMap() = hashMapOf()
9 | .apply {
10 | // No query payload
11 | }
12 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/data/src/web/WebApi.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.data.src.web
2 |
3 | import arrow.retrofit.adapter.either.ResponseE
4 | import com.singularity_code.core.common.util.createRetrofitService
5 | import com.singularity_code.core.network.util.Secured
6 | import com.singularity_code.core.network.util.defaultOkhttp
7 | import com.singularity_code.modsample.todolist.data.model.TDMDL
8 | import retrofit2.http.GET
9 | import retrofit2.http.Path
10 | import retrofit2.http.QueryMap
11 |
12 | interface TodoListApi {
13 | @GET("todos/")
14 | suspend fun getTodoList(
15 | @QueryMap queries: HashMap
16 | ): ResponseE>
17 |
18 | @GET("todos/{id}")
19 | suspend fun getTodoById(
20 | @Path("id") id: String
21 | ): ResponseE
22 | }
23 |
24 | val todoListWebApi by lazy {
25 | createRetrofitService(
26 | TodoListApi::class.java,
27 | defaultOkhttp(),
28 | Secured.getBaseUrl()
29 | )
30 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/ui/DI.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.ui
2 |
3 | import com.singularity_code.control.provider.sample.todolist.TodoSpace
4 | import com.singularity_code.modsample.todolist.ui.activity.TodoActivitySpace
5 | import org.koin.dsl.module
6 |
7 | val uiModule = module {
8 | factory {
9 | TodoActivitySpace()
10 | }
11 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/ui/activity/TodoActivity.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.ui.activity
2 |
3 | import androidx.compose.runtime.Composable
4 | import com.singularity_code.core.common.model.NOTHING
5 | import com.singularity_code.core.common.pattern.activity.ActivityResultEmitter
6 | import com.singularity_code.core.common.pattern.activity.BaseActivityAbs
7 | import com.singularity_code.core.ui.theme.ContentThemeWrapper
8 | import com.singularity_code.modsample.todolist.ui.screen.TodoScreen
9 |
10 | class TodoActivity : BaseActivityAbs(), ActivityResultEmitter {
11 | override val content = @Composable {
12 | ContentThemeWrapper {
13 | TodoScreen()
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/ui/activity/TodoActivitySpace.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.ui.activity
2 |
3 | import com.singularity_code.control.provider.sample.todolist.TodoSpace
4 | import com.singularity_code.core.common.util.createLauncher
5 |
6 | class TodoActivitySpace() : TodoSpace {
7 | override fun getLauncher() =
8 | createLauncher(
9 | activity = TodoActivity::class.java,
10 | outputType = TodoSpace.Result::class.java
11 | )
12 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/ui/screen/TodoScreen.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.ui.screen
2 |
3 |
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.lazy.LazyColumn
7 | import androidx.compose.foundation.shape.RoundedCornerShape
8 | import androidx.compose.material3.*
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.graphics.Color
13 | import androidx.compose.ui.text.style.TextAlign
14 | import androidx.compose.ui.tooling.preview.Preview
15 | import androidx.lifecycle.viewmodel.compose.viewModel
16 | import com.singularity_code.core.common.util.onState
17 | import com.singularity_code.core.ui.theme.ContentThemeWrapper
18 | import com.singularity_code.core.ui.util.toDp
19 | import com.singularity_code.modsample.todolist.data.model.TDMDL
20 | import com.singularity_code.modsample.todolist.data.payload.GetTodoListPld
21 | import com.singularity_code.modsample.todolist.ui.screen.viewmodel.TodoViewModel
22 |
23 | @Composable
24 | fun TodoScreen(
25 | modifier: Modifier = Modifier
26 | ) = Box(
27 | modifier = Modifier
28 | .fillMaxSize()
29 | .then(modifier)
30 | ) {
31 | Column(
32 | modifier = Modifier
33 | .fillMaxSize()
34 | ) {
35 | Content(
36 | modifier = Modifier
37 | .fillMaxWidth()
38 | .weight(1f)
39 | )
40 | DownloadButton(
41 | modifier = Modifier
42 | .padding(16.toDp)
43 | )
44 | }
45 | }
46 |
47 | @Composable
48 | fun Content(
49 | modifier: Modifier = Modifier,
50 | vm: TodoViewModel = viewModel()
51 | ) = Box(
52 | modifier = modifier
53 | ) {
54 | vm.todoListState
55 | .onState(
56 | default = {
57 | Text(text = "Idle")
58 | },
59 | loading = {
60 | ProgressBlocker(
61 | modifier = Modifier
62 | .align(Alignment.Center)
63 | )
64 | },
65 | failed = {
66 | Text(
67 | modifier = Modifier
68 | .align(Alignment.Center),
69 | text = "Failed: ${it.message}"
70 | )
71 | },
72 | success = {
73 | ListContent(
74 | modifier = Modifier
75 | .align(Alignment.Center),
76 | list = it
77 | )
78 | }
79 | )
80 | }
81 |
82 | @Composable
83 | fun ListContent(
84 | modifier: Modifier = Modifier,
85 | list: List = listOf()
86 | ) = LazyColumn(
87 | modifier = modifier
88 | ) {
89 | list.map {
90 | item(it.id) {
91 | ListItem(item = it)
92 | }
93 | }
94 | item {
95 | Spacer(
96 | modifier = Modifier
97 | .fillMaxWidth()
98 | .height(16.toDp)
99 | )
100 | }
101 | }
102 |
103 |
104 | @Composable
105 | fun ListItem(
106 | item: TDMDL
107 | ) = Card(
108 | shape = RoundedCornerShape(8.toDp),
109 | modifier = Modifier
110 | .padding(16.toDp, 16.toDp, 16.toDp, 0.toDp)
111 | ) {
112 | Card(
113 | modifier = Modifier
114 | .fillMaxWidth()
115 | .padding(8.toDp)
116 | .height(50.toDp)
117 | ) {
118 | Box(
119 | modifier = Modifier.fillMaxSize()
120 | ) {
121 | Text(
122 | modifier = Modifier
123 | .align(Alignment.Center),
124 | text = "${item.title}",
125 | textAlign = TextAlign.Center
126 | )
127 | }
128 | }
129 | }
130 |
131 | @Composable
132 | fun ProgressBlocker(
133 | modifier: Modifier = Modifier
134 | ) = CircularProgressIndicator(
135 | modifier = modifier,
136 | )
137 |
138 | @Composable
139 | fun DownloadButton(
140 | modifier: Modifier = Modifier,
141 | vm: TodoViewModel = viewModel()
142 | ) = Box(modifier = modifier) {
143 |
144 | Button(
145 | onClick = {
146 | vm.todoListState.request(payload = GetTodoListPld())
147 | },
148 | modifier = Modifier
149 | .fillMaxWidth()
150 | ) {
151 | Text(text = "Load")
152 | }
153 | }
154 |
155 | @Composable
156 | @Preview(showSystemUi = true)
157 | fun Preview() {
158 | ContentThemeWrapper() {
159 | TodoScreen()
160 | }
161 | }
162 |
163 | @Composable
164 | @Preview(showSystemUi = false)
165 | fun ListPreview() {
166 | ContentThemeWrapper(
167 | forceDark = true
168 | ) {
169 | Box {
170 | ListContent(list = TDMDL.MOCK_LIST)
171 | }
172 | }
173 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/ui/screen/viewmodel/TodoViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.ui.screen.viewmodel
2 |
3 | import com.singularity_code.core.common.pattern.viewmodel.BaseViewModelAbs
4 | import com.singularity_code.core.common.util.createStateHolder
5 | import com.singularity_code.modsample.todolist.data.getTodoList
6 | import com.singularity_code.modsample.todolist.data.model.TDMDL
7 | import com.singularity_code.modsample.todolist.data.payload.GetTodoListPld
8 |
9 | class TodoViewModel : BaseViewModelAbs(), TodoViewModelUseCase {
10 |
11 | override val todoListState =
12 | createStateHolder, GetTodoListPld> {
13 | getTodoList(it)
14 | }
15 |
16 | override fun clear() {
17 | todoListState.resetClear()
18 | }
19 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/main/java/com/singularity_code/modsample/todolist/ui/screen/viewmodel/TodoViewModelUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist.ui.screen.viewmodel
2 |
3 | import com.singularity_code.core.common.pattern.State
4 | import com.singularity_code.modsample.todolist.data.model.TDMDL
5 | import com.singularity_code.modsample.todolist.data.payload.GetTodoListPld
6 |
7 | interface TodoViewModelUseCase {
8 | val todoListState: State, GetTodoListPld>
9 | }
--------------------------------------------------------------------------------
/modsample/todolist/src/test/java/com/singularity_code/modsample/todolist/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.singularity_code.modsample.todolist
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "Base Architecture"
16 | include ':app'
17 | include ':core'
18 | include ':core:ui'
19 | include ':core:network'
20 | include ':core:common'
21 | include ':control'
22 | include ':control:provider'
23 | include ':control:igniter'
24 |
25 | include ':modsample'
26 | include ':modsample:splash'
27 | include ':modsample:pokemon'
28 | include ':modsample:todolist'
29 | include ':modsample:mmdexample'
30 |
--------------------------------------------------------------------------------