Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
315ba7c
refactor: MainActivity feature 패키지로 이관
rhkrwngud445 Jul 21, 2025
ce277ee
feat: MainActivity hilt 어노테이션 적용
rhkrwngud445 Jul 21, 2025
47bd2c6
feat: Navigation 생성
rhkrwngud445 Jul 22, 2025
2a47535
feat: NearApp 분리
rhkrwngud445 Jul 22, 2025
5562dc2
refactor: MainActivity feature.main 패키지로 이동
rhkrwngud445 Jul 22, 2025
ca87964
chore: navigation 종속성 추가
rhkrwngud445 Jul 22, 2025
b770ae9
chore: serialization 종속성 추가
rhkrwngud445 Jul 22, 2025
d3099fb
feat: home 예시 state 구성
rhkrwngud445 Jul 22, 2025
5df5686
feat: home 화면 에시 코드 작성
rhkrwngud445 Jul 22, 2025
fe95db8
docs: NearNavHost 주석 추가
rhkrwngud445 Jul 22, 2025
43844d4
refactor: presentation 및 데이터, 네트워크 모듈 분리
rhkrwngud445 Jul 22, 2025
d04d285
feat: repository example 추가
rhkrwngud445 Jul 22, 2025
d946ac8
feat: model 패키지 생성
rhkrwngud445 Jul 22, 2025
b178139
feat: example 모델 예시 추가
rhkrwngud445 Jul 23, 2025
cb59eb0
feat: 데이터 로딩 흐름 예시 추가
rhkrwngud445 Jul 23, 2025
d4d2e85
feat: viewModel 단일 초기화 예시 추가
rhkrwngud445 Jul 23, 2025
d007f8b
feat: snackbar 호출로직 구성
rhkrwngud445 Jul 23, 2025
a05c412
feat: pretendard font 리소스 추가
rhkrwngud445 Jul 26, 2025
10a228d
feat: 디자인 시스템 color 추가
rhkrwngud445 Jul 26, 2025
1376287
feat: color 스펠링 suppress 적용
rhkrwngud445 Jul 26, 2025
29d527b
feat: 폰트 구성
rhkrwngud445 Jul 26, 2025
802387b
feat: Near 테마 구성
rhkrwngud445 Jul 26, 2025
fc66dfa
feat: Typography lineHeight 수정
rhkrwngud445 Jul 27, 2025
f12d999
feat: NearBasicButton 추가
rhkrwngud445 Jul 27, 2025
7f71b9a
feat: NearBasicButton 색상 및 enable 속성 추가
rhkrwngud445 Jul 27, 2025
f08fcf5
feat: SolidTypeButton 추가
rhkrwngud445 Jul 27, 2025
c22dc6b
feat: LineTypeButton 추가
rhkrwngud445 Jul 27, 2025
f3777e5
feat: NearTextField 작업
rhkrwngud445 Jul 28, 2025
2db33d8
refactor: NearOutlinedTextFieldDecorationBox 분리
rhkrwngud445 Jul 28, 2025
02544f9
refactor: internal 패키지 생성 및 내부 컴포넌트 이관
rhkrwngud445 Jul 28, 2025
b87ee6f
feat: LimitedTextField 추가
rhkrwngud445 Jul 29, 2025
a985b88
feat: Checkbox 추가
rhkrwngud445 Jul 29, 2025
e0d3c8b
feat: Radio Button 추가
rhkrwngud445 Jul 29, 2025
08460a5
feat: toggle button 추가
rhkrwngud445 Jul 29, 2025
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