diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bc1aecd0..6bf8b6de 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -34,7 +34,7 @@ android { applicationId = "com.doyoonkim.knutice" minSdk = 31 targetSdk = 35 - versionCode = 24 + versionCode = 26 versionName = "1.5.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/doyoonkim/knutice/MainActivity.kt b/app/src/main/java/com/doyoonkim/knutice/MainActivity.kt index 9b2d0dca..3aaa5d24 100644 --- a/app/src/main/java/com/doyoonkim/knutice/MainActivity.kt +++ b/app/src/main/java/com/doyoonkim/knutice/MainActivity.kt @@ -1,6 +1,7 @@ package com.doyoonkim.knutice import android.Manifest +import android.app.AlarmManager import android.content.Intent import android.net.Uri import android.os.Bundle @@ -42,6 +43,9 @@ import com.doyoonkim.common.R import com.doyoonkim.common.di.AppPreferences import com.doyoonkim.common.theme.onAnyBackground import com.doyoonkim.common.theme.variantPurple +import com.doyoonkim.knutice.di.components.DaggerMainActivityComponent +import com.doyoonkim.knutice.di.components.DaggerSplashSceneComponent +import com.doyoonkim.knutice.di.util.DefaultSystemService import com.doyoonkim.main.splash.KnuticeSplashScreen import com.doyoonkim.main.viewmodel.SplashViewModel import com.doyoonkim.notification.local.NotificationAlarmScheduler @@ -50,9 +54,7 @@ import javax.inject.Inject class MainActivity : ComponentActivity() { - @Inject lateinit var viewModelFactory: ViewModelProvider.Factory - @Inject lateinit var notificationAlarmScheduler: NotificationAlarmScheduler - @Inject lateinit var appPreferences: AppPreferences + @Inject lateinit var alarmManager: AlarmManager // NavController private lateinit var navController: NavHostController @@ -60,7 +62,10 @@ class MainActivity : ComponentActivity() { private val receivedIntent = mutableStateOf(null) override fun onCreate(savedInstanceState: Bundle?) { - (applicationContext as MainApplication).appComponent.inject(this) + val appComponent = (application as MainApplication).appComponent + DaggerMainActivityComponent.factory().create(DefaultSystemService(appComponent)) + .inject(this) + super.onCreate(savedInstanceState) receivedIntent.value = intent @@ -76,9 +81,13 @@ class MainActivity : ComponentActivity() { var isPreProcessCompleted by remember { mutableStateOf(false) } if (!isPreProcessCompleted) { + val sceneComponent = remember(appComponent) { + DaggerSplashSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + KnuticeSplashScreen( modifier = Modifier.fillMaxSize(), - viewModel = viewModel(factory = viewModelFactory) + viewModel = viewModel(factory = sceneComponent.viewModelFactory()) ) { result -> if (!result) this.finish() isPreProcessCompleted = true @@ -94,7 +103,7 @@ class MainActivity : ComponentActivity() { permissions.entries.forEach { Log.d("MainServiceScreen", "${it.key}, ${it.value}") if (it.key == Manifest.permission.SCHEDULE_EXACT_ALARM - && !notificationAlarmScheduler.canScheduleExactAlarms()) { + && !alarmManager.canScheduleExactAlarms()) { showPermissionRationale = true } } @@ -114,7 +123,6 @@ class MainActivity : ComponentActivity() { MainServiceScreen( modifier = Modifier, navController = navController, - viewModelFactory = viewModelFactory ) { activity.finish() } if (showPermissionRationale) { diff --git a/app/src/main/java/com/doyoonkim/knutice/MainApplication.kt b/app/src/main/java/com/doyoonkim/knutice/MainApplication.kt index a77d3572..06ef2055 100644 --- a/app/src/main/java/com/doyoonkim/knutice/MainApplication.kt +++ b/app/src/main/java/com/doyoonkim/knutice/MainApplication.kt @@ -4,11 +4,14 @@ import android.app.Application import android.app.NotificationChannel import android.app.NotificationManager import android.os.Build +import android.util.Log import com.doyoonkim.common.di.AppInjector import com.doyoonkim.common.di.AppInjectorProvider import com.doyoonkim.common.R import com.doyoonkim.knutice.di.components.AppComponent import com.doyoonkim.knutice.di.components.DaggerAppComponent +import com.doyoonkim.knutice.di.components.DaggerNotificationServiceComponent +import com.doyoonkim.knutice.di.util.DefaultSystemService import com.doyoonkim.notification.fcm.PushNotificationService import javax.inject.Inject @@ -21,16 +24,21 @@ class MainApplication() : Application(), AppInjectorProvider { override val appInjector: AppInjector = object : AppInjector { override fun inject(target: Any) { when(target) { - is PushNotificationService -> appComponent.inject(target) + is PushNotificationService -> { + DaggerNotificationServiceComponent.factory() + .create(DefaultSystemService(appComponent)).inject(target) + } else -> error("Unsupported Target $target") } } + } @Inject lateinit var notificationManager: NotificationManager override fun onCreate() { super.onCreate() + // Application-Level injection appComponent.inject(this) // Create channel group diff --git a/app/src/main/java/com/doyoonkim/knutice/MainServiceScreen.kt b/app/src/main/java/com/doyoonkim/knutice/MainServiceScreen.kt index 51f235ab..92d4e206 100644 --- a/app/src/main/java/com/doyoonkim/knutice/MainServiceScreen.kt +++ b/app/src/main/java/com/doyoonkim/knutice/MainServiceScreen.kt @@ -13,7 +13,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color @@ -21,7 +20,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import com.doyoonkim.common.R @@ -30,15 +28,12 @@ import com.doyoonkim.common.theme.displayBackground import com.doyoonkim.common.theme.onAnyBackground import com.doyoonkim.common.theme.subTitle import com.doyoonkim.common.theme.title -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow +import com.doyoonkim.knutice.navigation.AppNavHost @Composable fun MainServiceScreen( modifier: Modifier = Modifier, navController: NavHostController, - viewModelFactory: ViewModelProvider.Factory, onExit: () -> Unit ) { @@ -138,7 +133,6 @@ fun MainServiceScreen( modifier = Modifier, contentPadding = contentPadding, navController = navController, - viewModelFactory = viewModelFactory, onExit = onExit ) } diff --git a/app/src/main/java/com/doyoonkim/knutice/di/components/AppComponent.kt b/app/src/main/java/com/doyoonkim/knutice/di/components/AppComponent.kt index 18cb389d..7426faac 100644 --- a/app/src/main/java/com/doyoonkim/knutice/di/components/AppComponent.kt +++ b/app/src/main/java/com/doyoonkim/knutice/di/components/AppComponent.kt @@ -1,49 +1,30 @@ package com.doyoonkim.knutice.di.components +import android.app.AlarmManager import android.app.Application -import com.doyoonkim.bookmark.di.BookmarkModule -import com.doyoonkim.common.di.CommonModule -import com.doyoonkim.data.di.DataBindingModule -import com.doyoonkim.data.di.DataModule -import com.doyoonkim.domain.di.DomainModule -import com.doyoonkim.knutice.MainActivity +import android.app.NotificationManager +import android.content.Context +import android.content.SharedPreferences +import com.doyoonkim.common.di.ApplicationContext import com.doyoonkim.knutice.MainApplication -import com.doyoonkim.knutice.di.AppModule -import com.doyoonkim.knutice.di.DispatcherModule -import com.doyoonkim.knutice.di.ViewModelFactoryModule -import com.doyoonkim.main.di.MainModule -import com.doyoonkim.network.di.NetworkModule -import com.doyoonkim.notification.di.NotificationBindingModule -import com.doyoonkim.notification.di.NotificationModule -import com.doyoonkim.notification.fcm.PushNotificationService +import com.doyoonkim.knutice.di.modules.AppModule import dagger.BindsInstance import dagger.Component -import javax.inject.Singleton -@Singleton @Component( modules = [ - AppModule::class, - DispatcherModule::class, - CommonModule::class, - DataModule::class, - DataBindingModule::class, - DomainModule::class, - NetworkModule::class, - NotificationModule::class, - NotificationBindingModule::class, - BookmarkModule::class, - MainModule::class, - ViewModelFactoryModule::class + AppModule::class ] ) interface AppComponent { fun inject(app: MainApplication) - fun inject(activity: MainActivity) - - fun inject(service: PushNotificationService) + // Provision Functions + @ApplicationContext fun applicationContext(): Context + fun sharedPreference(): SharedPreferences + fun alarmManager(): AlarmManager + fun notificationManager(): NotificationManager @Component.Factory interface Factory { diff --git a/app/src/main/java/com/doyoonkim/knutice/di/components/MainActivityComponent.kt b/app/src/main/java/com/doyoonkim/knutice/di/components/MainActivityComponent.kt new file mode 100644 index 00000000..d6abe190 --- /dev/null +++ b/app/src/main/java/com/doyoonkim/knutice/di/components/MainActivityComponent.kt @@ -0,0 +1,18 @@ +package com.doyoonkim.knutice.di.components + + +import com.doyoonkim.knutice.MainActivity +import com.doyoonkim.knutice.di.util.SystemServices +import dagger.Component + +@Component( + dependencies = [SystemServices::class] +) +interface MainActivityComponent { + fun inject(activity: MainActivity) + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): MainActivityComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/doyoonkim/knutice/di/components/NotificationServiceComponent.kt b/app/src/main/java/com/doyoonkim/knutice/di/components/NotificationServiceComponent.kt new file mode 100644 index 00000000..6d26093b --- /dev/null +++ b/app/src/main/java/com/doyoonkim/knutice/di/components/NotificationServiceComponent.kt @@ -0,0 +1,31 @@ +package com.doyoonkim.knutice.di.components + +import com.doyoonkim.common.di.CommonModule +import com.doyoonkim.data.di.ImageRemoteModule +import com.doyoonkim.data.di.NoticeRemoteModule +import com.doyoonkim.knutice.di.modules.DispatcherModule +import com.doyoonkim.knutice.di.util.SystemServices +import com.doyoonkim.network.di.NotificationNetworkModule +import com.doyoonkim.notification.di.NotificationModule +import com.doyoonkim.notification.fcm.PushNotificationService +import dagger.Component + +@Component( + dependencies = [SystemServices::class], + modules = [ + NotificationModule::class, + DispatcherModule::class, + NoticeRemoteModule::class, + ImageRemoteModule::class, + CommonModule::class, + NotificationNetworkModule::class + ] +) +interface NotificationServiceComponent { + fun inject(service: PushNotificationService) + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): NotificationServiceComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/doyoonkim/knutice/di/components/SceneComponents.kt b/app/src/main/java/com/doyoonkim/knutice/di/components/SceneComponents.kt new file mode 100644 index 00000000..01a646ea --- /dev/null +++ b/app/src/main/java/com/doyoonkim/knutice/di/components/SceneComponents.kt @@ -0,0 +1,245 @@ +package com.doyoonkim.knutice.di.components + +import androidx.lifecycle.ViewModelProvider +import com.doyoonkim.bookmark.di.BookmarkListSceneModule +import com.doyoonkim.bookmark.di.EditBookmarkSceneModule +import com.doyoonkim.data.di.LocalModule +import com.doyoonkim.data.di.NoticeRemoteModule +import com.doyoonkim.data.di.PreferencesRemoteModule +import com.doyoonkim.data.di.TipRemoteModule +import com.doyoonkim.data.di.TokenRemoteModule +import com.doyoonkim.domain.di.BookmarkUseCaseModule +import com.doyoonkim.domain.di.NoticeUseCaseModule +import com.doyoonkim.domain.di.PreProcessingUseCaseModule +import com.doyoonkim.domain.di.PreferencesUseCaseModule +import com.doyoonkim.domain.di.TipUseCaseModule +import com.doyoonkim.knutice.di.modules.DispatcherModule +import com.doyoonkim.knutice.di.modules.ViewModelFactoryModule +import com.doyoonkim.knutice.di.util.SystemServices +import com.doyoonkim.main.di.CustomerServiceSceneModule +import com.doyoonkim.main.di.HomeSceneModule +import com.doyoonkim.main.di.NoticeDetailSceneModule +import com.doyoonkim.main.di.NoticeInCategorySceneModule +import com.doyoonkim.main.di.NoticeSearchSceneModule +import com.doyoonkim.main.di.NotificationPreferencesSceneModule +import com.doyoonkim.main.di.SettingsSceneModule +import com.doyoonkim.main.di.SplashSceneModule +import com.doyoonkim.network.di.NetworkModule +import com.doyoonkim.notification.di.NotificationModule +import dagger.Component + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + HomeSceneModule::class, + NoticeUseCaseModule::class, + TipUseCaseModule::class, + NoticeRemoteModule::class, + TipRemoteModule::class, + NetworkModule::class + ] +) +interface HomeSceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): HomeSceneComponent + } +} + + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + BookmarkListSceneModule::class, + BookmarkUseCaseModule::class, + LocalModule::class + ] +) +interface BookmarkListSceneComponent { + fun getViewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): BookmarkListSceneComponent + } +} + + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + EditBookmarkSceneModule::class, + BookmarkUseCaseModule::class, + NoticeUseCaseModule::class, + NotificationModule::class, + LocalModule::class, + NoticeRemoteModule::class, + NetworkModule::class + ] +) +interface EditBookmarkSceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemService: SystemServices): EditBookmarkSceneComponent + } +} + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + NoticeDetailSceneModule::class, + NoticeUseCaseModule::class, + NoticeRemoteModule::class, + NetworkModule::class + ] +) +interface NoticeDetailSceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): NoticeDetailSceneComponent + } +} + + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + NoticeSearchSceneModule::class, + NoticeUseCaseModule::class, + NoticeRemoteModule::class, + NetworkModule::class + ] +) +interface NoticeSearchSceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): NoticeSearchSceneComponent + } +} + + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + NoticeInCategorySceneModule::class, + NoticeUseCaseModule::class, + NoticeRemoteModule::class, + NetworkModule::class + ] +) +interface NoticeInCategorySceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): NoticeInCategorySceneComponent + } +} + + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + CustomerServiceSceneModule::class, + PreferencesUseCaseModule::class, + PreferencesRemoteModule::class, + NetworkModule::class + ] +) +interface CustomerServiceSceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemService: SystemServices): CustomerServiceSceneComponent + } +} + + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + NotificationPreferencesSceneModule::class, + PreferencesUseCaseModule::class, + PreferencesRemoteModule::class, + NetworkModule::class + ] +) +interface NotificationPreferencesSceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): NotificationPreferencesSceneComponent + } +} + + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + SettingsSceneModule::class, + PreProcessingUseCaseModule::class, + LocalModule::class, + NoticeRemoteModule::class, + NetworkModule::class + ] +) +interface SettingsSceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): SettingsSceneComponent + } +} + + +@Component( + dependencies = [SystemServices::class], + modules = [ + ViewModelFactoryModule::class, + DispatcherModule::class, + SplashSceneModule::class, + NotificationModule::class, + PreProcessingUseCaseModule::class, + LocalModule::class, + NoticeRemoteModule::class, + TokenRemoteModule::class, + NetworkModule::class + ] +) +interface SplashSceneComponent { + fun viewModelFactory(): ViewModelProvider.Factory + + @Component.Factory + interface Factory { + fun create(systemServices: SystemServices): SplashSceneComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/doyoonkim/knutice/di/AppModule.kt b/app/src/main/java/com/doyoonkim/knutice/di/modules/AppModule.kt similarity index 87% rename from app/src/main/java/com/doyoonkim/knutice/di/AppModule.kt rename to app/src/main/java/com/doyoonkim/knutice/di/modules/AppModule.kt index 17f1daf8..dc33a47e 100644 --- a/app/src/main/java/com/doyoonkim/knutice/di/AppModule.kt +++ b/app/src/main/java/com/doyoonkim/knutice/di/modules/AppModule.kt @@ -1,4 +1,4 @@ -package com.doyoonkim.knutice.di +package com.doyoonkim.knutice.di.modules import android.app.AlarmManager import android.app.Application @@ -8,29 +8,25 @@ import android.content.SharedPreferences import com.doyoonkim.common.di.ApplicationContext import dagger.Module import dagger.Provides -import javax.inject.Singleton @Module object AppModule { // Inject ApplicationContext @Provides - @Singleton @ApplicationContext fun providesApplicationContext(app: Application): Context = app.applicationContext @Provides - @Singleton fun providesApplicationPreferences(@ApplicationContext context: Context): SharedPreferences = + // Only one instance of the SharedPreferences object is returned to any callers for the same name context.applicationContext.getSharedPreferences("app_pref", Context.MODE_PRIVATE) @Provides - @Singleton fun providesAlarmManager(@ApplicationContext context: Context) : AlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager @Provides - @Singleton fun provideNotificationManager(@ApplicationContext context: Context): NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager diff --git a/app/src/main/java/com/doyoonkim/knutice/di/DispatcherModule.kt b/app/src/main/java/com/doyoonkim/knutice/di/modules/DispatcherModule.kt similarity index 92% rename from app/src/main/java/com/doyoonkim/knutice/di/DispatcherModule.kt rename to app/src/main/java/com/doyoonkim/knutice/di/modules/DispatcherModule.kt index 63f35b39..cf3e8d2c 100644 --- a/app/src/main/java/com/doyoonkim/knutice/di/DispatcherModule.kt +++ b/app/src/main/java/com/doyoonkim/knutice/di/modules/DispatcherModule.kt @@ -1,4 +1,4 @@ -package com.doyoonkim.knutice.di +package com.doyoonkim.knutice.di.modules import com.doyoonkim.model.di.DefaultDispatcher import com.doyoonkim.model.di.IoDispatcher diff --git a/app/src/main/java/com/doyoonkim/knutice/di/ViewModelFactoryModule.kt b/app/src/main/java/com/doyoonkim/knutice/di/modules/ViewModelFactoryModule.kt similarity index 76% rename from app/src/main/java/com/doyoonkim/knutice/di/ViewModelFactoryModule.kt rename to app/src/main/java/com/doyoonkim/knutice/di/modules/ViewModelFactoryModule.kt index 41c564bf..ec5bd396 100644 --- a/app/src/main/java/com/doyoonkim/knutice/di/ViewModelFactoryModule.kt +++ b/app/src/main/java/com/doyoonkim/knutice/di/modules/ViewModelFactoryModule.kt @@ -1,6 +1,7 @@ -package com.doyoonkim.knutice.di +package com.doyoonkim.knutice.di.modules import androidx.lifecycle.ViewModelProvider +import com.doyoonkim.knutice.di.util.DaggerViewModelFactory import dagger.Binds import dagger.Module diff --git a/app/src/main/java/com/doyoonkim/knutice/di/DaggerViewModelFactory.kt b/app/src/main/java/com/doyoonkim/knutice/di/util/DaggerViewModelFactory.kt similarity index 95% rename from app/src/main/java/com/doyoonkim/knutice/di/DaggerViewModelFactory.kt rename to app/src/main/java/com/doyoonkim/knutice/di/util/DaggerViewModelFactory.kt index 04f94ab2..f7f3f7fb 100644 --- a/app/src/main/java/com/doyoonkim/knutice/di/DaggerViewModelFactory.kt +++ b/app/src/main/java/com/doyoonkim/knutice/di/util/DaggerViewModelFactory.kt @@ -1,4 +1,4 @@ -package com.doyoonkim.knutice.di +package com.doyoonkim.knutice.di.util import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider diff --git a/app/src/main/java/com/doyoonkim/knutice/di/util/DefaultSystemService.kt b/app/src/main/java/com/doyoonkim/knutice/di/util/DefaultSystemService.kt new file mode 100644 index 00000000..4cda2a56 --- /dev/null +++ b/app/src/main/java/com/doyoonkim/knutice/di/util/DefaultSystemService.kt @@ -0,0 +1,30 @@ +package com.doyoonkim.knutice.di.util + +import android.app.AlarmManager +import android.app.NotificationManager +import android.content.Context +import android.content.SharedPreferences +import com.doyoonkim.common.di.ApplicationContext +import com.doyoonkim.knutice.di.components.AppComponent + +interface SystemServices { + @ApplicationContext fun applicationContext(): Context + fun sharedPreferences(): SharedPreferences + fun alarmManager(): AlarmManager + fun notificationManager(): NotificationManager +} + +class DefaultSystemService( + private val appComponent: AppComponent +) : SystemServices { + + @ApplicationContext + override fun applicationContext(): Context = appComponent.applicationContext() + + override fun sharedPreferences(): SharedPreferences = appComponent.sharedPreference() + + override fun alarmManager(): AlarmManager = appComponent.alarmManager() + + override fun notificationManager(): NotificationManager = appComponent.notificationManager() + +} \ No newline at end of file diff --git a/app/src/main/java/com/doyoonkim/knutice/AppNavHost.kt b/app/src/main/java/com/doyoonkim/knutice/navigation/AppNavHost.kt similarity index 84% rename from app/src/main/java/com/doyoonkim/knutice/AppNavHost.kt rename to app/src/main/java/com/doyoonkim/knutice/navigation/AppNavHost.kt index 190b6573..811ad3d4 100644 --- a/app/src/main/java/com/doyoonkim/knutice/AppNavHost.kt +++ b/app/src/main/java/com/doyoonkim/knutice/navigation/AppNavHost.kt @@ -1,4 +1,4 @@ -package com.doyoonkim.knutice +package com.doyoonkim.knutice.navigation import android.net.Uri import androidx.compose.foundation.layout.PaddingValues @@ -6,23 +6,27 @@ import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.LayoutDirection -import androidx.lifecycle.ViewModelProvider import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost -import com.doyoonkim.bookmark.bookmarkServiceGraph import com.doyoonkim.common.navigation.NavRoutes -import com.doyoonkim.main.mainServiceNavGraph +import com.doyoonkim.knutice.MainApplication @Composable fun AppNavHost( modifier: Modifier = Modifier, contentPadding: PaddingValues, navController: NavHostController, - viewModelFactory: ViewModelProvider.Factory, onExit: () -> Unit = { /* ON EXIT HANDLING */ } ) { + + val appComponent = with(LocalContext.current) { + remember { (this.applicationContext as MainApplication).appComponent } + } + NavHost( modifier = modifier.padding( PaddingValues( @@ -35,7 +39,7 @@ fun AppNavHost( ) { mainServiceNavGraph( navController = navController, - viewModelFactory = viewModelFactory, + appComponent = appComponent, contentPadding = contentPadding, onNoticeDetailRequested = { target -> navController.navigate("noticeDetail/${target.nttId}/${Uri.encode(target.contentUrl)}/${target.isFabVisible}") @@ -48,7 +52,7 @@ fun AppNavHost( bookmarkServiceGraph( navController = navController, - viewModelFactory = viewModelFactory, + appComponent = appComponent, contentPadding = contentPadding, onNoticeDetailRequested = { target -> navController.navigate("noticeDetail/${target.nttId}/${Uri.encode(target.contentUrl)}/${target.isFabVisible}") diff --git a/feature/main/src/main/java/com/doyoonkim/main/MainServiceNavGraph.kt b/app/src/main/java/com/doyoonkim/knutice/navigation/MainServiceNavGraph.kt similarity index 82% rename from feature/main/src/main/java/com/doyoonkim/main/MainServiceNavGraph.kt rename to app/src/main/java/com/doyoonkim/knutice/navigation/MainServiceNavGraph.kt index fb5e7e2f..9f986ca1 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/MainServiceNavGraph.kt +++ b/app/src/main/java/com/doyoonkim/knutice/navigation/MainServiceNavGraph.kt @@ -1,4 +1,4 @@ -package com.doyoonkim.main +package com.doyoonkim.knutice.navigation import android.net.Uri import androidx.compose.animation.AnimatedContentTransitionScope @@ -8,9 +8,9 @@ import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder @@ -21,6 +21,15 @@ import com.doyoonkim.common.navigation.Destination import com.doyoonkim.common.navigation.NavRoutes import com.doyoonkim.common.navigation.NoticeDetail import com.doyoonkim.common.ui.TipCategory +import com.doyoonkim.knutice.di.components.AppComponent +import com.doyoonkim.knutice.di.components.DaggerCustomerServiceSceneComponent +import com.doyoonkim.knutice.di.components.DaggerHomeSceneComponent +import com.doyoonkim.knutice.di.components.DaggerNoticeDetailSceneComponent +import com.doyoonkim.knutice.di.components.DaggerNoticeInCategorySceneComponent +import com.doyoonkim.knutice.di.components.DaggerNoticeSearchSceneComponent +import com.doyoonkim.knutice.di.components.DaggerNotificationPreferencesSceneComponent +import com.doyoonkim.knutice.di.components.DaggerSettingsSceneComponent +import com.doyoonkim.knutice.di.util.DefaultSystemService import com.doyoonkim.main.home.HomeScreen import com.doyoonkim.main.notice.NoticeDetailScreen import com.doyoonkim.main.notice.NoticeSearchScreen @@ -41,18 +50,23 @@ import com.doyoonkim.model.NoticeCategory fun NavGraphBuilder.mainServiceNavGraph( navController: NavController, - viewModelFactory: ViewModelProvider.Factory, + appComponent: AppComponent, contentPadding: PaddingValues, onNoticeDetailRequested: (NoticeDetail) -> Unit, onBookmarkServiceRequested: (BookmarkInfo) -> Unit, onExit: () -> Unit = { } ) { + // ViewModels will be injected via ViewModelFactory composable(NavRoutes.Home.route) { + val sceneComponent = remember(appComponent) { + DaggerHomeSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + HomeScreen( modifier = Modifier.padding(horizontal = 5.dp), - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), bottomPadding = contentPadding.calculateBottomPadding(), onSettingsRequested = { navController.navigate(NavRoutes.Settings.route) }, onGoBackAction = { @@ -82,9 +96,13 @@ fun NavGraphBuilder.mainServiceNavGraph( composable( route = NavRoutes.NoticeSearch.route ) { + val sceneComponent = remember(appComponent) { + DaggerNoticeSearchSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + NoticeSearchScreen( modifier = Modifier, - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), bottomPadding = contentPadding.calculateBottomPadding(), onBackPressed = { navController.popBackStack() }, onNoticeSelected = { id, url -> @@ -108,10 +126,14 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ) { + val sceneComponent = remember(appComponent) { + DaggerNoticeInCategorySceneComponent.factory().create(DefaultSystemService(appComponent)) + } + NoticesInCategoryScreen( modifier = Modifier, category = NoticeCategory.GENERAL_NEWS, - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), onBackButtonPressed = { navController.popBackStack() }, onNoticeSelected = { id, url -> onNoticeDetailRequested(NoticeDetail(id, url)) @@ -134,10 +156,14 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ) { + val sceneComponent = remember(appComponent) { + DaggerNoticeInCategorySceneComponent.factory().create(DefaultSystemService(appComponent)) + } + NoticesInCategoryScreen( modifier = Modifier, category = NoticeCategory.ACADEMIC_NEWS, - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), onBackButtonPressed = { navController.popBackStack() }, onNoticeSelected = { id, url -> onNoticeDetailRequested(NoticeDetail(id, url)) @@ -160,10 +186,14 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ) { + val sceneComponent = remember(appComponent) { + DaggerNoticeInCategorySceneComponent.factory().create(DefaultSystemService(appComponent)) + } + NoticesInCategoryScreen( modifier = Modifier, category = NoticeCategory.SCHOLARSHIP_NEWS, - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), onBackButtonPressed = { navController.popBackStack() }, onNoticeSelected = { id, url -> onNoticeDetailRequested(NoticeDetail(id, url)) @@ -186,10 +216,14 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ) { + val sceneComponent = remember(appComponent) { + DaggerNoticeInCategorySceneComponent.factory().create(DefaultSystemService(appComponent)) + } + NoticesInCategoryScreen( modifier = Modifier, category = NoticeCategory.EVENT_NEWS, - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), onBackButtonPressed = { navController.popBackStack() }, onNoticeSelected = { id, url -> onNoticeDetailRequested(NoticeDetail(id, url)) @@ -212,10 +246,14 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ) { + val sceneComponent = remember(appComponent) { + DaggerNoticeInCategorySceneComponent.factory().create(DefaultSystemService(appComponent)) + } + NoticesInCategoryScreen( modifier = Modifier, category = NoticeCategory.EMPLOYMENT_NEWS, - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), onBackButtonPressed = { navController.popBackStack() }, onNoticeSelected = { id, url -> onNoticeDetailRequested(NoticeDetail(id, url)) @@ -239,9 +277,13 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ) { + val sceneComponent = remember(appComponent) { + DaggerSettingsSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + UserPreferenceScreen( modifier = Modifier.padding(horizontal = 10.dp), - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), onNotificationPreferenceClicked = { navController.navigate(NavRoutes.NotificationPreferences.route) }, onCustomerServiceClicked = { navController.navigate(NavRoutes.CustomerService.route) }, onOssClicked = { navController.navigate(NavRoutes.OpenSource.route) }, @@ -270,9 +312,13 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ) { + val sceneComponent = remember(appComponent) { + DaggerNotificationPreferencesSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + NotificationPreferencesScreen( modifier = Modifier.padding(horizontal = 10.dp), - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), onBackPressed = { navController.popBackStack() } ) } @@ -292,9 +338,13 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ) { + val sceneComponent = remember(appComponent) { + DaggerCustomerServiceSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + CustomerServiceScreen( modifier = Modifier.padding(horizontal = 10.dp), - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), onBackPressed = { navController.popBackStack() } ) } @@ -349,9 +399,13 @@ fun NavGraphBuilder.mainServiceNavGraph( ) } ?: Triple(0, "", false) + val sceneComponent = remember(appComponent) { + DaggerNoticeDetailSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + NoticeDetailScreen( modifier = Modifier.fillMaxSize(), - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), noticeInfo = noticeInfo, onBookmarkCreate = { onBookmarkServiceRequested(BookmarkInfo( noticeId = it.nttId, diff --git a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/bookmarkServiceGraph.kt b/app/src/main/java/com/doyoonkim/knutice/navigation/bookmarkServiceGraph.kt similarity index 81% rename from feature/bookmark/src/main/java/com/doyoonkim/bookmark/bookmarkServiceGraph.kt rename to app/src/main/java/com/doyoonkim/knutice/navigation/bookmarkServiceGraph.kt index 67c98992..be0626f5 100644 --- a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/bookmarkServiceGraph.kt +++ b/app/src/main/java/com/doyoonkim/knutice/navigation/bookmarkServiceGraph.kt @@ -1,17 +1,15 @@ -package com.doyoonkim.bookmark +package com.doyoonkim.knutice.navigation import android.net.Uri import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.core.EaseIn import androidx.compose.animation.core.EaseOut import androidx.compose.animation.core.tween -import androidx.compose.foundation.background import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder @@ -24,11 +22,14 @@ import com.doyoonkim.bookmark.viewmodel.EditBookmarkViewModel import com.doyoonkim.common.navigation.BookmarkInfo import com.doyoonkim.common.navigation.NavRoutes import com.doyoonkim.common.navigation.NoticeDetail -import com.doyoonkim.common.theme.displayBackground +import com.doyoonkim.knutice.di.components.AppComponent +import com.doyoonkim.knutice.di.components.DaggerBookmarkListSceneComponent +import com.doyoonkim.knutice.di.components.DaggerEditBookmarkSceneComponent +import com.doyoonkim.knutice.di.util.DefaultSystemService fun NavGraphBuilder.bookmarkServiceGraph( navController: NavController, - viewModelFactory: ViewModelProvider.Factory, + appComponent: AppComponent, contentPadding: PaddingValues, onNoticeDetailRequested: (NoticeDetail) -> Unit, onBookmarkRequested: (BookmarkInfo) -> Unit, @@ -36,9 +37,13 @@ fun NavGraphBuilder.bookmarkServiceGraph( ) { composable(NavRoutes.Bookmark.route) { + val sceneComponent = remember(appComponent) { + DaggerBookmarkListSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + BookmarkListScreen( modifier = Modifier.padding(horizontal = 5.dp), - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.getViewModelFactory()), bottomPadding = contentPadding.calculateBottomPadding(), onSettingsRequested = { navController.navigate(NavRoutes.Settings.route) }, onBookmarkSelected = { @@ -78,9 +83,13 @@ fun NavGraphBuilder.bookmarkServiceGraph( ) } ?: BookmarkInfo(0, "", "") + val sceneComponent = remember(appComponent) { + DaggerEditBookmarkSceneComponent.factory().create(DefaultSystemService(appComponent)) + } + EditBookmarkScreen( modifier = Modifier.padding(horizontal = 10.dp), - viewModel = viewModel(factory = viewModelFactory), + viewModel = viewModel(factory = sceneComponent.viewModelFactory()), bookmarkInfo = bookmarkInfo, onNoticeSelected = { onNoticeDetailRequested(it) }, onCompleted = { diff --git a/common/src/main/java/com/doyoonkim/common/di/Scopes.kt b/common/src/main/java/com/doyoonkim/common/di/Scopes.kt new file mode 100644 index 00000000..b240b554 --- /dev/null +++ b/common/src/main/java/com/doyoonkim/common/di/Scopes.kt @@ -0,0 +1,7 @@ +package com.doyoonkim.common.di + +import javax.inject.Scope + +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class ApplicationScope \ No newline at end of file diff --git a/common/src/main/res/values-ja/strings.xml b/common/src/main/res/values-ja/strings.xml index 7db11986..15118a04 100644 --- a/common/src/main/res/values-ja/strings.xml +++ b/common/src/main/res/values-ja/strings.xml @@ -87,4 +87,6 @@ どのようなお知らせをお探しですか? 検索結果がありません。 就職 + 提出できません. + リクエストの処理中にエラーが発生しました。 \ No newline at end of file diff --git a/common/src/main/res/values-ko-rKR/strings.xml b/common/src/main/res/values-ko-rKR/strings.xml index d4d8cbae..2f2d289e 100644 --- a/common/src/main/res/values-ko-rKR/strings.xml +++ b/common/src/main/res/values-ko-rKR/strings.xml @@ -87,4 +87,6 @@ 어떤 공지사항을 찾아드릴까요? 검색 결과가 없어요 취업공지 + 오류가 발생했습니다. + 요청을 처리하는 중 오류가 발생했어요. \ No newline at end of file diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 8fb25efc..feac737a 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -98,4 +98,6 @@ What do you like to search No result found. Career News + Submission Unavailable + Error occurred while processing your request. \ No newline at end of file diff --git a/core/data/src/main/java/com/doyoonkim/data/di/LocalModules.kt b/core/data/src/main/java/com/doyoonkim/data/di/LocalModules.kt new file mode 100644 index 00000000..d28bd159 --- /dev/null +++ b/core/data/src/main/java/com/doyoonkim/data/di/LocalModules.kt @@ -0,0 +1,38 @@ +package com.doyoonkim.data.di + +import android.content.Context +import com.doyoonkim.common.di.ApplicationContext +import com.doyoonkim.data.repository.LocalRepositoryImpl +import com.doyoonkim.data.room.LocalDatabase +import com.doyoonkim.domain.interfaces.BookmarkLocalRepository +import com.doyoonkim.domain.interfaces.NoticeLocalRepository +import dagger.Binds +import dagger.Module +import dagger.Provides + +@Module +abstract class LocalModule { + // Provides + companion object { + // Database + @Provides + fun provideLocalDatabase( + @ApplicationContext context: Context + ): LocalDatabase { + return LocalDatabase.getInstance(context) + } + + @Provides + fun provideMainDatabaseDao(db: LocalDatabase) = db.getDao() + } + + @Binds + abstract fun bindsBookmarkLocalRepository( + impl: LocalRepositoryImpl + ) : BookmarkLocalRepository + + @Binds + abstract fun bindsNoticeLocalRepository( + impl: LocalRepositoryImpl + ) : NoticeLocalRepository +} \ No newline at end of file diff --git a/core/data/src/main/java/com/doyoonkim/data/di/RemoteModules.kt b/core/data/src/main/java/com/doyoonkim/data/di/RemoteModules.kt new file mode 100644 index 00000000..21a955b0 --- /dev/null +++ b/core/data/src/main/java/com/doyoonkim/data/di/RemoteModules.kt @@ -0,0 +1,57 @@ +package com.doyoonkim.data.di + +import com.doyoonkim.data.repository.ImageRepositoryImpl +import com.doyoonkim.data.repository.RemoteRepositoryImpl +import com.doyoonkim.domain.interfaces.ImageRemoteRepository +import com.doyoonkim.domain.interfaces.NoticeRemoteRepository +import com.doyoonkim.domain.interfaces.TipRemoteRepository +import com.doyoonkim.domain.interfaces.TokenRemoteRepository +import com.doyoonkim.domain.interfaces.TopicSubscriptionRemoteRepository +import com.doyoonkim.domain.interfaces.UserReportRemoteRepository +import dagger.Binds +import dagger.Module + +@Module +abstract class NoticeRemoteModule { + @Binds + abstract fun bindsNoticeRemoteRepo( + impl: RemoteRepositoryImpl + ) : NoticeRemoteRepository +} + +@Module +abstract class TipRemoteModule { + @Binds + abstract fun bindsTipRemoteRepo( + impl: RemoteRepositoryImpl + ) : TipRemoteRepository +} + +@Module +abstract class TokenRemoteModule { + @Binds + abstract fun bindsTokenRemoteRepo( + impl: RemoteRepositoryImpl + ) : TokenRemoteRepository +} + +@Module +abstract class PreferencesRemoteModule { + @Binds + abstract fun bindsTopicSubscriptionRemoteRepo( + impl: RemoteRepositoryImpl + ) : TopicSubscriptionRemoteRepository + + @Binds + abstract fun bindsUserReportRemoteRepo( + impl: RemoteRepositoryImpl + ) : UserReportRemoteRepository +} + +@Module +abstract class ImageRemoteModule { + @Binds + abstract fun bindsImageRemoteRepo( + impl: ImageRepositoryImpl + ) : ImageRemoteRepository +} \ No newline at end of file diff --git a/core/data/src/main/java/com/doyoonkim/data/di/dataModule.kt b/core/data/src/main/java/com/doyoonkim/data/di/dataModule.kt deleted file mode 100644 index fe2ec26a..00000000 --- a/core/data/src/main/java/com/doyoonkim/data/di/dataModule.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.doyoonkim.data.di - -import android.content.Context -import android.util.Log -import androidx.room.Room -import com.doyoonkim.common.di.ApplicationContext -import com.doyoonkim.data.repository.ImageRepositoryImpl -import com.doyoonkim.data.repository.LocalRepositoryImpl -import com.doyoonkim.data.repository.RemoteRepositoryImpl -import com.doyoonkim.data.room.LocalDatabase -import com.doyoonkim.domain.interfaces.BookmarkLocalRepository -import com.doyoonkim.domain.interfaces.ImageRemoteRepository -import com.doyoonkim.domain.interfaces.NoticeLocalRepository -import com.doyoonkim.domain.interfaces.NoticeRemoteRepository -import com.doyoonkim.domain.interfaces.TipRemoteRepository -import com.doyoonkim.domain.interfaces.TokenRemoteRepository -import com.doyoonkim.domain.interfaces.TopicSubscriptionRemoteRepository -import com.doyoonkim.domain.interfaces.UserReportRemoteRepository -import dagger.Binds -import dagger.Module -import dagger.Provides -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.asExecutor -import javax.inject.Singleton - -@Module -object DataModule { - - // Database - @Provides - @Singleton - fun provideLocalDatabase( - @ApplicationContext context: Context - ): LocalDatabase { - // @Provides annotation is used because providing LocalDatabase instance requires custom-logic for instantiation. - return Room.databaseBuilder( - context, - LocalDatabase::class.java, - "Main Local Database" - ).setQueryCallback( - { sqlQuery, bindArgs -> - Log.d("SQL", "Query: $sqlQuery SQLArgs: $bindArgs") - }, - Dispatchers.IO.asExecutor() - ).addMigrations( - LocalDatabase.MIGRATION_1_2 - ).build() - } - - @Provides - fun provideMainDatabaseDao(db: LocalDatabase) = db.getDao() -} - -@Module -abstract class DataBindingModule { - - @Binds - abstract fun bindsNoticeRemoteRepo( - impl: RemoteRepositoryImpl - ) : NoticeRemoteRepository - - @Binds - abstract fun bindsTipRemoteRepo( - impl: RemoteRepositoryImpl - ) : TipRemoteRepository - - @Binds - abstract fun bindsTokenRemoteRepo( - impl: RemoteRepositoryImpl - ) : TokenRemoteRepository - - @Binds - abstract fun bindsTopicSubscriptionRemoteRepo( - impl: RemoteRepositoryImpl - ) : TopicSubscriptionRemoteRepository - - @Binds - abstract fun bindsUserReportRemoteRepo( - impl: RemoteRepositoryImpl - ) : UserReportRemoteRepository - - @Binds - abstract fun bindsImageRemoteRepo( - impl: ImageRepositoryImpl - ) : ImageRemoteRepository - - @Binds - abstract fun bindsBookmarkLocalRepository( - impl: LocalRepositoryImpl - ) : BookmarkLocalRepository - - @Binds - abstract fun bindsNoticeLocalRepository( - impl: LocalRepositoryImpl - ) : NoticeLocalRepository - -} \ No newline at end of file diff --git a/core/data/src/main/java/com/doyoonkim/data/repository/RemoteRepositoryImpl.kt b/core/data/src/main/java/com/doyoonkim/data/repository/RemoteRepositoryImpl.kt index e7b63b4f..e530a0ff 100644 --- a/core/data/src/main/java/com/doyoonkim/data/repository/RemoteRepositoryImpl.kt +++ b/core/data/src/main/java/com/doyoonkim/data/repository/RemoteRepositoryImpl.kt @@ -140,7 +140,7 @@ class RemoteRepositoryImpl @Inject constructor( override fun requestUserReportSubmission(body: UserReportBody) = flow { remoteSource.submitUserReport( // Should be revised. - UserReportRequest(body = body.copy(fcmToken = remoteSource.validatedToken)) + UserReportRequest(body = body) ).fold( onSuccess = { if (it.result?.resultCode == 200) emit(true) @@ -158,7 +158,7 @@ class RemoteRepositoryImpl @Inject constructor( ) = flow { remoteSource.run { submitTopicSubscriptionPreferences( - TopicSubscriptionPreferencesRequest(body = body.copy(fcmToken = this.validatedToken)) + TopicSubscriptionPreferencesRequest(body = body) ) }.fold( onSuccess = { diff --git a/core/data/src/main/java/com/doyoonkim/data/room/LocalRoomDatabase.kt b/core/data/src/main/java/com/doyoonkim/data/room/LocalRoomDatabase.kt index 6e849918..41a5bdcd 100644 --- a/core/data/src/main/java/com/doyoonkim/data/room/LocalRoomDatabase.kt +++ b/core/data/src/main/java/com/doyoonkim/data/room/LocalRoomDatabase.kt @@ -1,12 +1,17 @@ package com.doyoonkim.data.room +import android.content.Context +import android.util.Log import androidx.room.AutoMigration import androidx.room.Database +import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase import com.doyoonkim.data.model.Bookmark import com.doyoonkim.data.model.NoticeEntity +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asExecutor // Migration Strategy: https://stackoverflow.com/questions/56478785/room-database-schema-update-without-data-loss @@ -19,6 +24,26 @@ abstract class LocalDatabase : RoomDatabase() { // Migration Code companion object { + private var INSTANCE: LocalDatabase? = null + + fun getInstance(context: Context): LocalDatabase { + // Apply Custom Singleton logic. + return INSTANCE ?: synchronized(this) { + Room.databaseBuilder( + context, + LocalDatabase::class.java, + "Main Local Database" + ).setQueryCallback( + { sqlQuery, bindArgs -> + Log.d("SQL", "Query: $sqlQuery SQLArgs: $bindArgs") + }, + Dispatchers.IO.asExecutor() + ) + }.addMigrations( + MIGRATION_1_2 + ).build() + } + val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL("ALTER TABLE Bookmark ADD COLUMN created_at INTEGER DEFAULT 0 NOT NULL") diff --git a/core/domain/src/main/java/com/doyoonkim/domain/di/DomainModule.kt b/core/domain/src/main/java/com/doyoonkim/domain/di/DomainModule.kt index f2db4d59..aafc344d 100644 --- a/core/domain/src/main/java/com/doyoonkim/domain/di/DomainModule.kt +++ b/core/domain/src/main/java/com/doyoonkim/domain/di/DomainModule.kt @@ -73,7 +73,7 @@ abstract class DomainModule { ): ModifyBookmark @Binds - abstract fun bindsSubmitNotificationPReferences( + abstract fun bindsSubmitNotificationPreferences( impl: SubmitNotificationPreferencesImpl ): SubmitNotificationPreferences diff --git a/core/domain/src/main/java/com/doyoonkim/domain/di/Modules.kt b/core/domain/src/main/java/com/doyoonkim/domain/di/Modules.kt new file mode 100644 index 00000000..c16af9b4 --- /dev/null +++ b/core/domain/src/main/java/com/doyoonkim/domain/di/Modules.kt @@ -0,0 +1,111 @@ +package com.doyoonkim.domain.di + +import com.doyoonkim.domain.usecases.FetchAllBookmarks +import com.doyoonkim.domain.usecases.FetchAllBookmarksImpl +import com.doyoonkim.domain.usecases.FetchNoticeById +import com.doyoonkim.domain.usecases.FetchNoticeByIdFromLocal +import com.doyoonkim.domain.usecases.FetchNoticeByIdFromLocalImpl +import com.doyoonkim.domain.usecases.FetchNoticeByIdImpl +import com.doyoonkim.domain.usecases.FetchNoticesByKeyword +import com.doyoonkim.domain.usecases.FetchNoticesByKeywordImpl +import com.doyoonkim.domain.usecases.FetchNoticesPerPage +import com.doyoonkim.domain.usecases.FetchNoticesPerPageImpl +import com.doyoonkim.domain.usecases.FetchTips +import com.doyoonkim.domain.usecases.FetchTipsImpl +import com.doyoonkim.domain.usecases.FetchTopThreeNotices +import com.doyoonkim.domain.usecases.FetchTopThreeNoticesImpl +import com.doyoonkim.domain.usecases.FetchTopicSubscriptionStatus +import com.doyoonkim.domain.usecases.FetchTopicSubscriptionStatusImpl +import com.doyoonkim.domain.usecases.ModifyBookmark +import com.doyoonkim.domain.usecases.ModifyBookmarkImpl +import com.doyoonkim.domain.usecases.SubmitNotificationPreferences +import com.doyoonkim.domain.usecases.SubmitNotificationPreferencesImpl +import com.doyoonkim.domain.usecases.SubmitUserReport +import com.doyoonkim.domain.usecases.SubmitUserReportImpl +import com.doyoonkim.domain.usecases.SyncDataWithUpdateDatabase +import com.doyoonkim.domain.usecases.SyncDataWithUpdatedDatabaseImpl +import com.doyoonkim.domain.usecases.ValidateDeviceToken +import com.doyoonkim.domain.usecases.ValidateDeviceTokenImpl +import dagger.Binds +import dagger.Module + + +@Module +abstract class NoticeUseCaseModule { + @Binds + abstract fun bindsFetchNoticeById( + impl: FetchNoticeByIdImpl + ): FetchNoticeById + + @Binds + abstract fun bindsFetchNoticesByKeyword( + impl: FetchNoticesByKeywordImpl + ): FetchNoticesByKeyword + + @Binds + abstract fun bindsFetchNoticesPerPage( + impl: FetchNoticesPerPageImpl + ): FetchNoticesPerPage + + @Binds + abstract fun bindsFetchTopThreeNotices( + impl: FetchTopThreeNoticesImpl + ): FetchTopThreeNotices +} + +@Module +abstract class BookmarkUseCaseModule { + @Binds + abstract fun bindFetchAllBookmarks( + impl: FetchAllBookmarksImpl + ): FetchAllBookmarks + + @Binds + abstract fun bindsFetchNoticeByIdFromLocal( + impl: FetchNoticeByIdFromLocalImpl + ): FetchNoticeByIdFromLocal + + @Binds + abstract fun bindsModifyBookmark( + impl: ModifyBookmarkImpl + ): ModifyBookmark +} + +@Module +abstract class TipUseCaseModule { + @Binds + abstract fun bindsFetchTips( + impl: FetchTipsImpl + ): FetchTips +} + +@Module +abstract class PreferencesUseCaseModule { + @Binds + abstract fun bindsFetchTopicSubscriptionStatus( + impl: FetchTopicSubscriptionStatusImpl + ): FetchTopicSubscriptionStatus + + @Binds + abstract fun bindsSubmitNotificationPreferences( + impl: SubmitNotificationPreferencesImpl + ): SubmitNotificationPreferences + + @Binds + abstract fun bindsSubmitUserReport( + impl: SubmitUserReportImpl + ): SubmitUserReport +} + +@Module +abstract class PreProcessingUseCaseModule { + @Binds + abstract fun bindsValidateDeviceToken( + impl: ValidateDeviceTokenImpl + ): ValidateDeviceToken + + @Binds + abstract fun bindsSyncDataWithUpdatedDatabase( + impl: SyncDataWithUpdatedDatabaseImpl + ): SyncDataWithUpdateDatabase +} diff --git a/core/network/src/main/kotlin/com/doyoonkim/network/DeviceToken.kt b/core/network/src/main/kotlin/com/doyoonkim/network/DeviceToken.kt new file mode 100644 index 00000000..a46bdf69 --- /dev/null +++ b/core/network/src/main/kotlin/com/doyoonkim/network/DeviceToken.kt @@ -0,0 +1,12 @@ +package com.doyoonkim.network + + +object DeviceToken { + private var validatedToken = "" + + fun updateValidatedToken(token: String) { + validatedToken = token + } + + fun validatedToken(): String = validatedToken +} \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/doyoonkim/network/KnuticeRemoteSource.kt b/core/network/src/main/kotlin/com/doyoonkim/network/KnuticeRemoteSource.kt index 4d86a6c0..84fd6399 100644 --- a/core/network/src/main/kotlin/com/doyoonkim/network/KnuticeRemoteSource.kt +++ b/core/network/src/main/kotlin/com/doyoonkim/network/KnuticeRemoteSource.kt @@ -15,15 +15,12 @@ import javax.inject.Singleton */ // This class should be provided/injected as Singleton Instance. -@Singleton class KnuticeRemoteSource @Inject constructor( - private val knuticeApi: KnuticeService + private val knuticeApi: KnuticeService, + private val deviceToken: DeviceToken ) { private val TAG = "KnuticeRemoteSource" - // Should be later migrated to DataStore. - var validatedToken: String = "" - suspend fun getTopThreeNotices() = runCatching { knuticeApi.getTopThreeNotices() } @@ -43,9 +40,9 @@ class KnuticeRemoteSource @Inject constructor( } suspend fun getTopicSubscriptionStatus() = runCatching { - if (validatedToken.isBlank()) throw Exception("No validated token found") + if (deviceToken.validatedToken().isBlank()) throw Exception("No validated token found") else { - knuticeApi.getTopicSubscriptionStatus(validatedToken) + knuticeApi.getTopicSubscriptionStatus(deviceToken.validatedToken()) } } @@ -58,15 +55,17 @@ class KnuticeRemoteSource @Inject constructor( } fun updateValidatedToken(fcmToken: String) { - validatedToken = fcmToken + deviceToken.updateValidatedToken(fcmToken) } suspend fun submitUserReport(request: UserReportRequest) = runCatching { - knuticeApi.submitUserReport(request) - } + val body = request.body.copy(fcmToken = deviceToken.validatedToken()) + knuticeApi.submitUserReport(request.copy(body = body)) + } suspend fun submitTopicSubscriptionPreferences(request: TopicSubscriptionPreferencesRequest) = runCatching { - knuticeApi.submitTopicSubscriptionPreferences(request) + val body = request.body.copy(fcmToken = deviceToken.validatedToken()) + knuticeApi.submitTopicSubscriptionPreferences(request.copy(body = body)) } } \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/doyoonkim/network/di/NetworkModule.kt b/core/network/src/main/kotlin/com/doyoonkim/network/di/NetworkModule.kt index 726bb4ea..b9f23296 100644 --- a/core/network/src/main/kotlin/com/doyoonkim/network/di/NetworkModule.kt +++ b/core/network/src/main/kotlin/com/doyoonkim/network/di/NetworkModule.kt @@ -1,6 +1,7 @@ package com.doyoonkim.network.di import com.doyoonkim.network.BuildConfig +import com.doyoonkim.network.DeviceToken import com.doyoonkim.network.retrofit.KnuticeService import dagger.Module import dagger.Provides @@ -8,13 +9,26 @@ import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import javax.inject.Singleton -@Module +@Module(includes = [DeviceTokenModule::class]) object NetworkModule { @Provides - @Singleton fun providesKnuticeApi(provider: RetrofitProvider): KnuticeService { return provider.provide().create(KnuticeService::class.java) } +} +@Module(includes = [DeviceTokenModule::class]) +object NotificationNetworkModule { + @Provides + fun providesKnuticeApi(provider: RetrofitProvider): KnuticeService { + return provider.provide(5).create(KnuticeService::class.java) + } +} + +@Module +object DeviceTokenModule { + // Consider to annotated as @Binds + @Provides + fun providesDeviceTokenInstance(): DeviceToken = DeviceToken } \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/doyoonkim/network/di/RetrofitProvider.kt b/core/network/src/main/kotlin/com/doyoonkim/network/di/RetrofitProvider.kt index 526c699a..3aae5de2 100644 --- a/core/network/src/main/kotlin/com/doyoonkim/network/di/RetrofitProvider.kt +++ b/core/network/src/main/kotlin/com/doyoonkim/network/di/RetrofitProvider.kt @@ -1,17 +1,26 @@ package com.doyoonkim.network.di import com.doyoonkim.network.BuildConfig +import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory +import java.time.Duration +import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton -@Singleton class RetrofitProvider @Inject constructor() { - fun provide(): Retrofit = + fun provide(timeout: Long = 10): Retrofit = Retrofit.Builder() .baseUrl(BuildConfig.API_LIVE) + .client( + OkHttpClient.Builder() + .connectTimeout(timeout, TimeUnit.SECONDS) + .readTimeout(timeout, TimeUnit.SECONDS) + .writeTimeout(timeout, TimeUnit.SECONDS) + .build() + ) .addConverterFactory(GsonConverterFactory.create()) .build() diff --git a/core/notification/src/main/java/com/doyoonkim/notification/di/NotificationModule.kt b/core/notification/src/main/java/com/doyoonkim/notification/di/NotificationModule.kt index acae03fc..5c9e7383 100644 --- a/core/notification/src/main/java/com/doyoonkim/notification/di/NotificationModule.kt +++ b/core/notification/src/main/java/com/doyoonkim/notification/di/NotificationModule.kt @@ -18,29 +18,27 @@ import kotlinx.coroutines.CoroutineDispatcher import javax.inject.Singleton @Module -object NotificationModule { +abstract class NotificationModule { - @Provides - @Singleton - fun providesPushNotificationHandler( - remoteRepository: NoticeRemoteRepository, - imageRepository: ImageRemoteRepository, - bitmapHandler: BitmapHandler, - @IoDispatcher dispatcher: CoroutineDispatcher, - @ApplicationContext context: Context - ) = - PushNotificationHandler( - remoteRepository, - imageRepository, - bitmapHandler, - dispatcher, - context - ) + companion object { + // Considered to be removed. + @Provides + fun providesPushNotificationHandler( + remoteRepository: NoticeRemoteRepository, + imageRepository: ImageRemoteRepository, + bitmapHandler: BitmapHandler, + @IoDispatcher dispatcher: CoroutineDispatcher, + @ApplicationContext context: Context + ) = + PushNotificationHandler( + remoteRepository, + imageRepository, + bitmapHandler, + dispatcher, + context + ) + } -} - -@Module -abstract class NotificationBindingModule { @Binds abstract fun bindsNotificationAlarmScheduler( impl: NotificationAlarmScheduler @@ -50,4 +48,5 @@ abstract class NotificationBindingModule { abstract fun bindsTokenHandler( impl: TokenHandlerImpl ): TokenHandler + } \ No newline at end of file diff --git a/core/notification/src/main/java/com/doyoonkim/notification/fcm/PushNotificationHandler.kt b/core/notification/src/main/java/com/doyoonkim/notification/fcm/PushNotificationHandler.kt index b0bb2f5c..cfc1e541 100644 --- a/core/notification/src/main/java/com/doyoonkim/notification/fcm/PushNotificationHandler.kt +++ b/core/notification/src/main/java/com/doyoonkim/notification/fcm/PushNotificationHandler.kt @@ -120,55 +120,44 @@ class PushNotificationHandler @Inject constructor( Log.d(TAG, "START FETCHING NOTICE") nttId?.let { val notice = async { - runCatching { - withTimeout(5000L) { - remoteRepository.queryNoticeById(it.toInt()) - .firstOrNull() - } - } + remoteRepository.queryNoticeById(it.toInt()) + .firstOrNull() } - notice.await().fold( - onSuccess = { nullable -> - nullable?.let { vo -> - Log.d(TAG, "RECEIVED ${vo.toString()}") - notificationBuilder.apply { - setContentTitle(localizedTitle(vo.noticeName)) - setContentText(vo.title) - } + notice.await()?.let { vo -> + Log.d(TAG, "RECEIVED ${vo.toString()}") + notificationBuilder.apply { + setContentTitle(localizedTitle(vo.noticeName)) + setContentText(vo.title) + } - vo.imageUrl?.let { url -> - val bitmapImage = async { - runCatching { - withTimeout(5000L) { - imageRepository.getImageByteArrayFromUrl(url)?.let { b -> - bitMapHandler.decodeByteArray(b) - } - } + vo.imageUrl?.let { url -> + val bitmapImage = async { + runCatching { + withTimeout(5000L) { + imageRepository.getImageByteArrayFromUrl(url)?.let { b -> + bitMapHandler.decodeByteArray(b) } } - bitmapImage.await().fold( - onSuccess = { result -> - result?.let { - notificationBuilder.apply { - setStyle( - NotificationCompat.BigPictureStyle() - .bigPicture(it) - ) - } - } - }, - onFailure = { - Log.d(TAG, "Unable to receive image.\n" + - "REASON: ${it.stackTrace}") - } - ) } } - }, - onFailure = { - Log.d(TAG, "Unable to get Notice.\nREASON: ${it.stackTrace}") + bitmapImage.await().fold( + onSuccess = { result -> + result?.let { + notificationBuilder.apply { + setStyle( + NotificationCompat.BigPictureStyle() + .bigPicture(it) + ) + } + } + }, + onFailure = { + Log.d(TAG, "Unable to receive image.\n" + + "REASON: ${it.stackTrace}") + } + ) } - ) + } } }.invokeOnCompletion { notify(notificationId, notificationBuilder.build()) } diff --git a/core/notification/src/main/java/com/doyoonkim/notification/local/NotificationAlarmScheduler.kt b/core/notification/src/main/java/com/doyoonkim/notification/local/NotificationAlarmScheduler.kt index 303a663a..78d7d9fc 100644 --- a/core/notification/src/main/java/com/doyoonkim/notification/local/NotificationAlarmScheduler.kt +++ b/core/notification/src/main/java/com/doyoonkim/notification/local/NotificationAlarmScheduler.kt @@ -29,12 +29,12 @@ interface AlarmScheduler { } class NotificationAlarmScheduler @Inject constructor( - @ApplicationContext private val context: Context + @ApplicationContext private val context: Context, + private val alarmManager: AlarmManager ) : AlarmScheduler { private val TAG = "NotificationAlarmScheduler" // AlarmManager Instance // Context: ApplicationContext - private val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager override fun createPendingIntent(target: BookmarkVO, nav: BookmarkInfo): PendingIntent { val uri = "knutice://service/bookmark/${nav.noticeId}/${Uri.encode(nav.noticeTitle)}/${Uri.encode(nav.noticeInfo)}" diff --git a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/di/BookmarkModule.kt b/feature/bookmark/src/main/java/com/doyoonkim/bookmark/di/BookmarkModules.kt similarity index 76% rename from feature/bookmark/src/main/java/com/doyoonkim/bookmark/di/BookmarkModule.kt rename to feature/bookmark/src/main/java/com/doyoonkim/bookmark/di/BookmarkModules.kt index c6432eb9..baa851c9 100644 --- a/feature/bookmark/src/main/java/com/doyoonkim/bookmark/di/BookmarkModule.kt +++ b/feature/bookmark/src/main/java/com/doyoonkim/bookmark/di/BookmarkModules.kt @@ -9,16 +9,17 @@ import dagger.Module import dagger.multibindings.IntoMap @Module -abstract class BookmarkModule { - +abstract class BookmarkListSceneModule { @Binds @IntoMap @ViewModelKey(BookmarkListViewModel::class) - abstract fun bindsBookmarkListViewModel(viewModel: BookmarkListViewModel): ViewModel + abstract fun bindsBookmarkListViewModel(vm: BookmarkListViewModel): ViewModel +} +@Module +abstract class EditBookmarkSceneModule { @Binds @IntoMap @ViewModelKey(EditBookmarkViewModel::class) abstract fun bindsEditBookmarkViewModel(viewModel: EditBookmarkViewModel): ViewModel - } \ No newline at end of file diff --git a/feature/main/src/main/java/com/doyoonkim/main/di/MainModule.kt b/feature/main/src/main/java/com/doyoonkim/main/di/MainModules.kt similarity index 56% rename from feature/main/src/main/java/com/doyoonkim/main/di/MainModule.kt rename to feature/main/src/main/java/com/doyoonkim/main/di/MainModules.kt index c9aef3a8..64553458 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/di/MainModule.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/di/MainModules.kt @@ -15,46 +15,65 @@ import dagger.Module import dagger.multibindings.IntoMap @Module -abstract class MainModule { - +abstract class HomeSceneModule { @Binds @IntoMap @ViewModelKey(HomeViewModel::class) - abstract fun bindsHomeViewModel(viewModel: HomeViewModel): ViewModel + abstract fun bindsViewModel(viewModel: HomeViewModel): ViewModel +} +@Module +abstract class NoticeDetailSceneModule { @Binds @IntoMap @ViewModelKey(NoticeDetailViewModel::class) - abstract fun bindsNoticeDetailViewModel(viewModel: NoticeDetailViewModel): ViewModel + abstract fun bindsViewModel(viewModel: NoticeDetailViewModel): ViewModel +} +@Module +abstract class NoticeSearchSceneModule { @Binds @IntoMap @ViewModelKey(NoticeSearchViewModel::class) - abstract fun bindsNoticeSearchViewModel(viewModel: NoticeSearchViewModel): ViewModel + abstract fun bindsViewModel(viewModel: NoticeSearchViewModel): ViewModel +} +@Module +abstract class NoticeInCategorySceneModule { @Binds @IntoMap @ViewModelKey(NoticesInCategoryViewModel::class) - abstract fun bindsNoticesInCategoryViewModel(viewModel: NoticesInCategoryViewModel): ViewModel - - @Binds - @IntoMap - @ViewModelKey(NotificationPreferencesViewModel::class) - abstract fun bindsNotificationPreferencesViewModel(viewModel: NotificationPreferencesViewModel): ViewModel + abstract fun bindsViewModel(viewModel: NoticesInCategoryViewModel): ViewModel +} +@Module +abstract class CustomerServiceSceneModule { @Binds @IntoMap @ViewModelKey(CustomerServiceViewModel::class) - abstract fun bindsCustomerServiceViewModel(viewModel:CustomerServiceViewModel): ViewModel + abstract fun bindsViewModel(viewModel: CustomerServiceViewModel): ViewModel +} +@Module +abstract class NotificationPreferencesSceneModule { @Binds @IntoMap - @ViewModelKey(SplashViewModel::class) - abstract fun bindsSplashViewModel(viewModel: SplashViewModel): ViewModel + @ViewModelKey(NotificationPreferencesViewModel::class) + abstract fun bindsViewModel(viewModel: NotificationPreferencesViewModel): ViewModel +} +@Module +abstract class SettingsSceneModule { @Binds @IntoMap @ViewModelKey(SettingsViewModel::class) - abstract fun bindsSettingsViewModel(viewModel: SettingsViewModel): ViewModel + abstract fun bindsViewModel(viewModel: SettingsViewModel): ViewModel +} +@Module +abstract class SplashSceneModule { + @Binds + @IntoMap + @ViewModelKey(SplashViewModel::class) + abstract fun bindsViewModel(viewModel: SplashViewModel): ViewModel } \ No newline at end of file diff --git a/feature/main/src/main/java/com/doyoonkim/main/home/HomeScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/home/HomeScreen.kt index 488332b6..144bbda1 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/home/HomeScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/home/HomeScreen.kt @@ -64,6 +64,7 @@ fun HomeScreen( onFullContentRequested: (Int, String) -> Unit, onTipClicked: (TipCategory, String) -> Unit ) { + val uiState by viewModel.uiState.collectAsState() // Back button/gesture actions @@ -114,12 +115,12 @@ fun HomeScreen( if (uiState.tips.isNotEmpty()) { TipContainer( modifier = Modifier.fillMaxWidth().wrapContentHeight(), - tipCategory = TipCategory.SYS_NOTICE, + tipCategory = TipCategory.UPDATES, containerColor = MaterialTheme.colorScheme.onAnyBackground, tipText = uiState.tips[0].title, ) { onTipClicked( - TipCategory.SYS_NOTICE, + TipCategory.UPDATES, uiState.tips[0].url ) } diff --git a/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeDetailScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeDetailScreen.kt index 8d8b2c3a..8ad0664e 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeDetailScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/notice/NoticeDetailScreen.kt @@ -114,14 +114,9 @@ fun NoticeDetailScreen( """ let div_accessibility = document.getElementById('accessibility'); let div_header = document.getElementById('header'); - let div_point = document.getElementById('point'); let div_footer = document.getElementById('footer'); - let div_footer_root = document.getElementById('fb-root'); - - let section_svisual = document.getElementById('svisual'); - let section_location = document.getElementById('location'); + let aside_remote = document.getElementById('remote'); - let p_board_butt = document.getElementsByClassName('board_butt'); div_accessibility.remove(); diff --git a/feature/main/src/main/java/com/doyoonkim/main/preference/CustomerServiceScreen.kt b/feature/main/src/main/java/com/doyoonkim/main/preference/CustomerServiceScreen.kt index d6d3877d..5652353d 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/preference/CustomerServiceScreen.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/preference/CustomerServiceScreen.kt @@ -38,6 +38,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.doyoonkim.main.viewmodel.CustomerServiceViewModel import com.doyoonkim.common.R @@ -160,41 +161,46 @@ fun CustomerServiceScreen( } } - AnimatedVisibility( - modifier = Modifier.wrapContentSize().align(Alignment.Center), - visible = uiState.isSubmissionCompleted, - enter = scaleIn(), - exit = scaleOut() - ) { - Surface( - modifier = Modifier.padding(15.dp) - .clip(RoundedCornerShape(15.dp)), - color = MaterialTheme.colorScheme.surfaceBright + if (uiState.isSubmissionCompleted) { + Dialog( + onDismissRequest = { /* Do nothing on onDismiss */ } ) { - Column( - modifier = Modifier.wrapContentHeight() - .padding(30.dp), - verticalArrangement = Arrangement.spacedBy(10.dp) + Surface( + modifier = Modifier.padding(15.dp) + .clip(RoundedCornerShape(15.dp)), + color = MaterialTheme.colorScheme.surfaceBright ) { - Text( - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - text = stringResource(R.string.submission_completed_title) - ) - Text( - fontSize = 14.sp, - fontWeight = FontWeight.Bold, - text = stringResource(R.string.submission_completed__subtitle) - ) - Button( - onClick = { viewModel.resetSubmissionStatus() }, - modifier = Modifier.fillMaxWidth() + Column( + modifier = Modifier.wrapContentHeight() + .padding(30.dp), + verticalArrangement = Arrangement.spacedBy(10.dp) ) { + Text( + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + text = stringResource( + if (!uiState.isSubmissionFailed) R.string.submission_completed_title + else R.string.error_submission_unavailable + ) + ) Text( fontSize = 14.sp, fontWeight = FontWeight.Bold, - text = stringResource(R.string.btn_confirm) + text = stringResource( + if (!uiState.isSubmissionFailed) R.string.submission_completed__subtitle + else R.string.error_submission_unavailable_description + ) ) + Button( + onClick = { viewModel.resetSubmissionStatus() }, + modifier = Modifier.fillMaxWidth() + ) { + Text( + fontSize = 14.sp, + fontWeight = FontWeight.Bold, + text = stringResource(R.string.btn_confirm) + ) + } } } } diff --git a/feature/main/src/main/java/com/doyoonkim/main/viewmodel/NoticeDetailViewModel.kt b/feature/main/src/main/java/com/doyoonkim/main/viewmodel/NoticeDetailViewModel.kt index 297a23bd..dcbe40dd 100644 --- a/feature/main/src/main/java/com/doyoonkim/main/viewmodel/NoticeDetailViewModel.kt +++ b/feature/main/src/main/java/com/doyoonkim/main/viewmodel/NoticeDetailViewModel.kt @@ -4,12 +4,10 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.doyoonkim.domain.usecases.FetchNoticeById import com.doyoonkim.model.NoticeVO -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject