Skip to content
Closed
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
5 changes: 5 additions & 0 deletions Near/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.hilt.application)
alias(libs.plugins.kotlin.kapt)
alias(libs.plugins.kotlin.serialization)
}

android {
Expand Down Expand Up @@ -73,4 +74,8 @@ dependencies {
implementation(libs.room.ktx)
kapt(libs.room.compiler)
implementation(libs.room.paging)
// Navigation
implementation(libs.navigation.compose)
// Serialization
implementation(libs.kotlin.serialization.json)
}
4 changes: 2 additions & 2 deletions Near/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
android:theme="@style/Theme.Near"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:name=".presentation.feature.main.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Near">
Expand All @@ -26,4 +26,4 @@
</activity>
</application>

</manifest>
</manifest>
50 changes: 0 additions & 50 deletions Near/app/src/main/java/com/alarmy/near/MainActivity.kt

This file was deleted.

17 changes: 17 additions & 0 deletions Near/app/src/main/java/com/alarmy/near/data/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.alarmy.near.data.di

import com.alarmy.near.data.repository.ExampleRepository
import com.alarmy.near.data.repository.ExampleRepositoryImpl
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
abstract fun bindExampleRepository(exampleRepositoryImpl: ExampleRepositoryImpl): ExampleRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.alarmy.near.data.mapper

import com.alarmy.near.model.Example
import com.alarmy.near.network.response.ExampleEntity

fun ExampleEntity.toModel(): Example =
Example(
id = id.toString(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.alarmy.near.data.repository

import com.alarmy.near.model.Example
import kotlinx.coroutines.flow.Flow

interface ExampleRepository {
fun getExampleData(): String

fun getData(): Flow<Example>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.alarmy.near.data.repository

import com.alarmy.near.model.Example
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import javax.inject.Inject

class ExampleRepositoryImpl
@Inject
constructor() : ExampleRepository {
override fun getExampleData(): String = "Hello from Repository"

override fun getData(): Flow<Example> =
flow {
// val result = exampleService.fetchExample()
// emit(result.data.toModel())
}
}
Empty file.
5 changes: 5 additions & 0 deletions Near/app/src/main/java/com/alarmy/near/model/Example.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.alarmy.near.model

data class Example(
val id: String,
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.alarmy.near.di
package com.alarmy.near.network.di

// @Module
// @InstallIn(SingletonComponent::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.alarmy.near.network.response

data class ExampleEntity(
val id: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.alarmy.near.presentation.feature.home

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.alarmy.near.presentation.feature.home.model.HomeUiState
import com.alarmy.near.presentation.ui.theme.NearTheme

@Composable
internal fun HomeRoute(
viewModel: HomeViewModel = hiltViewModel(),
onShowErrorSnackBar: (throwable: Throwable?) -> Unit,
) {
val uiState = viewModel.uiStateFlow.collectAsStateWithLifecycle()
HomeScreen(
uiState = uiState.value,
onContactClick = {},
onRemoveContact = viewModel::removeContact,
)
}

@Composable
internal fun HomeScreen(
modifier: Modifier = Modifier,
uiState: HomeUiState,
onContactClick: (Long) -> Unit = { _ -> },
onRemoveContact: (Long) -> Unit = { _ -> },
) {
Column(modifier = Modifier.fillMaxSize().background(Color.White)) {
Text("홈 화면")
}
}

@Preview
@Composable
internal fun HomeScreenPreview() {
NearTheme {
HomeScreen(
uiState = HomeUiState.Loading,
onContactClick = {},
onRemoveContact = {},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.alarmy.near.presentation.feature.home

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alarmy.near.data.repository.ExampleRepository
import com.alarmy.near.presentation.feature.home.model.HomeUiState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class HomeViewModel
@Inject
constructor(
private val exampleRepository: ExampleRepository,
) : ViewModel() {
// Example: 여러번 초기화되는 StateFlow
private val _uiStateFlow = MutableStateFlow(HomeUiState.Loading)
val uiStateFlow = _uiStateFlow.asStateFlow()

// Example: 한 번만 초기화되는 StateFlow
private val exampleStateFlow =
exampleRepository
.getData()
.map {
// Mapping to UIState
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = HomeUiState.Loading,
)

fun fetchContacts() {
viewModelScope.launch {
exampleRepository
.getData()
.catch {
// handle error
}.collect {
// updateUI
}
}
}

fun removeContact(id: Long) {
// contactRepository.removeContact(id)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.alarmy.near.presentation.feature.home.model

sealed interface HomeUiState {
data object Loading : HomeUiState

data class Success(
val data: Any,
) : HomeUiState
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.alarmy.near.presentation.feature.home.navigation

import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.alarmy.near.presentation.feature.home.HomeRoute
import kotlinx.serialization.Serializable

@Serializable
object RouteHome

/*
* 추후 홈으로 화면 이동이 필요할 때 이 함수를 사용합니다.
* */
fun NavController.navigateToHome(navOptions: NavOptions) {
navigate(RouteHome, navOptions)
}

fun NavGraphBuilder.homeNavGraph(
onShowErrorSnackBar: (throwable: Throwable?) -> Unit,
onClickContact: (id: Long) -> Unit,
) {
composable<RouteHome> { backStackEntry ->
HomeRoute(
onShowErrorSnackBar = onShowErrorSnackBar,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.alarmy.near.presentation.feature.main

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import com.alarmy.near.presentation.ui.theme.NearTheme
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
NearTheme {
NearApp()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.alarmy.near.presentation.feature.main

import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.exclude
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.launch

@Composable
internal fun NearApp(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
) {
val snackBarState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()

Scaffold(
modifier = Modifier.fillMaxSize(),
snackbarHost = {
SnackbarHost(
hostState = snackBarState,
modifier =
Modifier.windowInsetsPadding(
WindowInsets.safeDrawing.exclude(
WindowInsets.ime,
),
),
)
},
) { innerPadding ->
NearNavHost(
modifier = Modifier.padding(innerPadding),
navController = navController,
onShowSnackbar = {
scope.launch {
snackBarState.showSnackbar(
message = it?.message ?: return@launch,
duration = SnackbarDuration.Short,
)
}
},
)
}
}
Loading