diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 241cf0d3..cf550461 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -30,6 +30,8 @@ dependencies { implementation(projects.core.network) implementation(projects.core.navigation) implementation(projects.core.ui) + implementation(projects.core.datastore) + implementation(projects.core.token) implementation(projects.core.util) implementation(projects.data) implementation(projects.domain) diff --git a/core/datastore/.gitignore b/core/datastore/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/core/datastore/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts new file mode 100644 index 00000000..c76d6461 --- /dev/null +++ b/core/datastore/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + alias(libs.plugins.twix.android.library) + alias(libs.plugins.twix.koin) + alias(libs.plugins.serialization) +} + +android { + namespace = "com.twix.datastore" +} + +dependencies { + implementation(projects.core.token) + + implementation(libs.androidx.datastore) + implementation(libs.kotlinx.serialization.json) +} diff --git a/core/datastore/consumer-rules.pro b/core/datastore/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/core/datastore/proguard-rules.pro b/core/datastore/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/core/datastore/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/datastore/src/main/AndroidManifest.xml b/core/datastore/src/main/AndroidManifest.xml new file mode 100644 index 00000000..8bdb7e14 --- /dev/null +++ b/core/datastore/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/core/datastore/src/main/java/com/twix/datastore/AuthConfigure.kt b/core/datastore/src/main/java/com/twix/datastore/AuthConfigure.kt new file mode 100644 index 00000000..3406980c --- /dev/null +++ b/core/datastore/src/main/java/com/twix/datastore/AuthConfigure.kt @@ -0,0 +1,52 @@ +package com.twix.datastore + +import androidx.datastore.core.Serializer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json +import java.io.InputStream +import java.io.OutputStream + +@Serializable +internal data class AuthConfigure( + val accessToken: String = + "eyJhbGciOiJIUzM4NCJ9." + + "eyJzdWIiOiIxIiwidHlwZSI6ImFjY2VzcyIsImlhdCI6MTc3MDI0NzM0NCwiZXhwIjoxNzcwODUyMTQ0fQ." + + "67rDscm8BeayYFA1gfcEMliEdEh8-HTUyE5TwmAT8Ef8ZvtaWczxpMNZqI5htiek", + val refreshToken: String = + "eyJhbGciOiJIUzM4NCJ9." + + "eyJzdWIiOiIxIiwidHlwZSI6InJlZnJlc2giLCJpYXQiOjE3NzAyNDczNDQsImV4cCI6MTc3MDg1MjE0NH0." + + "zgUYdR6onyeY5EaH2_pWLs1rjNLf8m8ZeXsY7Cbk99a_2tzR0rDBZO_hdGTnorRL", +) + +internal object AuthConfigureSerializer : Serializer { + override val defaultValue: AuthConfigure + get() = AuthConfigure() + + override suspend fun readFrom(input: InputStream): AuthConfigure = + try { + Json.decodeFromString( + deserializer = AuthConfigure.serializer(), + string = input.readBytes().decodeToString(), + ) + } catch (e: SerializationException) { + defaultValue + } + + override suspend fun writeTo( + t: AuthConfigure, + output: OutputStream, + ) { + withContext(Dispatchers.IO) { + output.write( + Json + .encodeToString( + serializer = AuthConfigure.serializer(), + value = t, + ).encodeToByteArray(), + ) + } + } +} diff --git a/core/datastore/src/main/java/com/twix/datastore/AuthTokenProvider.kt b/core/datastore/src/main/java/com/twix/datastore/AuthTokenProvider.kt new file mode 100644 index 00000000..17bbfbab --- /dev/null +++ b/core/datastore/src/main/java/com/twix/datastore/AuthTokenProvider.kt @@ -0,0 +1,32 @@ +package com.twix.datastore + +import android.content.Context +import androidx.datastore.core.DataStore +import com.twix.token.TokenProvider +import kotlinx.coroutines.flow.first + +class AuthTokenProvider( + private val context: Context, +) : TokenProvider { + private val dataStore: DataStore + get() = context.authDataStore + + override suspend fun accessToken(): String = dataStore.data.first().accessToken + + override suspend fun refreshToken(): String = dataStore.data.first().refreshToken + + override suspend fun saveToken( + accessToken: String, + refreshToken: String, + ) { + dataStore.updateData { + it.copy(accessToken = accessToken, refreshToken = refreshToken) + } + } + + override suspend fun clear() { + dataStore.updateData { + it.copy(accessToken = "", refreshToken = "") + } + } +} diff --git a/core/datastore/src/main/java/com/twix/datastore/DataStore.kt b/core/datastore/src/main/java/com/twix/datastore/DataStore.kt new file mode 100644 index 00000000..a98f6396 --- /dev/null +++ b/core/datastore/src/main/java/com/twix/datastore/DataStore.kt @@ -0,0 +1,10 @@ +package com.twix.datastore + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.dataStore + +internal val Context.authDataStore: DataStore by dataStore( + fileName = "auth-configure.json", + serializer = AuthConfigureSerializer, +) diff --git a/core/datastore/src/main/java/com/twix/datastore/di/DataStoreModule.kt b/core/datastore/src/main/java/com/twix/datastore/di/DataStoreModule.kt new file mode 100644 index 00000000..3c0dae11 --- /dev/null +++ b/core/datastore/src/main/java/com/twix/datastore/di/DataStoreModule.kt @@ -0,0 +1,10 @@ +package com.twix.datastore.di + +import com.twix.datastore.AuthTokenProvider +import com.twix.token.TokenProvider +import org.koin.dsl.module + +val dataStoreModule = + module { + single { AuthTokenProvider(get()) } + } diff --git a/core/token/.gitignore b/core/token/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/core/token/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/core/token/build.gradle.kts b/core/token/build.gradle.kts new file mode 100644 index 00000000..ba7b83cc --- /dev/null +++ b/core/token/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + alias(libs.plugins.twix.java.library) +} diff --git a/core/token/consumer-rules.pro b/core/token/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/core/token/proguard-rules.pro b/core/token/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/core/token/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/token/src/main/java/com/twix/token/TokenProvider.kt b/core/token/src/main/java/com/twix/token/TokenProvider.kt new file mode 100644 index 00000000..8d225b25 --- /dev/null +++ b/core/token/src/main/java/com/twix/token/TokenProvider.kt @@ -0,0 +1,14 @@ +package com.twix.token + +interface TokenProvider { + suspend fun accessToken(): String + + suspend fun refreshToken(): String + + suspend fun saveToken( + accessToken: String, + refreshToken: String, + ) + + suspend fun clear() +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 57f800f0..e5f0d17e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ kotlinx-serialization-json = "1.9.0" # AndroidX androidx-core-ktx = "1.17.0" androidx-lifecycle-runtime-ktx = "2.10.0" +androidx-datastore = "1.2.0" # Google material = "1.13.0" @@ -71,6 +72,7 @@ appcompat = "1.7.1" # AndroidX androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "androidx-lifecycle-runtime-ktx" } +androidx-datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" } # CameraX androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraX" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 05195c9d..718291c1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -37,4 +37,6 @@ include(":core:network") include(":core:analytics") include(":feature:main") include(":feature:task-certification") +include(":core:datastore") +include(":core:token") include(":core:result")