Add pull to refresh on the Lexion.
This commit is contained in:
		
							parent
							
								
									6167999001
								
							
						
					
					
						commit
						c5fb8bf99e
					
				
					 7 changed files with 153 additions and 63 deletions
				
			
		| 
						 | 
				
			
			@ -2,7 +2,8 @@ package com.pixelized.rplexicon.ui.screens.authentication
 | 
			
		|||
 | 
			
		||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
 | 
			
		||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +19,6 @@ import androidx.compose.runtime.State
 | 
			
		|||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.graphics.Brush
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.text.AnnotatedString
 | 
			
		||||
import androidx.compose.ui.text.buildAnnotatedString
 | 
			
		||||
| 
						 | 
				
			
			@ -38,17 +38,21 @@ import kotlinx.coroutines.CoroutineScope
 | 
			
		|||
 | 
			
		||||
@Composable
 | 
			
		||||
fun AuthenticationScreen(
 | 
			
		||||
    viewModel: AuthenticationViewModel = hiltViewModel()
 | 
			
		||||
    authenticationVM: AuthenticationViewModel = hiltViewModel(),
 | 
			
		||||
    versionVM: VersionViewModel = hiltViewModel(),
 | 
			
		||||
) {
 | 
			
		||||
    val screen = LocalScreenNavHost.current
 | 
			
		||||
    val activity = LocalActivity.current
 | 
			
		||||
    val state = viewModel.rememberAuthenticationState()
 | 
			
		||||
    val state = authenticationVM.rememberAuthenticationState()
 | 
			
		||||
 | 
			
		||||
    Surface {
 | 
			
		||||
        AuthenticationScreenContent(
 | 
			
		||||
            modifier = Modifier.fillMaxSize(),
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .fillMaxSize()
 | 
			
		||||
                .padding(all = 16.dp),
 | 
			
		||||
            version = versionVM.version,
 | 
			
		||||
            onGoogleSignIn = {
 | 
			
		||||
                viewModel.signIn(activity = activity)
 | 
			
		||||
                authenticationVM.signIn(activity = activity)
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,34 +78,27 @@ fun HandleAuthenticationState(
 | 
			
		|||
@Composable
 | 
			
		||||
private fun AuthenticationScreenContent(
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    version: VersionViewModel.Version,
 | 
			
		||||
    onGoogleSignIn: () -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    Box(
 | 
			
		||||
    Column(
 | 
			
		||||
        modifier = modifier,
 | 
			
		||||
        contentAlignment = Alignment.BottomCenter,
 | 
			
		||||
        verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.Bottom),
 | 
			
		||||
        horizontalAlignment = Alignment.End,
 | 
			
		||||
    ) {
 | 
			
		||||
        Button(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .padding(all = 16.dp)
 | 
			
		||||
                .fillMaxWidth(),
 | 
			
		||||
            colors = ButtonDefaults.outlinedButtonColors(),
 | 
			
		||||
            colors = ButtonDefaults.buttonColors(),
 | 
			
		||||
            onClick = onGoogleSignIn,
 | 
			
		||||
        ) {
 | 
			
		||||
            Text(text = rememeberGoogleStringResource())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
private fun rememberBackgroundGradient(): Brush {
 | 
			
		||||
    val colorScheme = MaterialTheme.colorScheme
 | 
			
		||||
    return remember {
 | 
			
		||||
        Brush.verticalGradient(
 | 
			
		||||
            colors = listOf(
 | 
			
		||||
                colorScheme.surface.copy(alpha = 0.2f),
 | 
			
		||||
                colorScheme.surface.copy(alpha = 0.5f),
 | 
			
		||||
                colorScheme.surface.copy(alpha = 1.0f),
 | 
			
		||||
            )
 | 
			
		||||
        Text(
 | 
			
		||||
            style = MaterialTheme.typography.labelSmall,
 | 
			
		||||
            text = version.toText(),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -175,8 +172,14 @@ private fun rememeberGoogleStringResource(): AnnotatedString {
 | 
			
		|||
@Preview(uiMode = UI_MODE_NIGHT_YES)
 | 
			
		||||
private fun AuthenticationScreenContentPreview() {
 | 
			
		||||
    LexiconTheme {
 | 
			
		||||
        AuthenticationScreenContent(
 | 
			
		||||
            onGoogleSignIn = { },
 | 
			
		||||
        )
 | 
			
		||||
        Surface {
 | 
			
		||||
            AuthenticationScreenContent(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .fillMaxSize()
 | 
			
		||||
                    .padding(all = 16.dp),
 | 
			
		||||
                version = VersionViewModel.Version(R.string.app_name, "0.0.0", "0"),
 | 
			
		||||
                onGoogleSignIn = { },
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.screens.authentication
 | 
			
		||||
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.Stable
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import com.pixelized.rplexicon.BuildConfig
 | 
			
		||||
import com.pixelized.rplexicon.R
 | 
			
		||||
import dagger.hilt.android.lifecycle.HiltViewModel
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
@HiltViewModel
 | 
			
		||||
class VersionViewModel @Inject constructor() : ViewModel() {
 | 
			
		||||
 | 
			
		||||
    val version = Version(
 | 
			
		||||
        appName = R.string.app_name,
 | 
			
		||||
        version = BuildConfig.VERSION_NAME,
 | 
			
		||||
        code = BuildConfig.VERSION_CODE.toString()
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @Stable
 | 
			
		||||
    data class Version(
 | 
			
		||||
        @StringRes val appName: Int,
 | 
			
		||||
        val version: String,
 | 
			
		||||
        val code: String,
 | 
			
		||||
    ) {
 | 
			
		||||
        @Composable
 | 
			
		||||
        @Stable
 | 
			
		||||
        fun toText(): String {
 | 
			
		||||
            return "${stringResource(id = appName)} ${version}.${code}"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ class CharacterDetailViewModel @Inject constructor(
 | 
			
		|||
        val source = repository.data.value[savedStateHandle.characterDetailArgument.id]
 | 
			
		||||
        return CharacterDetailUio(
 | 
			
		||||
            name = source.name,
 | 
			
		||||
            diminutive = source.diminutive?.let { "./ $it" },
 | 
			
		||||
            diminutive = source.diminutive?.takeIf { it.isNotBlank() }?.let { "./ $it" },
 | 
			
		||||
            gender = when (source.gender) {
 | 
			
		||||
                Lexicon.Gender.MALE -> "homme"
 | 
			
		||||
                Lexicon.Gender.FEMALE -> "femme"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,13 +7,23 @@ import android.content.res.Configuration.UI_MODE_NIGHT_YES
 | 
			
		|||
import androidx.activity.compose.rememberLauncherForActivityResult
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.PaddingValues
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.foundation.lazy.items
 | 
			
		||||
import androidx.compose.material.ExperimentalMaterialApi
 | 
			
		||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
 | 
			
		||||
import androidx.compose.material.pullrefresh.PullRefreshState
 | 
			
		||||
import androidx.compose.material.pullrefresh.pullRefresh
 | 
			
		||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
 | 
			
		||||
import androidx.compose.material3.ExperimentalMaterial3Api
 | 
			
		||||
import androidx.compose.material3.Scaffold
 | 
			
		||||
import androidx.compose.material3.Surface
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.material3.TopAppBar
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.LaunchedEffect
 | 
			
		||||
import androidx.compose.runtime.Stable
 | 
			
		||||
| 
						 | 
				
			
			@ -21,11 +31,14 @@ 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.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.navigation.LocalScreenNavHost
 | 
			
		||||
import com.pixelized.rplexicon.ui.navigation.navigateToCharacterDetail
 | 
			
		||||
import com.pixelized.rplexicon.ui.screens.lexicon.LexiconErrorUio.Default
 | 
			
		||||
| 
						 | 
				
			
			@ -43,15 +56,28 @@ sealed class LexiconErrorUio {
 | 
			
		|||
    object Default : LexiconErrorUio()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterialApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
fun LexiconScreen(
 | 
			
		||||
    viewModel: LexiconViewModel = hiltViewModel(),
 | 
			
		||||
) {
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
    val screen = LocalScreenNavHost.current
 | 
			
		||||
 | 
			
		||||
    val refresh = rememberPullRefreshState(
 | 
			
		||||
        refreshing = viewModel.isLoading.value,
 | 
			
		||||
        onRefresh = {
 | 
			
		||||
            scope.launch {
 | 
			
		||||
                viewModel.fetchLexicon()
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    Surface {
 | 
			
		||||
        LexiconScreenContent(
 | 
			
		||||
            items = viewModel.items,
 | 
			
		||||
            refresh = refresh,
 | 
			
		||||
            refreshing = viewModel.isLoading,
 | 
			
		||||
            onItem = {
 | 
			
		||||
                screen.navigateToCharacterDetail(id = it.id)
 | 
			
		||||
            },
 | 
			
		||||
| 
						 | 
				
			
			@ -66,23 +92,49 @@ fun LexiconScreen(
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
private fun LexiconScreenContent(
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    refresh: PullRefreshState,
 | 
			
		||||
    refreshing: State<Boolean>,
 | 
			
		||||
    items: State<List<LexiconItemUio>>,
 | 
			
		||||
    onItem: (LexiconItemUio) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    LazyColumn(
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        modifier = modifier,
 | 
			
		||||
        contentPadding = PaddingValues(vertical = 8.dp),
 | 
			
		||||
        topBar = {
 | 
			
		||||
            TopAppBar(
 | 
			
		||||
                title = {
 | 
			
		||||
                    Text(text = stringResource(id = R.string.app_name))
 | 
			
		||||
                },
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    ) {
 | 
			
		||||
        items(items = items.value) {
 | 
			
		||||
            LexiconItem(
 | 
			
		||||
        Box(
 | 
			
		||||
            modifier = Modifier.padding(paddingValues = it),
 | 
			
		||||
            contentAlignment = Alignment.TopCenter,
 | 
			
		||||
        ) {
 | 
			
		||||
            LazyColumn(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .clickable { onItem(it) }
 | 
			
		||||
                    .fillMaxWidth()
 | 
			
		||||
                    .padding(vertical = 8.dp, horizontal = 16.dp),
 | 
			
		||||
                item = it,
 | 
			
		||||
                    .fillMaxSize()
 | 
			
		||||
                    .pullRefresh(state = refresh),
 | 
			
		||||
                contentPadding = PaddingValues(vertical = 8.dp),
 | 
			
		||||
            ) {
 | 
			
		||||
                items(items = items.value) { item ->
 | 
			
		||||
                    LexiconItem(
 | 
			
		||||
                        modifier = Modifier
 | 
			
		||||
                            .clickable { onItem(item) }
 | 
			
		||||
                            .fillMaxWidth()
 | 
			
		||||
                            .padding(vertical = 8.dp, horizontal = 16.dp),
 | 
			
		||||
                        item = item,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            PullRefreshIndicator(
 | 
			
		||||
                refreshing = refreshing.value,
 | 
			
		||||
                state = refresh,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +168,7 @@ fun HandleError(
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterialApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
 | 
			
		||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
 | 
			
		||||
| 
						 | 
				
			
			@ -124,6 +177,11 @@ private fun LexiconScreenContentPreview() {
 | 
			
		|||
        Surface {
 | 
			
		||||
            LexiconScreenContent(
 | 
			
		||||
                modifier = Modifier.fillMaxSize(),
 | 
			
		||||
                refresh = rememberPullRefreshState(
 | 
			
		||||
                    refreshing = false,
 | 
			
		||||
                    onRefresh = {},
 | 
			
		||||
                ),
 | 
			
		||||
                refreshing = remember { mutableStateOf(false) },
 | 
			
		||||
                items = remember {
 | 
			
		||||
                    mutableStateOf(
 | 
			
		||||
                        listOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,6 @@ import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecovera
 | 
			
		|||
import com.pixelized.rplexicon.model.Lexicon
 | 
			
		||||
import com.pixelized.rplexicon.repository.LexiconRepository
 | 
			
		||||
import dagger.hilt.android.lifecycle.HiltViewModel
 | 
			
		||||
import kotlinx.coroutines.delay
 | 
			
		||||
import kotlinx.coroutines.flow.MutableSharedFlow
 | 
			
		||||
import kotlinx.coroutines.flow.SharedFlow
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +19,9 @@ class LexiconViewModel @Inject constructor(
 | 
			
		|||
    private val repository: LexiconRepository,
 | 
			
		||||
) : ViewModel() {
 | 
			
		||||
 | 
			
		||||
    private val _isLoading = mutableStateOf(false)
 | 
			
		||||
    val isLoading: State<Boolean> get() = _isLoading
 | 
			
		||||
 | 
			
		||||
    private val _items = mutableStateOf<List<LexiconItemUio>>(emptyList())
 | 
			
		||||
    val items: State<List<LexiconItemUio>> get() = _items
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +54,7 @@ class LexiconViewModel @Inject constructor(
 | 
			
		|||
 | 
			
		||||
    suspend fun fetchLexicon() {
 | 
			
		||||
        try {
 | 
			
		||||
            _isLoading.value = true
 | 
			
		||||
            repository.fetchLexicon()
 | 
			
		||||
        }
 | 
			
		||||
        // user need to accept OAuth2 permission.
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +67,10 @@ class LexiconViewModel @Inject constructor(
 | 
			
		|||
            Log.e(TAG, exception.message, exception)
 | 
			
		||||
            _error.emit(LexiconErrorUio.Default)
 | 
			
		||||
        }
 | 
			
		||||
        // clean the laoding state
 | 
			
		||||
        finally {
 | 
			
		||||
            _isLoading.value = false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,13 @@
 | 
			
		|||
package com.pixelized.rplexicon.ui.theme
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import androidx.compose.foundation.isSystemInDarkTheme
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.darkColorScheme
 | 
			
		||||
import androidx.compose.material3.dynamicDarkColorScheme
 | 
			
		||||
import androidx.compose.material3.dynamicLightColorScheme
 | 
			
		||||
import androidx.compose.material3.lightColorScheme
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.SideEffect
 | 
			
		||||
import androidx.compose.ui.graphics.toArgb
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.platform.LocalView
 | 
			
		||||
import androidx.core.view.WindowCompat
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -25,42 +21,32 @@ private val LightColorScheme = lightColorScheme(
 | 
			
		|||
    primary = Purple40,
 | 
			
		||||
    secondary = PurpleGrey40,
 | 
			
		||||
    tertiary = Pink40
 | 
			
		||||
 | 
			
		||||
    /* Other default colors to override
 | 
			
		||||
    background = Color(0xFFFFFBFE),
 | 
			
		||||
    surface = Color(0xFFFFFBFE),
 | 
			
		||||
    onPrimary = Color.White,
 | 
			
		||||
    onSecondary = Color.White,
 | 
			
		||||
    onTertiary = Color.White,
 | 
			
		||||
    onBackground = Color(0xFF1C1B1F),
 | 
			
		||||
    onSurface = Color(0xFF1C1B1F),
 | 
			
		||||
    */
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun LexiconTheme(
 | 
			
		||||
    darkTheme: Boolean = isSystemInDarkTheme(),
 | 
			
		||||
    // Dynamic color is available on Android 12+
 | 
			
		||||
    dynamicColor: Boolean = true,
 | 
			
		||||
    content: @Composable () -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    val colorScheme = when {
 | 
			
		||||
//        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
 | 
			
		||||
//            val context = LocalContext.current
 | 
			
		||||
//            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
 | 
			
		||||
//        }
 | 
			
		||||
 | 
			
		||||
        darkTheme -> DarkColorScheme
 | 
			
		||||
        else -> LightColorScheme
 | 
			
		||||
    }
 | 
			
		||||
//    val view = LocalView.current
 | 
			
		||||
//    if (!view.isInEditMode) {
 | 
			
		||||
//        SideEffect {
 | 
			
		||||
//            val window = (view.context as Activity).window
 | 
			
		||||
//            window.statusBarColor = colorScheme.primary.toArgb()
 | 
			
		||||
//            WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
 | 
			
		||||
//        }
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    val view = LocalView.current
 | 
			
		||||
    if (!view.isInEditMode) {
 | 
			
		||||
        SideEffect {
 | 
			
		||||
            val window = (view.context as Activity).window
 | 
			
		||||
            colorScheme.background.toArgb().let {
 | 
			
		||||
                window.statusBarColor = it
 | 
			
		||||
                window.navigationBarColor = it
 | 
			
		||||
            }
 | 
			
		||||
            WindowCompat.getInsetsController(window, view).let {
 | 
			
		||||
                it.isAppearanceLightStatusBars = !darkTheme
 | 
			
		||||
                it.isAppearanceLightNavigationBars = !darkTheme
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MaterialTheme(
 | 
			
		||||
        colorScheme = colorScheme,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue