Skip to content

Commit

Permalink
Implement repository pattern for datastore settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Taewan-P committed May 30, 2024
1 parent 17049da commit c97ebf4
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.chungjungsoo.gptmobile.data.dto

import dev.chungjungsoo.gptmobile.data.model.DynamicTheme
import dev.chungjungsoo.gptmobile.data.model.ThemeMode

data class ThemeSetting(
val dynamicTheme: DynamicTheme = DynamicTheme.OFF,
val themeMode: ThemeMode = ThemeMode.SYSTEM
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.chungjungsoo.gptmobile.data.repository

import dev.chungjungsoo.gptmobile.data.dto.Platform
import dev.chungjungsoo.gptmobile.data.dto.ThemeSetting

interface SettingRepository {
suspend fun fetchPlatforms(): List<Platform>
suspend fun fetchThemes(): ThemeSetting
suspend fun updatePlatforms(platforms: List<Platform>)
suspend fun updateThemes(themeSetting: ThemeSetting)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dev.chungjungsoo.gptmobile.data.repository

import dev.chungjungsoo.gptmobile.data.datastore.SettingDataSource
import dev.chungjungsoo.gptmobile.data.dto.Platform
import dev.chungjungsoo.gptmobile.data.dto.ThemeSetting
import dev.chungjungsoo.gptmobile.data.model.ApiType
import dev.chungjungsoo.gptmobile.data.model.DynamicTheme
import dev.chungjungsoo.gptmobile.data.model.ThemeMode
import javax.inject.Inject

class SettingRepositoryImpl @Inject constructor(
private val settingDataSource: SettingDataSource
) : SettingRepository {

override suspend fun fetchPlatforms(): List<Platform> {
return ApiType.entries.map { apiType ->
val status = settingDataSource.getStatus(apiType)
val token = settingDataSource.getToken(apiType)
val model = settingDataSource.getModel(apiType)

Platform(apiType, enabled = status ?: false, token = token, model = model)
}
}

override suspend fun fetchThemes(): ThemeSetting {
return ThemeSetting(
dynamicTheme = settingDataSource.getDynamicTheme() ?: DynamicTheme.OFF,
themeMode = settingDataSource.getThemeMode() ?: ThemeMode.SYSTEM
)
}

override suspend fun updatePlatforms(platforms: List<Platform>) {
platforms.forEach { platform ->
settingDataSource.updateStatus(platform.name, platform.selected)

if (platform.token != null) {
settingDataSource.updateToken(platform.name, platform.token)
}

if (platform.model != null) {
settingDataSource.updateModel(platform.name, platform.model)
}
}
}

override suspend fun updateThemes(themeSetting: ThemeSetting) {
settingDataSource.updateDynamicTheme(themeSetting.dynamicTheme)
settingDataSource.updateThemeMode(themeSetting.themeMode)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package dev.chungjungsoo.gptmobile.di

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dev.chungjungsoo.gptmobile.data.datastore.SettingDataSource
import dev.chungjungsoo.gptmobile.data.repository.SettingRepository
import dev.chungjungsoo.gptmobile.data.repository.SettingRepositoryImpl
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object SettingRepositoryModule {

@Provides
@Singleton
fun provideSettingRepository(
settingDataSource: SettingDataSource
): SettingRepository = SettingRepositoryImpl(settingDataSource)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@ package dev.chungjungsoo.gptmobile.presentation.common
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.chungjungsoo.gptmobile.data.datastore.SettingDataSource
import dev.chungjungsoo.gptmobile.data.dto.ThemeSetting
import dev.chungjungsoo.gptmobile.data.model.DynamicTheme
import dev.chungjungsoo.gptmobile.data.model.ThemeMode
import dev.chungjungsoo.gptmobile.data.repository.SettingRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

@HiltViewModel
class ThemeViewModel @Inject constructor(private val settingDataSource: SettingDataSource) : ViewModel() {

data class ThemeSetting(
val dynamicTheme: DynamicTheme = DynamicTheme.OFF,
val themeMode: ThemeMode = ThemeMode.SYSTEM
)
class ThemeViewModel @Inject constructor(private val settingRepository: SettingRepository) : ViewModel() {

private val _themeSetting = MutableStateFlow(ThemeSetting())
val themeSetting = _themeSetting.asStateFlow()
Expand All @@ -29,12 +25,7 @@ class ThemeViewModel @Inject constructor(private val settingDataSource: SettingD

private fun fetchThemes() {
viewModelScope.launch {
_themeSetting.update { setting ->
setting.copy(
dynamicTheme = settingDataSource.getDynamicTheme() ?: DynamicTheme.OFF,
themeMode = settingDataSource.getThemeMode() ?: ThemeMode.SYSTEM
)
}
_themeSetting.update { settingRepository.fetchThemes() }
}
}

Expand All @@ -43,7 +34,7 @@ class ThemeViewModel @Inject constructor(private val settingDataSource: SettingD
setting.copy(dynamicTheme = theme)
}
viewModelScope.launch {
settingDataSource.updateDynamicTheme(theme)
settingRepository.updateThemes(_themeSetting.value)
}
}

Expand All @@ -52,7 +43,7 @@ class ThemeViewModel @Inject constructor(private val settingDataSource: SettingD
setting.copy(themeMode = theme)
}
viewModelScope.launch {
settingDataSource.updateThemeMode(theme)
settingRepository.updateThemes(_themeSetting.value)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.chungjungsoo.gptmobile.data.database.entity.ChatRoom
import dev.chungjungsoo.gptmobile.data.datastore.SettingDataSource
import dev.chungjungsoo.gptmobile.data.dto.Platform
import dev.chungjungsoo.gptmobile.data.model.ApiType
import dev.chungjungsoo.gptmobile.data.repository.ChatRepository
import dev.chungjungsoo.gptmobile.data.repository.SettingRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand All @@ -19,7 +18,7 @@ import kotlinx.coroutines.launch
@HiltViewModel
class HomeViewModel @Inject constructor(
private val chatRepository: ChatRepository,
private val settingDataSource: SettingDataSource
private val settingRepository: SettingRepository
) : ViewModel() {

private val _chatList = MutableStateFlow(listOf<ChatRoom>())
Expand Down Expand Up @@ -74,13 +73,7 @@ class HomeViewModel @Inject constructor(

fun fetchPlatformStatus() {
viewModelScope.launch {
val platforms = ApiType.entries.map { apiType ->
val status = settingDataSource.getStatus(apiType)
val token = settingDataSource.getToken(apiType)
val model = settingDataSource.getModel(apiType)

Platform(apiType, enabled = status ?: false, token = token, model = model)
}
val platforms = settingRepository.fetchPlatforms()
_platformState.update { platforms }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package dev.chungjungsoo.gptmobile.presentation.ui.main
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.chungjungsoo.gptmobile.data.datastore.SettingDataSource
import dev.chungjungsoo.gptmobile.data.dto.Platform
import dev.chungjungsoo.gptmobile.data.model.ApiType
import dev.chungjungsoo.gptmobile.data.repository.SettingRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -17,7 +15,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

@HiltViewModel
class MainViewModel @Inject constructor(private val settingDataSource: SettingDataSource) : ViewModel() {
class MainViewModel @Inject constructor(private val settingRepository: SettingRepository) : ViewModel() {

sealed class SplashEvent {
data object OpenIntro : SplashEvent()
Expand Down Expand Up @@ -47,13 +45,7 @@ class MainViewModel @Inject constructor(private val settingDataSource: SettingDa
}
}

private suspend fun fetchPlatformSettings() = ApiType.entries.map { apiType ->
val status = settingDataSource.getStatus(apiType)
val token = settingDataSource.getToken(apiType)
val model = settingDataSource.getModel(apiType)

Platform(apiType, enabled = status ?: false, token = token, model = model)
}.filter { it.enabled }
private suspend fun fetchPlatformSettings() = settingRepository.fetchPlatforms().filter { it.enabled }

private suspend fun sendSplashEvent(event: SplashEvent) {
_event.emit(event)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package dev.chungjungsoo.gptmobile.presentation.ui.setting
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.chungjungsoo.gptmobile.data.datastore.SettingDataSource
import dev.chungjungsoo.gptmobile.data.dto.Platform
import dev.chungjungsoo.gptmobile.data.model.ApiType
import dev.chungjungsoo.gptmobile.data.repository.SettingRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand All @@ -15,7 +14,7 @@ import kotlinx.coroutines.launch

@HiltViewModel
class SettingViewModel @Inject constructor(
private val settingDataSource: SettingDataSource
private val settingRepository: SettingRepository
) : ViewModel() {

private val _platformState = MutableStateFlow(listOf<Platform>())
Expand All @@ -30,13 +29,7 @@ class SettingViewModel @Inject constructor(

fun fetchPlatformStatus() {
viewModelScope.launch {
val platforms = ApiType.entries.map { apiType ->
val status = settingDataSource.getStatus(apiType)
val token = settingDataSource.getToken(apiType)
val model = settingDataSource.getModel(apiType)

Platform(apiType, enabled = status ?: false, token = token, model = model)
}
val platforms = settingRepository.fetchPlatforms()
_platformState.update { platforms }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ fun SetupCompleteScreen(
Spacer(modifier = Modifier.weight(1f))
PrimaryLongButton(
onClick = {
setupViewModel.saveCheckedState()
setupViewModel.saveTokenState()
setupViewModel.saveModelState()
setupViewModel.savePlatformState()
val nextStep = setupViewModel.getNextSetupRoute(currentRoute)
onNavigate(nextStep)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package dev.chungjungsoo.gptmobile.presentation.ui.setup
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.chungjungsoo.gptmobile.data.datastore.SettingDataSource
import dev.chungjungsoo.gptmobile.data.dto.Platform
import dev.chungjungsoo.gptmobile.data.model.ApiType
import dev.chungjungsoo.gptmobile.data.repository.SettingRepository
import dev.chungjungsoo.gptmobile.presentation.common.Route
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -15,7 +15,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

@HiltViewModel
class SetupViewModel @Inject constructor(private val settingDataSource: SettingDataSource) : ViewModel() {
class SetupViewModel @Inject constructor(private val settingRepository: SettingRepository) : ViewModel() {

// LinkedHashSet should be used to guarantee item order
val openaiModels = linkedSetOf("gpt-4o", "gpt-4-turbo", "gpt-4", "gpt-3.5-turbo")
Expand Down Expand Up @@ -84,34 +84,12 @@ class SetupViewModel @Inject constructor(private val settingDataSource: SettingD
}
}

fun saveCheckedState() {
_platformState.value.forEach { platform ->
viewModelScope.launch {
settingDataSource.updateStatus(platform.name, platform.selected)
}
}
}

fun saveTokenState() {
_platformState.value.filter { it.selected && it.token != null }.forEach { platform ->
viewModelScope.launch {
settingDataSource.updateToken(platform.name, platform.token!!)
}
fun savePlatformState() {
viewModelScope.launch {
settingRepository.updatePlatforms(_platformState.value)
}
}

fun saveModelState() {
_platformState.value.filter { it.selected && it.token != null && it.model != null }.forEach { platform ->
viewModelScope.launch {
settingDataSource.updateModel(platform.name, platform.model!!)
}
}
}

fun setModel(apiType: ApiType, defaultModelIndex: Int): String {
return platformState.value.find { it.name == apiType }?.model ?: setDefaultModel(apiType, defaultModelIndex)
}

fun getNextSetupRoute(currentRoute: String?): String {
val steps = listOf(
Route.SELECT_PLATFORM,
Expand Down

0 comments on commit c97ebf4

Please sign in to comment.