add map list tab
This commit is contained in:
		
							parent
							
								
									87a1471efe
								
							
						
					
					
						commit
						57d1273435
					
				
					 17 changed files with 527 additions and 82 deletions
				
			
		| 
						 | 
				
			
			@ -32,6 +32,7 @@ class LocationParser @Inject constructor() {
 | 
			
		|||
                            sheetIndex = index,
 | 
			
		||||
                            name = name,
 | 
			
		||||
                            uri = uri,
 | 
			
		||||
                            marquees = emptyList(),
 | 
			
		||||
                        )
 | 
			
		||||
                    } else {
 | 
			
		||||
                        null
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.composable.error
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import androidx.activity.compose.rememberLauncherForActivityResult
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.LaunchedEffect
 | 
			
		||||
import androidx.compose.runtime.Stable
 | 
			
		||||
import androidx.compose.runtime.rememberCoroutineScope
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import com.pixelized.rplexicon.LocalSnack
 | 
			
		||||
import com.pixelized.rplexicon.R
 | 
			
		||||
import kotlinx.coroutines.flow.SharedFlow
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
 | 
			
		||||
@Stable
 | 
			
		||||
sealed class FetchErrorUio {
 | 
			
		||||
    @Stable
 | 
			
		||||
    data class Permission(val intent: Intent) : FetchErrorUio()
 | 
			
		||||
 | 
			
		||||
    @Stable
 | 
			
		||||
    object Structure : FetchErrorUio()
 | 
			
		||||
 | 
			
		||||
    @Stable
 | 
			
		||||
    object Default : FetchErrorUio()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun HandleFetchError(
 | 
			
		||||
    errors: SharedFlow<FetchErrorUio>,
 | 
			
		||||
    onPermissionGranted: suspend () -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    val context = LocalContext.current
 | 
			
		||||
    val snack = LocalSnack.current
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
 | 
			
		||||
    val launcher = rememberLauncherForActivityResult(
 | 
			
		||||
        contract = ActivityResultContracts.StartActivityForResult(),
 | 
			
		||||
    ) { result ->
 | 
			
		||||
        if (result.resultCode == Activity.RESULT_OK) {
 | 
			
		||||
            scope.launch {
 | 
			
		||||
                onPermissionGranted()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LaunchedEffect(key1 = "LexiconErrorManagement") {
 | 
			
		||||
        errors.collect { error ->
 | 
			
		||||
            when (error) {
 | 
			
		||||
                is FetchErrorUio.Permission -> launcher.launch(error.intent)
 | 
			
		||||
                is FetchErrorUio.Structure -> snack.showSnackbar(message = context.getString(R.string.error_structure))
 | 
			
		||||
                is FetchErrorUio.Default -> snack.showSnackbar(message = context.getString(R.string.error_generic))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.navigation
 | 
			
		||||
 | 
			
		||||
import androidx.compose.animation.ExperimentalAnimationApi
 | 
			
		||||
import androidx.compose.foundation.layout.navigationBarsPadding
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyListState
 | 
			
		||||
import androidx.compose.material3.BottomAppBar
 | 
			
		||||
| 
						 | 
				
			
			@ -33,8 +32,10 @@ import com.pixelized.rplexicon.LocalSnack
 | 
			
		|||
import com.pixelized.rplexicon.R
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.pages.LEXICON_ROUTE
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.pages.composableLexicon
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.pages.composableQuestList
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.pages.composableLocations
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.pages.composableQuests
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.pages.navigateToLexicon
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.pages.navigateToLocation
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.pages.navigateToQuestList
 | 
			
		||||
 | 
			
		||||
val LocalPageNavHost = staticCompositionLocalOf<NavHostController> {
 | 
			
		||||
| 
						 | 
				
			
			@ -44,9 +45,11 @@ val LocalPageNavHost = staticCompositionLocalOf<NavHostController> {
 | 
			
		|||
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterial3Api::class)
 | 
			
		||||
@Composable
 | 
			
		||||
fun HomeNavHost(
 | 
			
		||||
    lexiconListState: LazyListState,
 | 
			
		||||
    navHostController: NavHostController = rememberAnimatedNavController(),
 | 
			
		||||
    bottomBarItems: List<BottomBarItem> = rememberBottomBarItems(navHostController = navHostController),
 | 
			
		||||
    bottomBarItems: List<BottomBarItem> = rememberBottomBarItems(navHostController),
 | 
			
		||||
    lexiconListState: LazyListState,
 | 
			
		||||
    questListState: LazyListState,
 | 
			
		||||
    locationListState: LazyListState,
 | 
			
		||||
    startDestination: String = LEXICON_ROUTE
 | 
			
		||||
) {
 | 
			
		||||
    CompositionLocalProvider(
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +76,8 @@ fun HomeNavHost(
 | 
			
		|||
                    tonalElevation = 0.dp,
 | 
			
		||||
                ) {
 | 
			
		||||
                    bottomBarItems.forEachIndexed { index, item ->
 | 
			
		||||
                        val selectedItem = remember { derivedStateOf { selectedIndex.value == index } }
 | 
			
		||||
                        val selectedItem =
 | 
			
		||||
                            remember { derivedStateOf { selectedIndex.value == index } }
 | 
			
		||||
                        NavigationBarItem(
 | 
			
		||||
                            selected = selectedItem.value,
 | 
			
		||||
                            onClick = {
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +107,8 @@ fun HomeNavHost(
 | 
			
		|||
                        startDestination = startDestination,
 | 
			
		||||
                    ) {
 | 
			
		||||
                        composableLexicon(lazyListState = lexiconListState)
 | 
			
		||||
                        composableQuestList()
 | 
			
		||||
                        composableQuests(lazyListState = questListState)
 | 
			
		||||
                        composableLocations(lazyListState = locationListState)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -124,17 +129,23 @@ private fun rememberBottomBarItems(
 | 
			
		|||
    navHostController: NavHostController,
 | 
			
		||||
): List<BottomBarItem> {
 | 
			
		||||
    return remember(navHostController) {
 | 
			
		||||
        val option = navHostController.pageOption()
 | 
			
		||||
        listOf(
 | 
			
		||||
            BottomBarItem(
 | 
			
		||||
                icon = R.drawable.ic_outline_account_circle_24,
 | 
			
		||||
                label = R.string.home_lexicon,
 | 
			
		||||
                onClick = { navHostController.navigateToLexicon(navHostController.pageOption()) }
 | 
			
		||||
                onClick = { navHostController.navigateToLexicon(option) }
 | 
			
		||||
            ),
 | 
			
		||||
            BottomBarItem(
 | 
			
		||||
                icon = R.drawable.ic_outline_scroll_24,
 | 
			
		||||
                label = R.string.home_quest_log,
 | 
			
		||||
                onClick = { navHostController.navigateToQuestList(option) }
 | 
			
		||||
            ),
 | 
			
		||||
            BottomBarItem(
 | 
			
		||||
                icon = R.drawable.ic_outline_map_24,
 | 
			
		||||
                label = R.string.home_quest_log,
 | 
			
		||||
                onClick = { navHostController.navigateToQuestList(navHostController.pageOption()) }
 | 
			
		||||
            ),
 | 
			
		||||
                label = R.string.home_location,
 | 
			
		||||
                onClick = { navHostController.navigateToLocation(option) }
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,9 @@ fun ScreenNavHost(
 | 
			
		|||
    navHostController: NavHostController = rememberAnimatedNavController(),
 | 
			
		||||
    startDestination: String = AUTHENTICATION_ROUTE,
 | 
			
		||||
) {
 | 
			
		||||
    val lexiconListState: LazyListState = rememberLazyListState()
 | 
			
		||||
    val lexiconListState =rememberLazyListState()
 | 
			
		||||
    val questListState = rememberLazyListState()
 | 
			
		||||
    val locationListState = rememberLazyListState()
 | 
			
		||||
 | 
			
		||||
    CompositionLocalProvider(
 | 
			
		||||
        LocalScreenNavHost provides navHostController,
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +40,11 @@ fun ScreenNavHost(
 | 
			
		|||
            startDestination = startDestination,
 | 
			
		||||
        ) {
 | 
			
		||||
            composableAuthentication()
 | 
			
		||||
            composableHome(lexiconListState)
 | 
			
		||||
            composableHome(
 | 
			
		||||
                lexiconListState = lexiconListState,
 | 
			
		||||
                questListState = questListState,
 | 
			
		||||
                locationListState = locationListState
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            composableLexiconDetail()
 | 
			
		||||
            composableLexiconSearch()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.navigation.pages
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyListState
 | 
			
		||||
import androidx.navigation.NavController
 | 
			
		||||
import androidx.navigation.NavGraphBuilder
 | 
			
		||||
import androidx.navigation.NavOptionsBuilder
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.NavigationAnimation
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.animatedComposable
 | 
			
		||||
import com.pixelized.rplexicon.ui.screens.location.list.LocationScreen
 | 
			
		||||
 | 
			
		||||
private const val ROUTE = "locations"
 | 
			
		||||
 | 
			
		||||
const val LOCATION_ROUTE = ROUTE
 | 
			
		||||
 | 
			
		||||
fun NavGraphBuilder.composableLocations(
 | 
			
		||||
    lazyListState: LazyListState,
 | 
			
		||||
) {
 | 
			
		||||
    animatedComposable(
 | 
			
		||||
        route = LOCATION_ROUTE,
 | 
			
		||||
        animation = NavigationAnimation.NONE,
 | 
			
		||||
    ) {
 | 
			
		||||
        LocationScreen(
 | 
			
		||||
            lazyListState = lazyListState,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun NavController.navigateToLocation(
 | 
			
		||||
    option: NavOptionsBuilder.() -> Unit = {},
 | 
			
		||||
) {
 | 
			
		||||
    navigate(route = ROUTE, builder = option)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.navigation.pages
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyListState
 | 
			
		||||
import androidx.navigation.NavGraphBuilder
 | 
			
		||||
import androidx.navigation.NavHostController
 | 
			
		||||
import androidx.navigation.NavOptionsBuilder
 | 
			
		||||
| 
						 | 
				
			
			@ -11,12 +12,14 @@ private const val ROUTE = "quests"
 | 
			
		|||
 | 
			
		||||
const val QUEST_LIST_ROUTE = ROUTE
 | 
			
		||||
 | 
			
		||||
fun NavGraphBuilder.composableQuestList() {
 | 
			
		||||
fun NavGraphBuilder.composableQuests(
 | 
			
		||||
    lazyListState: LazyListState,
 | 
			
		||||
) {
 | 
			
		||||
    animatedComposable(
 | 
			
		||||
        route = QUEST_LIST_ROUTE,
 | 
			
		||||
        animation = NavigationAnimation.NONE,
 | 
			
		||||
    ) {
 | 
			
		||||
        QuestListScreen()
 | 
			
		||||
        QuestListScreen(lazyListState = lazyListState)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,12 +14,18 @@ const val HOME_ROUTE = ROUTE
 | 
			
		|||
 | 
			
		||||
fun NavGraphBuilder.composableHome(
 | 
			
		||||
    lexiconListState: LazyListState,
 | 
			
		||||
    questListState: LazyListState,
 | 
			
		||||
    locationListState: LazyListState,
 | 
			
		||||
) {
 | 
			
		||||
    animatedComposable(
 | 
			
		||||
        route = HOME_ROUTE,
 | 
			
		||||
        animation = NavigationAnimation.Fade,
 | 
			
		||||
    ) {
 | 
			
		||||
        HomeNavHost(lexiconListState = lexiconListState)
 | 
			
		||||
        HomeNavHost(
 | 
			
		||||
            lexiconListState = lexiconListState,
 | 
			
		||||
            questListState = questListState,
 | 
			
		||||
            locationListState = locationListState
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,7 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.screens.lexicon.list
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
 | 
			
		||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
 | 
			
		||||
import androidx.activity.compose.rememberLauncherForActivityResult
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.compose.animation.AnimatedContent
 | 
			
		||||
import androidx.compose.animation.AnimatedVisibility
 | 
			
		||||
import androidx.compose.animation.ExperimentalAnimationApi
 | 
			
		||||
| 
						 | 
				
			
			@ -29,8 +25,6 @@ import androidx.compose.material3.MaterialTheme
 | 
			
		|||
import androidx.compose.material3.Surface
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.LaunchedEffect
 | 
			
		||||
import androidx.compose.runtime.Stable
 | 
			
		||||
import androidx.compose.runtime.State
 | 
			
		||||
import androidx.compose.runtime.derivedStateOf
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
| 
						 | 
				
			
			@ -38,39 +32,23 @@ import androidx.compose.runtime.remember
 | 
			
		|||
import androidx.compose.runtime.rememberCoroutineScope
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.res.painterResource
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import com.pixelized.rplexicon.LocalSnack
 | 
			
		||||
import com.pixelized.rplexicon.R
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.FloatingActionButton
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.Loader
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToLexiconDetail
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToLexiconSearch
 | 
			
		||||
import com.pixelized.rplexicon.ui.screens.lexicon.list.LexiconErrorUio.Default
 | 
			
		||||
import com.pixelized.rplexicon.ui.screens.lexicon.list.LexiconErrorUio.Permission
 | 
			
		||||
import com.pixelized.rplexicon.ui.screens.lexicon.list.LexiconErrorUio.Structure
 | 
			
		||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.extentions.cell
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
 | 
			
		||||
import kotlinx.coroutines.flow.SharedFlow
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
 | 
			
		||||
@Stable
 | 
			
		||||
sealed class LexiconErrorUio {
 | 
			
		||||
    @Stable
 | 
			
		||||
    data class Permission(val intent: Intent) : LexiconErrorUio()
 | 
			
		||||
 | 
			
		||||
    @Stable
 | 
			
		||||
    object Structure : LexiconErrorUio()
 | 
			
		||||
 | 
			
		||||
    @Stable
 | 
			
		||||
    object Default : LexiconErrorUio()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterialApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
| 
						 | 
				
			
			@ -111,9 +89,9 @@ fun LexiconScreen(
 | 
			
		|||
            },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        HandleError(
 | 
			
		||||
        HandleFetchError(
 | 
			
		||||
            errors = viewModel.error,
 | 
			
		||||
            onLexiconPermissionGranted = {
 | 
			
		||||
            onPermissionGranted = {
 | 
			
		||||
                viewModel.fetchLexicon()
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -216,36 +194,6 @@ private fun LexiconScreenContent(
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun HandleError(
 | 
			
		||||
    errors: SharedFlow<LexiconErrorUio>,
 | 
			
		||||
    onLexiconPermissionGranted: suspend () -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    val context = LocalContext.current
 | 
			
		||||
    val snack = LocalSnack.current
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
 | 
			
		||||
    val launcher = rememberLauncherForActivityResult(
 | 
			
		||||
        contract = ActivityResultContracts.StartActivityForResult(),
 | 
			
		||||
    ) { result ->
 | 
			
		||||
        if (result.resultCode == Activity.RESULT_OK) {
 | 
			
		||||
            scope.launch {
 | 
			
		||||
                onLexiconPermissionGranted()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LaunchedEffect(key1 = "LexiconErrorManagement") {
 | 
			
		||||
        errors.collect { error ->
 | 
			
		||||
            when (error) {
 | 
			
		||||
                is Permission -> launcher.launch(error.intent)
 | 
			
		||||
                is Structure -> snack.showSnackbar(message = context.getString(R.string.error_structure))
 | 
			
		||||
                is Default -> snack.showSnackbar(message = context.getString(R.string.error_generic))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterialApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecovera
 | 
			
		|||
import com.pixelized.rplexicon.R
 | 
			
		||||
import com.pixelized.rplexicon.model.Lexicon
 | 
			
		||||
import com.pixelized.rplexicon.repository.LexiconRepository
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
 | 
			
		||||
import dagger.hilt.android.lifecycle.HiltViewModel
 | 
			
		||||
import kotlinx.coroutines.flow.MutableSharedFlow
 | 
			
		||||
| 
						 | 
				
			
			@ -27,8 +28,8 @@ class LexiconViewModel @Inject constructor(
 | 
			
		|||
    private val _items = mutableStateOf<List<LexiconItemUio>>(emptyList())
 | 
			
		||||
    val items: State<List<LexiconItemUio>> get() = _items
 | 
			
		||||
 | 
			
		||||
    private val _error = MutableSharedFlow<LexiconErrorUio>()
 | 
			
		||||
    val error: SharedFlow<LexiconErrorUio> get() = _error
 | 
			
		||||
    private val _error = MutableSharedFlow<FetchErrorUio>()
 | 
			
		||||
    val error: SharedFlow<FetchErrorUio> get() = _error
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
| 
						 | 
				
			
			@ -77,15 +78,15 @@ class LexiconViewModel @Inject constructor(
 | 
			
		|||
        // user need to accept OAuth2 permission.
 | 
			
		||||
        catch (exception: UserRecoverableAuthIOException) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
            _error.emit(LexiconErrorUio.Permission(intent = exception.intent))
 | 
			
		||||
            _error.emit(FetchErrorUio.Permission(intent = exception.intent))
 | 
			
		||||
        } catch (exception: IncompatibleSheetStructure) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
            _error.emit(LexiconErrorUio.Structure)
 | 
			
		||||
            _error.emit(FetchErrorUio.Structure)
 | 
			
		||||
        }
 | 
			
		||||
        // default exception
 | 
			
		||||
        catch (exception: Exception) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
            _error.emit(LexiconErrorUio.Default)
 | 
			
		||||
            _error.emit(FetchErrorUio.Default)
 | 
			
		||||
        }
 | 
			
		||||
        // clean the laoding state
 | 
			
		||||
        finally {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.screens.location.list
 | 
			
		||||
 | 
			
		||||
import android.content.res.Configuration
 | 
			
		||||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Surface
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.Stable
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.text.AnnotatedString
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import androidx.compose.ui.tooling.preview.PreviewParameter
 | 
			
		||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.LOS_HOLLOW
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.extentions.cell
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.extentions.placeholder
 | 
			
		||||
 | 
			
		||||
@Stable
 | 
			
		||||
data class LocationItemUio(
 | 
			
		||||
    val id: Int,
 | 
			
		||||
    val title: String,
 | 
			
		||||
    val placeholder: Boolean = false,
 | 
			
		||||
) {
 | 
			
		||||
    companion object {
 | 
			
		||||
        fun preview(
 | 
			
		||||
            id: Int = 0,
 | 
			
		||||
            title: String = "Daggerfall",
 | 
			
		||||
            placeHolder: Boolean = false,
 | 
			
		||||
        ): LocationItemUio {
 | 
			
		||||
            return LocationItemUio(
 | 
			
		||||
                id = id,
 | 
			
		||||
                title = title,
 | 
			
		||||
                placeholder = placeHolder,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun LocationItem(
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    item: LocationItemUio,
 | 
			
		||||
) {
 | 
			
		||||
    val typography = MaterialTheme.lexicon.typography
 | 
			
		||||
 | 
			
		||||
    Box(
 | 
			
		||||
        modifier = modifier,
 | 
			
		||||
        contentAlignment = Alignment.CenterStart,
 | 
			
		||||
    ) {
 | 
			
		||||
        Row(
 | 
			
		||||
            horizontalArrangement = Arrangement.spacedBy(8.dp),
 | 
			
		||||
        ) {
 | 
			
		||||
            Text(
 | 
			
		||||
                modifier = when (item.placeholder) {
 | 
			
		||||
                    true -> Modifier.placeholder { true }
 | 
			
		||||
                    else -> Modifier.alignByBaseline()
 | 
			
		||||
                },
 | 
			
		||||
                text = LOS_HOLLOW,
 | 
			
		||||
            )
 | 
			
		||||
            Text(
 | 
			
		||||
                modifier = when (item.placeholder) {
 | 
			
		||||
                    true -> Modifier.placeholder { true }
 | 
			
		||||
                    else -> Modifier.alignByBaseline()
 | 
			
		||||
                },
 | 
			
		||||
                text = remember(item.placeholder) {
 | 
			
		||||
                    AnnotatedString(
 | 
			
		||||
                        text = item.title,
 | 
			
		||||
                        spanStyles = when (item.placeholder) {
 | 
			
		||||
                            true -> emptyList()
 | 
			
		||||
                            else -> listOf(
 | 
			
		||||
                                AnnotatedString.Range(
 | 
			
		||||
                                    item = typography.dropCapMediumSpan,
 | 
			
		||||
                                    start = 0,
 | 
			
		||||
                                    end = 1,
 | 
			
		||||
                                )
 | 
			
		||||
                            )
 | 
			
		||||
                        },
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
 | 
			
		||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
 | 
			
		||||
private fun QuestItemPreview(
 | 
			
		||||
    @PreviewParameter(QuestItemPreviewProvider::class) preview: LocationItemUio,
 | 
			
		||||
) {
 | 
			
		||||
    LexiconTheme {
 | 
			
		||||
        Surface {
 | 
			
		||||
            LocationItem(
 | 
			
		||||
                modifier = Modifier.cell(),
 | 
			
		||||
                item = preview,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private class QuestItemPreviewProvider : PreviewParameterProvider<LocationItemUio> {
 | 
			
		||||
    override val values: Sequence<LocationItemUio> = sequenceOf(
 | 
			
		||||
        LocationItemUio.preview(placeHolder = false),
 | 
			
		||||
        LocationItemUio.preview(placeHolder = true),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,167 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.screens.location.list
 | 
			
		||||
 | 
			
		||||
import android.content.res.Configuration
 | 
			
		||||
import androidx.compose.animation.AnimatedContent
 | 
			
		||||
import androidx.compose.animation.ExperimentalAnimationApi
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyListState
 | 
			
		||||
import androidx.compose.foundation.lazy.items
 | 
			
		||||
import androidx.compose.foundation.lazy.rememberLazyListState
 | 
			
		||||
import androidx.compose.material.ExperimentalMaterialApi
 | 
			
		||||
import androidx.compose.material.pullrefresh.PullRefreshState
 | 
			
		||||
import androidx.compose.material.pullrefresh.pullRefresh
 | 
			
		||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Surface
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.State
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.runtime.rememberCoroutineScope
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.Loader
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
 | 
			
		||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.extentions.cell
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterialApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
fun LocationScreen(
 | 
			
		||||
    viewModel: LocationViewModel = hiltViewModel(),
 | 
			
		||||
    lazyListState: LazyListState,
 | 
			
		||||
) {
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
    val screen = LocalScreenNavHost.current
 | 
			
		||||
 | 
			
		||||
    val refresh = rememberPullRefreshState(
 | 
			
		||||
        refreshing = false,
 | 
			
		||||
        onRefresh = {
 | 
			
		||||
            scope.launch {
 | 
			
		||||
                viewModel.fetchLocation()
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    Surface {
 | 
			
		||||
        LocationContent(
 | 
			
		||||
            items = viewModel.items,
 | 
			
		||||
            lazyColumnState = lazyListState,
 | 
			
		||||
            refreshState = refresh,
 | 
			
		||||
            refreshing = viewModel.isLoading,
 | 
			
		||||
            onItem = {
 | 
			
		||||
//                screen.navigateToQuestDetail(id = it.id)
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        HandleFetchError(
 | 
			
		||||
            errors = viewModel.error,
 | 
			
		||||
            onPermissionGranted = {
 | 
			
		||||
                viewModel.fetchLocation()
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterialApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
private fun LocationContent(
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    lazyColumnState: LazyListState,
 | 
			
		||||
    refreshState: PullRefreshState,
 | 
			
		||||
    refreshing: State<Boolean>,
 | 
			
		||||
    items: State<List<LocationItemUio>>,
 | 
			
		||||
    onItem: (LocationItemUio) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    Box(
 | 
			
		||||
        modifier = modifier,
 | 
			
		||||
        contentAlignment = Alignment.TopCenter,
 | 
			
		||||
    ) {
 | 
			
		||||
        AnimatedContent(
 | 
			
		||||
            targetState = items.value.isEmpty(),
 | 
			
		||||
            transitionSpec = MaterialTheme.lexicon.animation.itemList,
 | 
			
		||||
            label = "AnimatedLocations"
 | 
			
		||||
        ) { empty ->
 | 
			
		||||
            when (empty) {
 | 
			
		||||
                true -> LazyColumn(
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxSize()
 | 
			
		||||
                        .pullRefresh(state = refreshState),
 | 
			
		||||
                    state = lazyColumnState,
 | 
			
		||||
                    contentPadding = MaterialTheme.lexicon.dimens.itemListPadding,
 | 
			
		||||
                ) {
 | 
			
		||||
                    items(count = 2) {
 | 
			
		||||
                        LocationItem(
 | 
			
		||||
                            modifier = Modifier.cell(),
 | 
			
		||||
                            item = LocationItemUio.preview(placeHolder = true),
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                else -> LazyColumn(
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxSize()
 | 
			
		||||
                        .pullRefresh(state = refreshState),
 | 
			
		||||
                    state = lazyColumnState,
 | 
			
		||||
                    contentPadding = MaterialTheme.lexicon.dimens.itemListPadding,
 | 
			
		||||
                ) {
 | 
			
		||||
                    items(
 | 
			
		||||
                        items = items.value,
 | 
			
		||||
                        key = { it.id },
 | 
			
		||||
                        contentType = { "Location" },
 | 
			
		||||
                    ) {
 | 
			
		||||
                        LocationItem(
 | 
			
		||||
                            modifier = Modifier
 | 
			
		||||
                                .clickable { onItem(it) }
 | 
			
		||||
                                .cell(),
 | 
			
		||||
                            item = it,
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Loader(
 | 
			
		||||
            refreshState = refreshState,
 | 
			
		||||
            refreshing = refreshing,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterialApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
 | 
			
		||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
 | 
			
		||||
private fun QuestListPreview() {
 | 
			
		||||
    LexiconTheme {
 | 
			
		||||
        Surface {
 | 
			
		||||
            LocationContent(
 | 
			
		||||
                modifier = Modifier.fillMaxSize(),
 | 
			
		||||
                lazyColumnState = rememberLazyListState(),
 | 
			
		||||
                refreshState = rememberPullRefreshState(
 | 
			
		||||
                    refreshing = false,
 | 
			
		||||
                    onRefresh = {},
 | 
			
		||||
                ),
 | 
			
		||||
                refreshing = remember { mutableStateOf(false) },
 | 
			
		||||
                items = remember {
 | 
			
		||||
                    mutableStateOf(
 | 
			
		||||
                        listOf(
 | 
			
		||||
                            LocationItemUio.preview(id = 0, title = "Daggerfall"),
 | 
			
		||||
                            LocationItemUio.preview(id = 1, title = "Athkatla"),
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
                onItem = { },
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.screens.location.list
 | 
			
		||||
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import androidx.compose.runtime.State
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import androidx.lifecycle.viewModelScope
 | 
			
		||||
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException
 | 
			
		||||
import com.pixelized.rplexicon.repository.LocationRepository
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
 | 
			
		||||
import dagger.hilt.android.lifecycle.HiltViewModel
 | 
			
		||||
import kotlinx.coroutines.flow.MutableSharedFlow
 | 
			
		||||
import kotlinx.coroutines.flow.SharedFlow
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
@HiltViewModel
 | 
			
		||||
class LocationViewModel @Inject constructor(
 | 
			
		||||
    private val repository: LocationRepository,
 | 
			
		||||
) : ViewModel() {
 | 
			
		||||
 | 
			
		||||
    private val _isLoading = mutableStateOf(false)
 | 
			
		||||
    val isLoading: State<Boolean> get() = _isLoading
 | 
			
		||||
 | 
			
		||||
    private val _items = mutableStateOf<List<LocationItemUio>>(emptyList())
 | 
			
		||||
    val items: State<List<LocationItemUio>> get() = _items
 | 
			
		||||
 | 
			
		||||
    private val _error = MutableSharedFlow<FetchErrorUio>()
 | 
			
		||||
    val error: SharedFlow<FetchErrorUio> get() = _error
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            launch {
 | 
			
		||||
                repository.data.collect { items ->
 | 
			
		||||
                    _items.value = items.map { item ->
 | 
			
		||||
                        LocationItemUio(
 | 
			
		||||
                            id = item.id,
 | 
			
		||||
                            title = item.name,
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            launch {
 | 
			
		||||
                fetchLocation()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun fetchLocation() {
 | 
			
		||||
        try {
 | 
			
		||||
            _isLoading.value = true
 | 
			
		||||
            repository.fetchLocation()
 | 
			
		||||
        }
 | 
			
		||||
        // user need to accept OAuth2 permission.
 | 
			
		||||
        catch (exception: UserRecoverableAuthIOException) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
            _error.emit(FetchErrorUio.Permission(intent = exception.intent))
 | 
			
		||||
        } catch (exception: IncompatibleSheetStructure) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
            _error.emit(FetchErrorUio.Structure)
 | 
			
		||||
        }
 | 
			
		||||
        // default exception
 | 
			
		||||
        catch (exception: Exception) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
            _error.emit(FetchErrorUio.Default)
 | 
			
		||||
        }
 | 
			
		||||
        // clean the laoding state
 | 
			
		||||
        finally {
 | 
			
		||||
            _isLoading.value = false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val TAG = "LocationViewModel"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier
 | 
			
		|||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.Loader
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.error.HandleFetchError
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.screens.navigateToQuestDetail
 | 
			
		||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
 | 
			
		||||
| 
						 | 
				
			
			@ -38,9 +39,9 @@ import kotlinx.coroutines.launch
 | 
			
		|||
@Composable
 | 
			
		||||
fun QuestListScreen(
 | 
			
		||||
    viewModel: QuestListViewModel = hiltViewModel(),
 | 
			
		||||
    lazyListState: LazyListState,
 | 
			
		||||
) {
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
    val lazyListState = rememberLazyListState()
 | 
			
		||||
    val screen = LocalScreenNavHost.current
 | 
			
		||||
 | 
			
		||||
    val refresh = rememberPullRefreshState(
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +63,13 @@ fun QuestListScreen(
 | 
			
		|||
                screen.navigateToQuestDetail(id = it.id)
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        HandleFetchError(
 | 
			
		||||
            errors = viewModel.error,
 | 
			
		||||
            onPermissionGranted = {
 | 
			
		||||
                viewModel.fetchQuests()
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +118,7 @@ private fun QuestListContent(
 | 
			
		|||
                    items(
 | 
			
		||||
                        items = items.value,
 | 
			
		||||
                        key = { it.id },
 | 
			
		||||
                        contentType = { "Lexicon" },
 | 
			
		||||
                        contentType = { "Quest" },
 | 
			
		||||
                    ) {
 | 
			
		||||
                        QuestItem(
 | 
			
		||||
                            modifier = Modifier
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,8 +7,11 @@ import androidx.lifecycle.ViewModel
 | 
			
		|||
import androidx.lifecycle.viewModelScope
 | 
			
		||||
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException
 | 
			
		||||
import com.pixelized.rplexicon.repository.QuestRepository
 | 
			
		||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
 | 
			
		||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
 | 
			
		||||
import dagger.hilt.android.lifecycle.HiltViewModel
 | 
			
		||||
import kotlinx.coroutines.flow.MutableSharedFlow
 | 
			
		||||
import kotlinx.coroutines.flow.SharedFlow
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -23,8 +26,8 @@ class QuestListViewModel @Inject constructor(
 | 
			
		|||
    private val _items = mutableStateOf<List<QuestItemUio>>(emptyList())
 | 
			
		||||
    val items: State<List<QuestItemUio>> get() = _items
 | 
			
		||||
 | 
			
		||||
//    private val _error = MutableSharedFlow<LexiconErrorUio>()
 | 
			
		||||
//    val error: SharedFlow<LexiconErrorUio> get() = _error
 | 
			
		||||
    private val _error = MutableSharedFlow<FetchErrorUio>()
 | 
			
		||||
    val error: SharedFlow<FetchErrorUio> get() = _error
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
| 
						 | 
				
			
			@ -53,15 +56,15 @@ class QuestListViewModel @Inject constructor(
 | 
			
		|||
        // user need to accept OAuth2 permission.
 | 
			
		||||
        catch (exception: UserRecoverableAuthIOException) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
//                _error.emit(LexiconErrorUio.Permission(intent = exception.intent))
 | 
			
		||||
            _error.emit(FetchErrorUio.Permission(intent = exception.intent))
 | 
			
		||||
        } catch (exception: IncompatibleSheetStructure) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
//                _error.emit(LexiconErrorUio.Structure)
 | 
			
		||||
            _error.emit(FetchErrorUio.Structure)
 | 
			
		||||
        }
 | 
			
		||||
        // default exception
 | 
			
		||||
        catch (exception: Exception) {
 | 
			
		||||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
//                _error.emit(LexiconErrorUio.Default)
 | 
			
		||||
            _error.emit(FetchErrorUio.Default)
 | 
			
		||||
        }
 | 
			
		||||
        // clean the laoding state
 | 
			
		||||
        finally {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue