diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml new file mode 100644 index 0000000..1424a5e --- /dev/null +++ b/.github/auto_assign.yml @@ -0,0 +1,9 @@ +addAssignees: author + +addReviewers: true + +reviewers: + - vvan2 + - sonms + - seungjae708 + - dmp100 diff --git a/.github/ISSUE_TEMPLATE/pull_request_template.md b/.github/pull_request_template.md similarity index 100% rename from .github/ISSUE_TEMPLATE/pull_request_template.md rename to .github/pull_request_template.md diff --git a/.github/workflows/auto_assign_action.yml b/.github/workflows/auto_assign_action.yml new file mode 100644 index 0000000..721a0f9 --- /dev/null +++ b/.github/workflows/auto_assign_action.yml @@ -0,0 +1,13 @@ +name: "Auto Assign and Reviewers" +on: + pull_request: + types: [opened, ready_for_review] + +jobs: + add-reviewers-and-assignees: + runs-on: ubuntu-latest + steps: + - name: Assign author and add reviewers + uses: kentaro-m/auto-assign-action@v2.0.0 + with: + configuration-path: '.github/auto_assign.yml' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 0000000..371f2e2 --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/deviceManager.xml b/.idea/deviceManager.xml new file mode 100644 index 0000000..91f9558 --- /dev/null +++ b/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..c42ee85 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,81 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import java.util.Properties + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.dagger.hilt) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.devtools.ksp) +} + +val properties = Properties().apply { + load(project.rootProject.file("local.properties").inputStream()) +} + + +android { + namespace = "com.kiero" + compileSdk = libs.versions.compileSdk.get().toInt() + + defaultConfig { + applicationId = "com.Kiero" + minSdk = libs.versions.minSdk.get().toInt() + targetSdk = libs.versions.targetSdk.get().toInt() + versionCode = libs.versions.versionCode.get().toInt() + versionName = libs.versions.versionName.get() + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + buildConfigField("String", "BASE_URL", properties["base.url"].toString()) + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } + buildFeatures { + compose = true + buildConfig = true + } +} + +dependencies { + testImplementation(libs.junit) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.bundles.test) + + debugImplementation(libs.bundles.debug) + + implementation(libs.bundles.androidx) + implementation(platform(libs.androidx.compose.bom)) + + implementation(libs.kotlinx.immutable) + + implementation(platform(libs.okhttp.bom)) + implementation(libs.bundles.okhttp) + implementation(libs.bundles.retrofit) + implementation(libs.kotlinx.serialization.json) + + implementation(libs.bundles.hilt) + ksp(libs.hilt.compiler) + + implementation(libs.coil.compose) + + implementation(libs.timber) + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/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/app/src/androidTest/java/com/kiero/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/kiero/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..c490b9d --- /dev/null +++ b/app/src/androidTest/java/com/kiero/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.kiero + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.Kiero", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2645079 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/kiero/KieroApplication.kt b/app/src/main/java/com/kiero/KieroApplication.kt new file mode 100644 index 0000000..b084382 --- /dev/null +++ b/app/src/main/java/com/kiero/KieroApplication.kt @@ -0,0 +1,26 @@ +package com.kiero + +import android.app.Application +import androidx.appcompat.app.AppCompatDelegate +import dagger.hilt.android.HiltAndroidApp +import timber.log.Timber + +@HiltAndroidApp +class KieroApplication : Application() { + override fun onCreate() { + super.onCreate() + setTimber() + setDayMode() + } + + private fun setTimber() { + if (BuildConfig.DEBUG) { + Timber.Forest.plant(Timber.DebugTree()) + } + } + + private fun setDayMode() { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/common/extension/ModifierExt.kt b/app/src/main/java/com/kiero/core/common/extension/ModifierExt.kt new file mode 100644 index 0000000..bc877b9 --- /dev/null +++ b/app/src/main/java/com/kiero/core/common/extension/ModifierExt.kt @@ -0,0 +1,16 @@ +package com.kiero.core.common.extension + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed + +fun Modifier.noRippleClickable(onClick: () -> Unit): Modifier = composed { + this.clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + onClick() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/common/util/HandleError.kt b/app/src/main/java/com/kiero/core/common/util/HandleError.kt new file mode 100644 index 0000000..8c00884 --- /dev/null +++ b/app/src/main/java/com/kiero/core/common/util/HandleError.kt @@ -0,0 +1,14 @@ +package com.kiero.core.common.util + +import java.io.IOException +import java.net.UnknownHostException +import java.util.concurrent.TimeoutException + +fun handleError(throwable: Throwable): String { + return when (throwable) { + is TimeoutException -> "네트워크 시간이 초과되었습니다. 다시 시도해주세요." + is UnknownHostException -> "서버에 연결할 수 없습니다. 인터넷 연결을 확인하세요." + is IOException -> "네트워크 연결에 문제가 발생했습니다. 다시 시도하세요." + else -> "알 수 없는 오류가 발생했습니다. 잠시 후 다시 시도하세요." + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/common/util/SuspendRunCatching.kt b/app/src/main/java/com/kiero/core/common/util/SuspendRunCatching.kt new file mode 100644 index 0000000..0f2ccf7 --- /dev/null +++ b/app/src/main/java/com/kiero/core/common/util/SuspendRunCatching.kt @@ -0,0 +1,19 @@ +package com.kiero.core.common.util + +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.ensureActive +import kotlin.coroutines.cancellation.CancellationException +import kotlin.coroutines.coroutineContext + +suspend inline fun suspendRunCatching(block: suspend () -> R): Result { + return try { + Result.success(block()) + } catch (t: TimeoutCancellationException) { + Result.failure(t) + } catch (c: CancellationException) { + throw c + } catch (e: Throwable) { + coroutineContext.ensureActive() + Result.failure(e) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/designsystem/theme/Color.kt b/app/src/main/java/com/kiero/core/designsystem/theme/Color.kt new file mode 100644 index 0000000..89a5fe1 --- /dev/null +++ b/app/src/main/java/com/kiero/core/designsystem/theme/Color.kt @@ -0,0 +1,11 @@ +package com.kiero.core.designsystem.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/designsystem/theme/Theme.kt b/app/src/main/java/com/kiero/core/designsystem/theme/Theme.kt new file mode 100644 index 0000000..2dfb2a2 --- /dev/null +++ b/app/src/main/java/com/kiero/core/designsystem/theme/Theme.kt @@ -0,0 +1,57 @@ +package com.kiero.core.designsystem.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun KieroTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/designsystem/theme/Type.kt b/app/src/main/java/com/kiero/core/designsystem/theme/Type.kt new file mode 100644 index 0000000..bc262cf --- /dev/null +++ b/app/src/main/java/com/kiero/core/designsystem/theme/Type.kt @@ -0,0 +1,35 @@ +package com.kiero.core.designsystem.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) + diff --git a/app/src/main/java/com/kiero/core/model/UiState.kt b/app/src/main/java/com/kiero/core/model/UiState.kt new file mode 100644 index 0000000..c39e06c --- /dev/null +++ b/app/src/main/java/com/kiero/core/model/UiState.kt @@ -0,0 +1,18 @@ +package com.kiero.core.model + +import androidx.compose.runtime.Stable + +@Stable +sealed interface UiState { + data object Empty : UiState + + data object Loading : UiState + + data class Success( + val data: T, + ) : UiState + + data class Failure( + val message: String, + ) : UiState +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/navigation/MainTabRoute.kt b/app/src/main/java/com/kiero/core/navigation/MainTabRoute.kt new file mode 100644 index 0000000..b64ec68 --- /dev/null +++ b/app/src/main/java/com/kiero/core/navigation/MainTabRoute.kt @@ -0,0 +1,3 @@ +package com.kiero.core.navigation + +interface MainTabRoute : Route \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/navigation/Route.kt b/app/src/main/java/com/kiero/core/navigation/Route.kt new file mode 100644 index 0000000..d68c79f --- /dev/null +++ b/app/src/main/java/com/kiero/core/navigation/Route.kt @@ -0,0 +1,3 @@ +package com.kiero.core.navigation + +interface Route \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/network/di/NetworkModule.kt b/app/src/main/java/com/kiero/core/network/di/NetworkModule.kt new file mode 100644 index 0000000..b3735af --- /dev/null +++ b/app/src/main/java/com/kiero/core/network/di/NetworkModule.kt @@ -0,0 +1,70 @@ +package com.kiero.core.network.di + +import com.kiero.BuildConfig +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Converter +import retrofit2.Retrofit +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object NetworkModule { + + @Provides + @Singleton + fun providesLoggingInterceptor() = HttpLoggingInterceptor().apply { + level = if (BuildConfig.DEBUG) { + HttpLoggingInterceptor.Level.BODY + } else { + HttpLoggingInterceptor.Level.NONE + } + } + + @Provides + @Singleton + fun providesOkHttpClient( + loggingInterceptor: HttpLoggingInterceptor, + ): OkHttpClient = OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .addInterceptor(loggingInterceptor) + .build() + + + /* + Test 용 Setting 입니다 + */ + @Provides + @Singleton + fun providesJson(): Json = Json { + ignoreUnknownKeys = true + coerceInputValues = true + isLenient = true + prettyPrint = false + encodeDefaults = true + } + + @Provides + @Singleton + fun providesConverterFactory(json: Json): Converter.Factory = + json.asConverterFactory("application/json".toMediaType()) + @Provides + @Singleton + fun providesRetrofit( + client: OkHttpClient, + converterFactory: Converter.Factory, + ): Retrofit = Retrofit.Builder() + .baseUrl(BuildConfig.BASE_URL) + .addConverterFactory(converterFactory) + .client(client) + .build() +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/core/network/model/BaseResponse.kt b/app/src/main/java/com/kiero/core/network/model/BaseResponse.kt new file mode 100644 index 0000000..3b013fd --- /dev/null +++ b/app/src/main/java/com/kiero/core/network/model/BaseResponse.kt @@ -0,0 +1,15 @@ +package com.kiero.core.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BaseResponse( + @SerialName("code") + val code: String, + @SerialName("message") + val message: String, + @SerialName("data") + val data: T, +) +// TODO : 명세서 확인 후 수정 예정 diff --git a/app/src/main/java/com/kiero/core/network/model/DummyBaseResponse.kt b/app/src/main/java/com/kiero/core/network/model/DummyBaseResponse.kt new file mode 100644 index 0000000..172771e --- /dev/null +++ b/app/src/main/java/com/kiero/core/network/model/DummyBaseResponse.kt @@ -0,0 +1,18 @@ +package com.kiero.core.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class DummyBaseResponse( + @SerialName("data") + val data: T, + @SerialName("page") + val page: Int? = null, + @SerialName("per_page") + val perPage: Int? = null, + @SerialName("total") + val total: Int? = null, + @SerialName("total_pages") + val totalPages: Int? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/auth/mapper/DummyMapper.kt b/app/src/main/java/com/kiero/data/auth/mapper/DummyMapper.kt new file mode 100644 index 0000000..b15e89f --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/mapper/DummyMapper.kt @@ -0,0 +1,28 @@ +package com.kiero.data.auth.mapper + +import com.kiero.data.auth.remote.dto.response.DummyResponseDto +import com.kiero.data.auth.model.DummyEntity +import javax.inject.Inject + +class DummyMapper @Inject constructor() { + fun mapDtoToEntity(dto : DummyResponseDto) : DummyEntity { + return DummyEntity( + profile = dto.avatar, + firstName = dto.firstName, + id = dto.id, + lastName = dto.lastName, + ) + } + + fun mapEntityToDto(entity : DummyEntity) : DummyResponseDto { + return DummyResponseDto( + avatar = entity.profile, + firstName = entity.firstName, + id = entity.id, + lastName = entity.lastName, + email = "" + ) + } +} + + diff --git a/app/src/main/java/com/kiero/data/auth/model/DummyEntity.kt b/app/src/main/java/com/kiero/data/auth/model/DummyEntity.kt new file mode 100644 index 0000000..b67a9c8 --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/model/DummyEntity.kt @@ -0,0 +1,8 @@ +package com.kiero.data.auth.model + +data class DummyEntity( + val profile: String, + val firstName: String, + val id: Int, + val lastName: String, +) diff --git a/app/src/main/java/com/kiero/data/auth/remote/api/DummyService.kt b/app/src/main/java/com/kiero/data/auth/remote/api/DummyService.kt new file mode 100644 index 0000000..d2f3ed4 --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/remote/api/DummyService.kt @@ -0,0 +1,15 @@ +package com.kiero.data.auth.remote.api + +import com.kiero.core.network.model.DummyBaseResponse +import com.kiero.data.auth.remote.dto.response.DummyResponseDto +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.Query + +interface DummyService { + @GET("api/users") + suspend fun getDummyLists( + @Header("x-api-key") apiKey: String = "reqres-free-v1", + @Query("page") page: Int = 2, + ): DummyBaseResponse> +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/auth/remote/datasource/DummyDataSource.kt b/app/src/main/java/com/kiero/data/auth/remote/datasource/DummyDataSource.kt new file mode 100644 index 0000000..c67ce24 --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/remote/datasource/DummyDataSource.kt @@ -0,0 +1,8 @@ +package com.kiero.data.auth.remote.datasource + +import com.kiero.core.network.model.DummyBaseResponse +import com.kiero.data.auth.remote.dto.response.DummyResponseDto + +interface DummyDataSource { + suspend fun getDummyList(): DummyBaseResponse> +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/auth/remote/datasourceimpl/DummyDataSourceImpl.kt b/app/src/main/java/com/kiero/data/auth/remote/datasourceimpl/DummyDataSourceImpl.kt new file mode 100644 index 0000000..9dc7159 --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/remote/datasourceimpl/DummyDataSourceImpl.kt @@ -0,0 +1,14 @@ +package com.kiero.data.auth.remote.datasourceimpl + +import com.kiero.core.network.model.DummyBaseResponse +import com.kiero.data.auth.remote.api.DummyService +import com.kiero.data.auth.remote.datasource.DummyDataSource +import com.kiero.data.auth.remote.dto.response.DummyResponseDto +import javax.inject.Inject + +class DummyDataSourceImpl @Inject constructor( + private val dummyService: DummyService, +) : DummyDataSource { + override suspend fun getDummyList(): DummyBaseResponse> = + dummyService.getDummyLists() +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/auth/remote/dto/request/DummyRequestDto.kt b/app/src/main/java/com/kiero/data/auth/remote/dto/request/DummyRequestDto.kt new file mode 100644 index 0000000..d5a7b9c --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/remote/dto/request/DummyRequestDto.kt @@ -0,0 +1,4 @@ +package com.kiero.data.auth.remote.dto.request + +class DummyRequestDto { +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/auth/remote/dto/response/DummyResponseDto.kt b/app/src/main/java/com/kiero/data/auth/remote/dto/response/DummyResponseDto.kt new file mode 100644 index 0000000..f636dea --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/remote/dto/response/DummyResponseDto.kt @@ -0,0 +1,18 @@ +package com.kiero.data.auth.remote.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class DummyResponseDto( + @SerialName("id") + val id: Int, + @SerialName("email") + val email: String, + @SerialName("first_name") + val firstName: String, + @SerialName("last_name") + val lastName: String, + @SerialName("avatar") + val avatar: String +) \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/auth/repository/DummyRepository.kt b/app/src/main/java/com/kiero/data/auth/repository/DummyRepository.kt new file mode 100644 index 0000000..f24d309 --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/repository/DummyRepository.kt @@ -0,0 +1,7 @@ +package com.kiero.data.auth.repository + +import com.kiero.data.auth.model.DummyEntity + +interface DummyRepository { + suspend fun getDummyList(): Result> +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/auth/repositoryimpl/DummyRepositoryImpl.kt b/app/src/main/java/com/kiero/data/auth/repositoryimpl/DummyRepositoryImpl.kt new file mode 100644 index 0000000..cce078c --- /dev/null +++ b/app/src/main/java/com/kiero/data/auth/repositoryimpl/DummyRepositoryImpl.kt @@ -0,0 +1,19 @@ +package com.kiero.data.auth.repositoryimpl + +import com.kiero.core.common.util.suspendRunCatching +import com.kiero.data.auth.mapper.DummyMapper +import com.kiero.data.auth.remote.datasource.DummyDataSource +import com.kiero.data.auth.model.DummyEntity +import com.kiero.data.auth.repository.DummyRepository +import javax.inject.Inject + + +class DummyRepositoryImpl @Inject constructor( + private val dummyDataSource: DummyDataSource, + private val mapper: DummyMapper, +) : DummyRepository { + override suspend fun getDummyList(): Result> = suspendRunCatching { + dummyDataSource.getDummyList().data.map { mapper.mapDtoToEntity(it) } + } +} + diff --git a/app/src/main/java/com/kiero/data/di/DataSourceModule.kt b/app/src/main/java/com/kiero/data/di/DataSourceModule.kt new file mode 100644 index 0000000..77a2f80 --- /dev/null +++ b/app/src/main/java/com/kiero/data/di/DataSourceModule.kt @@ -0,0 +1,20 @@ +package com.kiero.data.di + +import com.kiero.data.auth.remote.datasource.DummyDataSource +import com.kiero.data.auth.remote.datasourceimpl.DummyDataSourceImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + + +@Module +@InstallIn(SingletonComponent::class) +abstract class DummyDataSourceModule { + @Binds + @Singleton + abstract fun bindDummyDataSource( + dummyDataSourceImpl: DummyDataSourceImpl, + ): DummyDataSource +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/di/RepositoryModule.kt b/app/src/main/java/com/kiero/data/di/RepositoryModule.kt new file mode 100644 index 0000000..0311472 --- /dev/null +++ b/app/src/main/java/com/kiero/data/di/RepositoryModule.kt @@ -0,0 +1,21 @@ +package com.kiero.data.di + +import com.kiero.data.auth.repositoryimpl.DummyRepositoryImpl +import com.kiero.data.auth.repository.DummyRepository +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +interface RepositoryModule { + + @Binds + @Singleton + fun bindsDummyRepository( + dummyRepositoryImpl: DummyRepositoryImpl + ): DummyRepository + +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/di/ServiceModule.kt b/app/src/main/java/com/kiero/data/di/ServiceModule.kt new file mode 100644 index 0000000..3f8b3d3 --- /dev/null +++ b/app/src/main/java/com/kiero/data/di/ServiceModule.kt @@ -0,0 +1,20 @@ +package com.kiero.data.di + +import com.kiero.data.auth.remote.api.DummyService +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import retrofit2.Retrofit +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object ServiceModule { + + @Provides + @Singleton + fun providesDummyService(retrofit: Retrofit): DummyService = + retrofit.create(DummyService::class.java) + +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/data/kid/model/.gitkeep b/app/src/main/java/com/kiero/data/kid/model/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/kid/repository/.gitkeep b/app/src/main/java/com/kiero/data/kid/repository/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/kid/repositoryimpl/.gitkeep b/app/src/main/java/com/kiero/data/kid/repositoryimpl/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/mapper/.gitkeep b/app/src/main/java/com/kiero/data/parent/mapper/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/model/.gitkeep b/app/src/main/java/com/kiero/data/parent/model/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/remote/api/.gitkeep b/app/src/main/java/com/kiero/data/parent/remote/api/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/remote/datasource/.gitkeep b/app/src/main/java/com/kiero/data/parent/remote/datasource/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/remote/datasourcimpl/.gitkeep b/app/src/main/java/com/kiero/data/parent/remote/datasourcimpl/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/remote/dto/.gitkeep b/app/src/main/java/com/kiero/data/parent/remote/dto/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/remote/dto/reqeust/.gitkeep b/app/src/main/java/com/kiero/data/parent/remote/dto/reqeust/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/remote/dto/response/.gitkeep b/app/src/main/java/com/kiero/data/parent/remote/dto/response/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/data/parent/repository/.gitkeep b/app/src/main/java/com/kiero/data/parent/repository/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/presentation/auth/AuthScreen.kt b/app/src/main/java/com/kiero/presentation/auth/AuthScreen.kt new file mode 100644 index 0000000..fde703d --- /dev/null +++ b/app/src/main/java/com/kiero/presentation/auth/AuthScreen.kt @@ -0,0 +1,117 @@ +package com.kiero.presentation.auth + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.sp +import com.kiero.core.common.extension.noRippleClickable +import com.kiero.core.model.UiState +import com.kiero.core.designsystem.theme.KieroTheme +import com.kiero.data.auth.model.DummyEntity +import com.kiero.presentation.auth.component.DummyItem +import kotlinx.collections.immutable.PersistentList + +@Composable +fun AuthRoute( + paddingValues: PaddingValues, + navigateUp: () -> Unit, + navigateNext: () -> Unit, + state: UiState>, +) { + AuthScreen( + paddingValues = paddingValues, + navigateUp = navigateUp, + navigateNext = navigateNext, + state = state, + modifier = Modifier + .fillMaxSize() + ) +} + +@Composable +fun AuthScreen( + paddingValues: PaddingValues, + navigateUp: () -> Unit, + navigateNext: () -> Unit, + state: UiState>, + modifier: Modifier = Modifier, +) { + LazyColumn( + modifier = modifier + .fillMaxSize() + .padding(paddingValues), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + when (state) { + is UiState.Loading -> { + item { + Text( + modifier = modifier + .noRippleClickable { navigateUp() }, + textAlign = TextAlign.Center, + text = "Dummy", + fontSize = 30.sp + ) + } + } + + is UiState.Empty -> { + item { + Text( + modifier = modifier + .noRippleClickable { navigateUp() }, + textAlign = TextAlign.Center, + text = "Dummy", + fontSize = 30.sp + ) + } + } + + is UiState.Failure -> { + item { + Text( + modifier = modifier + .noRippleClickable { navigateUp() }, + textAlign = TextAlign.Center, + text = state.message, + ) + } + } + + is UiState.Success -> { + items(state.data) { + DummyItem( + id = it.id, + firstName = it.firstName, + lastName = it.lastName, + profileUrl = it.profile, + navigateNext = navigateNext + ) + } + } + } + } +} + +@Preview +@Composable +private fun DummyScreenPreview() { + KieroTheme { + AuthScreen( + paddingValues = PaddingValues(), + navigateUp = {}, + navigateNext = {}, + state = UiState.Loading + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/presentation/auth/component/DummyItem.kt b/app/src/main/java/com/kiero/presentation/auth/component/DummyItem.kt new file mode 100644 index 0000000..f8e649d --- /dev/null +++ b/app/src/main/java/com/kiero/presentation/auth/component/DummyItem.kt @@ -0,0 +1,57 @@ +package com.kiero.presentation.auth.component + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import com.kiero.core.common.extension.noRippleClickable + + +@Composable +fun DummyItem( + id: Int, + firstName: String, + lastName: String, + profileUrl: String, + navigateNext: () -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .padding(16.dp) + .fillMaxWidth() + ) { + AsyncImage( + model = profileUrl, + contentDescription = null, + modifier = Modifier + .size(80.dp) + .clip(CircleShape) + .noRippleClickable { + navigateNext() + }, + contentScale = ContentScale.Crop + ) + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "$firstName $lastName", + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "ID: $id", + ) + } +} diff --git a/app/src/main/java/com/kiero/presentation/auth/model/AuthContract.kt b/app/src/main/java/com/kiero/presentation/auth/model/AuthContract.kt new file mode 100644 index 0000000..19646bc --- /dev/null +++ b/app/src/main/java/com/kiero/presentation/auth/model/AuthContract.kt @@ -0,0 +1,18 @@ +package com.kiero.presentation.auth.model + +import androidx.compose.runtime.Immutable +import com.kiero.core.model.UiState +import com.kiero.data.auth.model.DummyEntity +import kotlinx.collections.immutable.PersistentList + + +@Immutable +data class DummyState( + val uiState: UiState> = UiState.Loading, +) + +sealed class DummySideEffect { + data class ShowSnackBar(val message: String) : DummySideEffect() + data object NavigateUp : DummySideEffect() + data object NavigateNext : DummySideEffect() +} diff --git a/app/src/main/java/com/kiero/presentation/auth/viewmodel/AuthViewModel.kt b/app/src/main/java/com/kiero/presentation/auth/viewmodel/AuthViewModel.kt new file mode 100644 index 0000000..f5ff987 --- /dev/null +++ b/app/src/main/java/com/kiero/presentation/auth/viewmodel/AuthViewModel.kt @@ -0,0 +1,56 @@ +package com.kiero.presentation.auth.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.kiero.core.common.util.handleError +import com.kiero.core.model.UiState +import com.kiero.data.auth.repository.DummyRepository +import com.kiero.presentation.auth.model.DummySideEffect +import com.kiero.presentation.auth.model.DummyState + +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class AuthViewModel @Inject constructor( + private val dummyRepository: DummyRepository, +) : ViewModel() { + private val _state = MutableStateFlow(DummyState()) + val state: StateFlow = _state.asStateFlow() + + private val _sideEffect = MutableSharedFlow() + val sideEffect: MutableSharedFlow = _sideEffect + + fun getDummyList() = viewModelScope.launch { + dummyRepository.getDummyList() + .onSuccess { + _state.value = _state.value.copy( + uiState = UiState.Success(it.toPersistentList()) + ) + }.onFailure { throwable -> + val errorMessage = handleError(throwable) + _state.value = _state.value.copy( + uiState = UiState.Failure(errorMessage) + ) + showSnackBar(errorMessage) + } + } + + private fun showSnackBar(message: String) = viewModelScope.launch { + _sideEffect.emit(DummySideEffect.ShowSnackBar(message)) + } + + fun navigateUp() = viewModelScope.launch { + _sideEffect.emit(DummySideEffect.NavigateUp) + } + + fun navigateNext() = viewModelScope.launch { + _sideEffect.emit(DummySideEffect.NavigateNext) + } +} diff --git a/app/src/main/java/com/kiero/presentation/kid/.gitkeep b/app/src/main/java/com/kiero/presentation/kid/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/kiero/presentation/main/MainActivity.kt b/app/src/main/java/com/kiero/presentation/main/MainActivity.kt new file mode 100644 index 0000000..c4de60b --- /dev/null +++ b/app/src/main/java/com/kiero/presentation/main/MainActivity.kt @@ -0,0 +1,42 @@ +package com.kiero.presentation.main + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.kiero.core.designsystem.theme.KieroTheme +import com.kiero.presentation.auth.AuthRoute +import com.kiero.presentation.auth.viewmodel.AuthViewModel +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + private val viewModel: AuthViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + + setContent { + KieroTheme { + val state by viewModel.state.collectAsStateWithLifecycle() + + LaunchedEffect(Unit) { + viewModel.getDummyList() + } + + AuthRoute( + paddingValues = PaddingValues(), + navigateUp = { viewModel.navigateUp() }, + navigateNext = { viewModel.navigateNext() }, + state = state.uiState + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kiero/presentation/parent/.gitkeep b/app/src/main/java/com/kiero/presentation/parent/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..a13294d --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Kiero + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..ca4515e --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +