Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix api version, add basic architecture structure #3

Merged
merged 5 commits into from
Jul 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# AProSelection

[![Android CI](https://github.com/stslex/AProSelection/actions/workflows/android_build.yml/badge.svg)](https://github.com/stslex/AProSelection/actions/workflows/android_build.yml)
16 changes: 1 addition & 15 deletions app/src/main/java/com/stslex/aproselection/ui/InitialApp.kt
Original file line number Diff line number Diff line change
@@ -1,28 +1,14 @@
package com.stslex.aproselection.ui

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.compose.rememberNavController
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.stslex.aproselection.navigation.NavigationHost
import com.stslex.aproselection.core.ui.theme.AppTheme
import com.stslex.aproselection.navigation.NavigationHost

@Composable
fun InitialApp() {
val navController = rememberNavController()
val systemUiController = rememberSystemUiController()
val isDarkTheme = isSystemInDarkTheme()

DisposableEffect(systemUiController, isDarkTheme) {
systemUiController.setSystemBarsColor(
color = Color.Transparent,
darkIcons = isDarkTheme.not(),
)
onDispose {}
}

NavigationHost(navController = navController)
}
Expand Down
4 changes: 0 additions & 4 deletions app/src/main/java/com/stslex/aproselection/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ package com.stslex.aproselection.ui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.core.view.WindowCompat
import com.stslex.aproselection.core.ui.theme.AppTheme

class MainActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

WindowCompat.setDecorFitsSystemWindows(window, false)

setContent {
AppTheme {
InitialApp()
Expand Down
3 changes: 3 additions & 0 deletions core/network/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ val key = properties["API_KEY"]?.toString()
?: throw IllegalStateException("API_KEY")
val apiHost = properties["API_SERVER_HOST"]?.toString()
?: throw IllegalStateException("API_SERVER_HOST")
val apiVersion = properties["API_VERSION"]?.toString()
?: throw IllegalStateException("API_VERSION")

android {
defaultConfig {
buildConfigField("String", "API_KEY", key)
buildConfigField("String", "API_SERVER_HOST", apiHost)
buildConfigField("String", "API_VERSION", apiVersion)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import io.ktor.client.plugins.logging.DEFAULT
import io.ktor.client.plugins.logging.LogLevel
import io.ktor.client.plugins.logging.Logger
import io.ktor.client.plugins.logging.Logging
import io.ktor.client.request.bearerAuth
import io.ktor.http.URLProtocol
import io.ktor.http.encodedPath
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
Expand Down Expand Up @@ -43,21 +45,11 @@ class NetworkClientImpl : NetworkClient {
get() = client.config {
defaultRequest {
url {
host = "${BuildConfig.API_SERVER_HOST}$HOST_API_URL"
host = BuildConfig.API_SERVER_HOST
encodedPath = BuildConfig.API_VERSION
protocol = URLProtocol.HTTP
}
// headers {
// append(
// HEADER_AUTH,
// "$HEADER_AUTH_FIELD ${BuildConfig.API_KEY}"
// )
// }
bearerAuth(BuildConfig.API_KEY)
}
}

companion object {
private const val HOST_API_URL = "/api/v1"
private const val HEADER_AUTH = "Authorization"
private const val HEADER_AUTH_FIELD = "Client-ID"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stslex.aproselection.core.network.clients.auth

import com.stslex.aproselection.core.network.clients.auth.model.HelloRequestModel

interface AuthNetworkClient {

suspend fun getHello(username: String): HelloRequestModel
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.stslex.aproselection.core.network.clients.auth

import com.stslex.aproselection.core.network.client.NetworkClient
import com.stslex.aproselection.core.network.clients.auth.model.HelloRequestModel
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.http.appendPathSegments
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class AuthNetworkClientImpl(
private val networkClient: NetworkClient
) : AuthNetworkClient {

override suspend fun getHello(
username: String
): HelloRequestModel = withContext(Dispatchers.IO) {
networkClient
.apiClient
.get {
url.appendPathSegments("hello", username)
}
.body()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.stslex.aproselection.core.network.clients.auth.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class HelloRequestModel(
@SerialName("text")
val text: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.stslex.aproselection.core.network.di

import com.stslex.aproselection.core.network.client.NetworkClient
import com.stslex.aproselection.core.network.client.NetworkClientImpl
import com.stslex.aproselection.core.network.clients.auth.AuthNetworkClient
import com.stslex.aproselection.core.network.clients.auth.AuthNetworkClientImpl
import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
Expand All @@ -10,5 +12,6 @@ object ModuleCoreNetwork {

val moduleCoreNetwork = module {
singleOf(::NetworkClientImpl) { bind<NetworkClient>() }
singleOf(::AuthNetworkClientImpl) { bind<AuthNetworkClient>() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.stslex.aproselection.core.ui.base

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn

open class BaseViewModel : ViewModel() {

fun <T> Flow<T>.stateIn(
initialValue: T
): StateFlow<T> = this.stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = initialValue
)

fun handleError(throwable: Throwable) {
Log.e(javaClass.simpleName, throwable.message, throwable)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.toArgb
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import com.google.accompanist.systemuicontroller.rememberSystemUiController

private val DarkColorScheme = darkColorScheme(
primary = Purple80,
Expand Down Expand Up @@ -55,10 +56,19 @@ fun AppTheme(
}
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.statusBarColor = colorScheme.primary.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
val window = (view.context as Activity).window
val systemUiController = rememberSystemUiController()
val isDarkTheme = isSystemInDarkTheme()

DisposableEffect(systemUiController, isDarkTheme) {
WindowCompat.setDecorFitsSystemWindows(window, false)
systemUiController.setSystemBarsColor(
color = Color.Transparent,
darkIcons = isDarkTheme.not(),
)
onDispose {
WindowCompat.setDecorFitsSystemWindows(window, true)
}
}
}

Expand Down
3 changes: 0 additions & 3 deletions feature/auth/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
plugins {
id("aproselection.android.library")
id("aproselection.android.library.compose")
kotlin("plugin.serialization")
}

dependencies {
implementation(project(":core:ui"))
implementation(project(":core:network"))
implementation(libs.bundles.ktor)
implementation(libs.bundles.okhttp)
}

android.namespace = "com.stslex.aproselection.feature.auth"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stslex.aproselection.feature.auth.data.repository

import kotlinx.coroutines.flow.Flow

interface AuthRepository {

fun getHello(username: String): Flow<String>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.stslex.aproselection.feature.auth.data.repository

import com.stslex.aproselection.core.network.clients.auth.AuthNetworkClient
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

class AuthRepositoryImpl(
private val networkClient: AuthNetworkClient
) : AuthRepository {

override fun getHello(username: String): Flow<String> = flow {
val helloResponse = networkClient
.getHello(username = username)
.text
emit(helloResponse)
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package com.stslex.aproselection.feature.auth.di

import com.stslex.aproselection.feature.auth.data.repository.AuthRepository
import com.stslex.aproselection.feature.auth.data.repository.AuthRepositoryImpl
import com.stslex.aproselection.feature.auth.domain.interactor.AuthInteractor
import com.stslex.aproselection.feature.auth.domain.interactor.AuthInteractorImpl
import com.stslex.aproselection.feature.auth.ui.AuthViewModel
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.factoryOf
import org.koin.dsl.module

object ModuleFeatureAuth {

val moduleFeatureAuth = module {
viewModelOf(::AuthViewModel)
factoryOf(::AuthInteractorImpl) { bind<AuthInteractor>() }
factoryOf(::AuthRepositoryImpl) { bind<AuthRepository>() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.stslex.aproselection.feature.auth.domain.interactor

import kotlinx.coroutines.flow.Flow

interface AuthInteractor {

fun getHello(username: String): Flow<String>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.stslex.aproselection.feature.auth.domain.interactor

import com.stslex.aproselection.feature.auth.data.repository.AuthRepository
import kotlinx.coroutines.flow.Flow

class AuthInteractorImpl(
private val repository: AuthRepository
) : AuthInteractor {

override fun getHello(
username: String
): Flow<String> = repository.getHello(
username = username
)
}
Loading