Add google signin & navigation.
This commit is contained in:
parent
6876ad7052
commit
f2357c6151
31 changed files with 764 additions and 114 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import com.android.build.gradle.internal.dsl.SigningConfig
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
|
|
@ -6,15 +8,24 @@ plugins {
|
|||
}
|
||||
|
||||
android {
|
||||
namespace = "com.pixelized.lexique"
|
||||
namespace = "com.pixelized.rplexicon"
|
||||
compileSdk = 33
|
||||
|
||||
signingConfigs {
|
||||
create("pixelized") {
|
||||
storeFile = file(project.properties["PIXELIZED_RELEASE_STORE_FILE"] as String)
|
||||
storePassword = project.properties["PIXELIZED_RELEASE_STORE_PASSWORD"] as String
|
||||
keyAlias = project.properties["PIXELIZED_RELEASE_KEY_ALIAS"] as String
|
||||
keyPassword = project.properties["PIXELIZED_RELEASE_KEY_PASSWORD"] as String
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.pixelized.lexique"
|
||||
applicationId = "com.pixelized.rplexicon"
|
||||
minSdk = 26
|
||||
targetSdk = 33
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
versionName = "0.1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
|
@ -24,10 +35,20 @@ android {
|
|||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
isDebuggable = false
|
||||
isMinifyEnabled = true
|
||||
signingConfig = signingConfigs.pixelized
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
debug {
|
||||
applicationIdSuffix = ".dev"
|
||||
isDebuggable = true
|
||||
isMinifyEnabled = false
|
||||
signingConfig = signingConfigs.pixelized
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -67,15 +88,24 @@ dependencies {
|
|||
implementation("androidx.compose.material3:material3:1.1.1")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling:1.4.3")
|
||||
|
||||
// Accompanist
|
||||
implementation("com.google.accompanist:accompanist-navigation-animation:0.30.1")
|
||||
implementation("com.google.accompanist:accompanist-placeholder:0.30.1")
|
||||
|
||||
// Hilt: Dependency injection
|
||||
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
|
||||
implementation("com.google.dagger:hilt-android:2.45")
|
||||
kapt("com.google.dagger:hilt-compiler:2.45")
|
||||
|
||||
// Google service
|
||||
implementation("com.google.android.gms:play-services-auth:20.6.0")
|
||||
|
||||
// Image
|
||||
implementation("com.github.skydoves:landscapist-glide:2.1.11")
|
||||
kapt("com.github.bumptech.glide:compiler:4.14.2") // this have to be align with landscapist-glide
|
||||
|
||||
// Retrofit : Network
|
||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
}
|
||||
}
|
||||
|
||||
private val NamedDomainObjectContainer<SigningConfig>.pixelized get() = this.getByName("pixelized")
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
package com.pixelized.lexique
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.pixelized.lexique.ui.screens.lexicon.LexiconScreen
|
||||
import com.pixelized.lexique.ui.theme.LexiconTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
LexiconTheme {
|
||||
// A surface container using the 'background' color from the theme
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
LexiconScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.pixelized.lexique.ui.screens.detail
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class CharacterDetailViewModel @Inject constructor() : ViewModel() {
|
||||
}
|
||||
48
app/src/main/java/com/pixelized/rplexicon/MainActivity.kt
Normal file
48
app/src/main/java/com/pixelized/rplexicon/MainActivity.kt
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package com.pixelized.rplexicon
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.pixelized.rplexicon.ui.navigation.ScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
val LocalActivity = staticCompositionLocalOf<Activity> { error("Activity not available") }
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
LexiconTheme {
|
||||
CompositionLocalProvider(
|
||||
LocalActivity provides this
|
||||
) {
|
||||
Scaffold(
|
||||
content = { padding ->
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues = padding),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
ScreenNavHost()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique
|
||||
package com.pixelized.rplexicon
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique.model
|
||||
package com.pixelized.rplexicon.model
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.pixelized.lexique.module
|
||||
package com.pixelized.rplexicon.module
|
||||
|
||||
import com.pixelized.lexique.network.IGoogleSpreadSheet
|
||||
import com.pixelized.rplexicon.network.IGoogleSpreadSheet
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique.network
|
||||
package com.pixelized.rplexicon.network
|
||||
|
||||
import retrofit2.http.GET
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.lexique.repository
|
||||
package com.pixelized.rplexicon.repository
|
||||
|
||||
import android.net.Uri
|
||||
import com.pixelized.lexique.model.Lexicon
|
||||
import com.pixelized.lexique.network.IGoogleSpreadSheet
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import com.pixelized.rplexicon.network.IGoogleSpreadSheet
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.pixelized.rplexicon.ui.navigation
|
||||
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavOptionsBuilder
|
||||
import com.pixelized.rplexicon.ui.screens.authentication.AuthenticationScreen
|
||||
|
||||
private const val ROUTE = "authentication"
|
||||
|
||||
const val AUTHENTICATION_ROUTE = ROUTE
|
||||
|
||||
fun NavGraphBuilder.composableAuthentication() {
|
||||
animatedComposable(
|
||||
route = AUTHENTICATION_ROUTE,
|
||||
animation = NavigationAnimation.Fade,
|
||||
) {
|
||||
AuthenticationScreen()
|
||||
}
|
||||
}
|
||||
|
||||
fun NavHostController.navigateToAuthentication(
|
||||
option: NavOptionsBuilder.() -> Unit = {},
|
||||
) {
|
||||
navigate(route = ROUTE, builder = option)
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.pixelized.rplexicon.ui.navigation
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavOptionsBuilder
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.navArgument
|
||||
import com.pixelized.rplexicon.ui.screens.detail.CharacterDetailScreen
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ARG
|
||||
|
||||
private const val ROUTE = "CharacterDetail"
|
||||
private const val ARG_ID = "id"
|
||||
val CHARACTER_DETAIL_ROUTE = "$ROUTE?${ARG_ID.ARG}"
|
||||
|
||||
@Stable
|
||||
@Immutable
|
||||
data class CharacterDetailArgument(
|
||||
val id: String,
|
||||
)
|
||||
|
||||
val SavedStateHandle.characterDetailArgument: CharacterDetailArgument
|
||||
get() = CharacterDetailArgument(
|
||||
id = get(ARG_ID) ?: error("CharacterDetailArgument argument: id")
|
||||
)
|
||||
|
||||
fun NavGraphBuilder.composableCharacterDetail() {
|
||||
animatedComposable(
|
||||
route = CHARACTER_DETAIL_ROUTE,
|
||||
arguments = listOf(
|
||||
navArgument(name = ARG_ID) {
|
||||
type = NavType.StringType
|
||||
}
|
||||
),
|
||||
animation = NavigationAnimation.Push,
|
||||
) {
|
||||
CharacterDetailScreen()
|
||||
}
|
||||
}
|
||||
|
||||
fun NavHostController.navigateToCharacterDetail(
|
||||
id: String,
|
||||
option: NavOptionsBuilder.() -> Unit = {},
|
||||
) {
|
||||
val route = "$ROUTE?$ARG_ID=$id"
|
||||
navigate(route = route, builder = option)
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.pixelized.rplexicon.ui.navigation
|
||||
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavOptionsBuilder
|
||||
import com.pixelized.rplexicon.ui.screens.lexicon.LexiconScreen
|
||||
|
||||
private const val ROUTE = "lexicon"
|
||||
|
||||
const val LEXICON_ROUTE = ROUTE
|
||||
|
||||
fun NavGraphBuilder.composableLexicon() {
|
||||
animatedComposable(
|
||||
route = LEXICON_ROUTE,
|
||||
animation = NavigationAnimation.Fade,
|
||||
) {
|
||||
LexiconScreen()
|
||||
}
|
||||
}
|
||||
|
||||
fun NavHostController.navigateToLexicon(
|
||||
option: NavOptionsBuilder.() -> Unit = {},
|
||||
) {
|
||||
navigate(route = ROUTE, builder = option)
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.pixelized.rplexicon.ui.navigation
|
||||
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavOptionsBuilder
|
||||
import com.google.accompanist.navigation.animation.AnimatedNavHost
|
||||
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
||||
|
||||
val LocalScreenNavHost = staticCompositionLocalOf<NavHostController> {
|
||||
error("LocalScreenNavHost not ready")
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
@Composable
|
||||
fun ScreenNavHost(
|
||||
navHostController: NavHostController = rememberAnimatedNavController(),
|
||||
startDestination: String = AUTHENTICATION_ROUTE,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalScreenNavHost provides navHostController,
|
||||
) {
|
||||
AnimatedNavHost(
|
||||
navController = navHostController,
|
||||
startDestination = startDestination,
|
||||
) {
|
||||
composableAuthentication()
|
||||
composableLexicon()
|
||||
composableCharacterDetail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun defaultOption(): NavOptionsBuilder.() -> Unit = { }
|
||||
|
||||
fun rootOption(): NavOptionsBuilder.() -> Unit = {
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
popUpTo(0) {
|
||||
saveState = true
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package com.pixelized.rplexicon.ui.navigation
|
||||
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.NamedNavArgument
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import com.google.accompanist.navigation.animation.composable
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
fun NavGraphBuilder.animatedComposable(
|
||||
route: String,
|
||||
arguments: List<NamedNavArgument> = emptyList(),
|
||||
animation: NavigationAnimation = NavigationAnimation.NONE,
|
||||
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit,
|
||||
) {
|
||||
composable(
|
||||
route = route,
|
||||
arguments = arguments,
|
||||
enterTransition = animation.enterTransition,
|
||||
exitTransition = animation.exitTransition,
|
||||
popEnterTransition = animation.popEnterTransition,
|
||||
popExitTransition = animation.popExitTransition,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
sealed class NavigationAnimation constructor(
|
||||
val enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)?,
|
||||
val exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)?,
|
||||
val popEnterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)?,
|
||||
val popExitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)?,
|
||||
) {
|
||||
object Push : NavigationAnimation(
|
||||
enterTransition = {
|
||||
slideIntoContainer(
|
||||
towards = AnimatedContentScope.SlideDirection.Left,
|
||||
animationSpec = tween(DURATION),
|
||||
)
|
||||
},
|
||||
exitTransition = {
|
||||
null
|
||||
},
|
||||
popEnterTransition = {
|
||||
null
|
||||
},
|
||||
popExitTransition = {
|
||||
slideOutOfContainer(
|
||||
towards = AnimatedContentScope.SlideDirection.Right,
|
||||
animationSpec = tween(DURATION),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
object Modal : NavigationAnimation(
|
||||
enterTransition = {
|
||||
slideIntoContainer(
|
||||
towards = AnimatedContentScope.SlideDirection.Up,
|
||||
animationSpec = tween(DURATION),
|
||||
)
|
||||
},
|
||||
exitTransition = {
|
||||
null
|
||||
},
|
||||
popEnterTransition = {
|
||||
null
|
||||
},
|
||||
popExitTransition = {
|
||||
slideOutOfContainer(
|
||||
towards = AnimatedContentScope.SlideDirection.Down,
|
||||
animationSpec = tween(DURATION),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
object Fade : NavigationAnimation(
|
||||
enterTransition = {
|
||||
fadeIn(
|
||||
animationSpec = tween(DURATION),
|
||||
)
|
||||
},
|
||||
exitTransition = {
|
||||
null
|
||||
},
|
||||
popEnterTransition = {
|
||||
null
|
||||
},
|
||||
popExitTransition = {
|
||||
fadeOut(
|
||||
animationSpec = tween(DURATION),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
object NONE : NavigationAnimation(
|
||||
enterTransition = null,
|
||||
exitTransition = null,
|
||||
popEnterTransition = null,
|
||||
popExitTransition = null,
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val DURATION = 300
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
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.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
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.LocalActivity
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.navigation.navigateToLexicon
|
||||
import com.pixelized.rplexicon.ui.navigation.rootOption
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.ui.theme.colors.GoogleColorPalette
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@Composable
|
||||
fun AuthenticationScreen(
|
||||
viewModel: AuthenticationViewModel = hiltViewModel()
|
||||
) {
|
||||
val screen = LocalScreenNavHost.current
|
||||
val activity = LocalActivity.current
|
||||
val state = viewModel.rememberAuthenticationState(activity = activity)
|
||||
|
||||
Surface {
|
||||
AuthenticationScreenContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
onGoogleSignIn = {
|
||||
viewModel.signIn(activity = activity)
|
||||
},
|
||||
)
|
||||
|
||||
HandleAuthenticationState(
|
||||
state = state,
|
||||
onSignIn = {
|
||||
screen.navigateToLexicon(option = rootOption())
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HandleAuthenticationState(
|
||||
state: State<AuthenticationViewModel.Authentication>,
|
||||
onSignIn: suspend CoroutineScope.() -> Unit
|
||||
) {
|
||||
if (state.value == AuthenticationViewModel.Authentication.Success) {
|
||||
LaunchedEffect(key1 = "Authentication.Success", block = onSignIn)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AuthenticationScreenContent(
|
||||
modifier: Modifier = Modifier,
|
||||
onGoogleSignIn: () -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier,
|
||||
contentAlignment = Alignment.BottomCenter,
|
||||
) {
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.padding(all = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
colors = ButtonDefaults.outlinedButtonColors(),
|
||||
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),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememeberGoogleStringResource(): AnnotatedString {
|
||||
val default = LocalTextStyle.current.toSpanStyle()
|
||||
val google = stringResource(id = R.string.action_google_sign_in)
|
||||
return remember {
|
||||
buildAnnotatedString {
|
||||
withStyle(
|
||||
style = default
|
||||
) {
|
||||
append(google)
|
||||
append(" ")
|
||||
}
|
||||
withStyle(
|
||||
style = default.copy(
|
||||
color = GoogleColorPalette.BLUE,
|
||||
fontWeight = FontWeight.ExtraBold
|
||||
),
|
||||
) {
|
||||
append("G")
|
||||
}
|
||||
withStyle(
|
||||
style = default.copy(
|
||||
color = GoogleColorPalette.RED,
|
||||
fontWeight = FontWeight.ExtraBold
|
||||
),
|
||||
) {
|
||||
append("o")
|
||||
}
|
||||
withStyle(
|
||||
style = default.copy(
|
||||
color = GoogleColorPalette.YELLOW,
|
||||
fontWeight = FontWeight.ExtraBold
|
||||
),
|
||||
) {
|
||||
append("o")
|
||||
}
|
||||
withStyle(
|
||||
style = default.copy(
|
||||
color = GoogleColorPalette.BLUE,
|
||||
fontWeight = FontWeight.ExtraBold
|
||||
),
|
||||
) {
|
||||
append("g")
|
||||
}
|
||||
withStyle(
|
||||
style = default.copy(
|
||||
color = GoogleColorPalette.GREEN,
|
||||
fontWeight = FontWeight.ExtraBold
|
||||
),
|
||||
) {
|
||||
append("l")
|
||||
}
|
||||
withStyle(
|
||||
style = default.copy(
|
||||
color = GoogleColorPalette.RED,
|
||||
fontWeight = FontWeight.ExtraBold
|
||||
),
|
||||
) {
|
||||
append("e")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun AuthenticationScreenContentPreview() {
|
||||
LexiconTheme {
|
||||
AuthenticationScreenContent(
|
||||
onGoogleSignIn = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package com.pixelized.rplexicon.ui.screens.authentication
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.IntentSender.SendIntentException
|
||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.IntentSenderRequest
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import com.google.android.gms.auth.api.identity.GetSignInIntentRequest
|
||||
import com.google.android.gms.auth.api.identity.Identity
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||
import com.pixelized.rplexicon.R
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AuthenticationViewModel @Inject constructor(
|
||||
application: Application,
|
||||
) : AndroidViewModel(application) {
|
||||
|
||||
private val context: Context get() = getApplication()
|
||||
private var launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>? = null
|
||||
|
||||
private val account: GoogleSignInAccount? by lazy {
|
||||
GoogleSignIn.getLastSignedInAccount(application)
|
||||
}
|
||||
|
||||
private val lastGoogleToken: String? by lazy {
|
||||
GoogleSignIn.getLastSignedInAccount(application)?.idToken
|
||||
}
|
||||
|
||||
private val state = mutableStateOf(
|
||||
when (account) {
|
||||
null -> Authentication.Initial
|
||||
else -> Authentication.Success
|
||||
}
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun rememberAuthenticationState(activity: Activity): State<Authentication> {
|
||||
launcher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.StartIntentSenderForResult(),
|
||||
onResult = {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
val credential = Identity
|
||||
.getSignInClient(activity)
|
||||
.getSignInCredentialFromIntent(it.data)
|
||||
state.value = Authentication.Success
|
||||
} else {
|
||||
state.value = Authentication.Failure
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
fun signIn(activity: Activity) {
|
||||
state.value = Authentication.Initial
|
||||
|
||||
val request: GetSignInIntentRequest = GetSignInIntentRequest.builder()
|
||||
.setServerClientId(context.getString(R.string.google_sign_in_id))
|
||||
.build()
|
||||
|
||||
Identity.getSignInClient(activity).getSignInIntent(request)
|
||||
.addOnSuccessListener { result ->
|
||||
try {
|
||||
launcher?.launch(
|
||||
IntentSenderRequest.Builder(result.intentSender).build()
|
||||
)
|
||||
} catch (e: SendIntentException) {
|
||||
state.value = Authentication.Failure
|
||||
}
|
||||
}
|
||||
.addOnFailureListener { e ->
|
||||
state.value = Authentication.Failure
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
sealed class Authentication {
|
||||
object Initial : Authentication()
|
||||
object Success : Authentication()
|
||||
object Failure : Authentication()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique.ui.screens.detail
|
||||
package com.pixelized.rplexicon.ui.screens.detail
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
|
|
@ -32,6 +32,8 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -50,8 +52,8 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.lexique.R
|
||||
import com.pixelized.lexique.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.skydoves.landscapist.ImageOptions
|
||||
import com.skydoves.landscapist.glide.GlideImage
|
||||
|
||||
|
|
@ -70,7 +72,14 @@ data class CharacterDetailUio(
|
|||
fun CharacterDetailScreen(
|
||||
viewModel: CharacterDetailViewModel = hiltViewModel(),
|
||||
) {
|
||||
|
||||
Surface {
|
||||
CharacterDetailScreenContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
item = viewModel.character,
|
||||
onBack = { },
|
||||
onItem = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
|
||||
|
|
@ -78,8 +87,9 @@ fun CharacterDetailScreen(
|
|||
private fun CharacterDetailScreenContent(
|
||||
modifier: Modifier = Modifier,
|
||||
state: ScrollState = rememberScrollState(),
|
||||
item: CharacterDetailUio,
|
||||
item: State<CharacterDetailUio>,
|
||||
onBack: () -> Unit,
|
||||
onItem: () -> Unit,
|
||||
) {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val typography = MaterialTheme.typography
|
||||
|
|
@ -104,7 +114,7 @@ private fun CharacterDetailScreenContent(
|
|||
Box(
|
||||
modifier = Modifier.padding(paddingValues = paddingValues),
|
||||
) {
|
||||
item.portrait.firstOrNull()?.let { uri ->
|
||||
item.value.portrait.firstOrNull()?.let { uri ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -142,14 +152,14 @@ private fun CharacterDetailScreenContent(
|
|||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
item.name?.let {
|
||||
item.value.name?.let {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = typography.headlineSmall,
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
item.diminutive?.let {
|
||||
item.value.diminutive?.let {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = remember { typography.labelMedium.copy(fontStyle = FontStyle.Italic) },
|
||||
|
|
@ -161,20 +171,20 @@ private fun CharacterDetailScreenContent(
|
|||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
item.race?.let {
|
||||
item.value.race?.let {
|
||||
Text(
|
||||
style = remember { typography.labelMedium.copy(fontStyle = FontStyle.Italic) },
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
item.gender?.let {
|
||||
item.value.gender?.let {
|
||||
Text(
|
||||
style = remember { typography.labelMedium.copy(fontStyle = FontStyle.Italic) },
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
item.description?.let {
|
||||
item.value.description?.let {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp),
|
||||
style = typography.titleMedium,
|
||||
|
|
@ -193,7 +203,7 @@ private fun CharacterDetailScreenContent(
|
|||
text = it,
|
||||
)
|
||||
}
|
||||
item.history?.let {
|
||||
item.value.history?.let {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp),
|
||||
style = typography.titleMedium,
|
||||
|
|
@ -205,7 +215,7 @@ private fun CharacterDetailScreenContent(
|
|||
text = it,
|
||||
)
|
||||
}
|
||||
if (item.portrait.isNotEmpty()) {
|
||||
if (item.value.portrait.isNotEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp),
|
||||
style = typography.titleMedium,
|
||||
|
|
@ -215,7 +225,7 @@ private fun CharacterDetailScreenContent(
|
|||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
items(items = item.portrait) {
|
||||
items(items = item.value.portrait) {
|
||||
GlideImage(
|
||||
modifier = Modifier.height(320.dp),
|
||||
imageModel = { it },
|
||||
|
|
@ -261,29 +271,35 @@ private fun Modifier.scrollOffset(
|
|||
private fun CharacterDetailScreenContentPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
val character = remember {
|
||||
mutableStateOf(
|
||||
CharacterDetailUio(
|
||||
name = "Brulkhai",
|
||||
diminutive = "./ Bru",
|
||||
gender = "female",
|
||||
race = "Demi-Orc",
|
||||
portrait = listOf(
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/889/large/bayard-wu-0716.jpg?1468642855"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/877/large/bayard-wu-0714.jpg?1468642665"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/887/large/bayard-wu-0715.jpg?1468642839"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/891/large/bayard-wu-0623-03.jpg?1468642872"),
|
||||
Uri.parse("https://cdna.artstation.com/p/assets/images/images/002/869/868/large/bayard-wu-0622-03.jpg?1466664135"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/002/869/871/large/bayard-wu-0622-04.jpg?1466664153"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/347/181/large/bayard-wu-1217.jpg?1482770883"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/635/large/bayard-wu-1215.jpg?1482166826"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/631/large/bayard-wu-1209.jpg?1482166803"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/641/large/bayard-wu-1212.jpg?1482166838"),
|
||||
),
|
||||
description = "Brulkhai, ou plus simplement Bru, est solidement bâti. Elle mesure 192 cm pour 110 kg de muscles lorsqu’elle est en bonne santé. Elle a les cheveux châtains, les yeux noisettes et la peau couleur gris-vert typique de son espèce. D’un tempérament taciturne, elle parle peu et de façon concise. Elle est parfois brutale, aussi bien physiquement que verbalement, Elle ne prend cependant aucun plaisir à malmener ceux qu’elle considère plus faibles qu’elle. D’une nature simple et honnête, elle ne mâche pas ses mots et ne dissimule généralement pas ses pensées. Son intelligence modeste est plus le reflet d’un manque d’éducation et d’une capacité limitée à gérer ses émotions qu’à une débilité congénitale. Elle voue à la force un culte car c’est par son expression qu’elle se sent vraiment vivante et éprouve de grandes difficultés vis à vis de ceux qu’elle nomme foshnu (bébé, chouineur en commun).",
|
||||
history = null,
|
||||
)
|
||||
)
|
||||
}
|
||||
CharacterDetailScreenContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
item = CharacterDetailUio(
|
||||
name = "Brulkhai",
|
||||
diminutive = "./ Bru",
|
||||
gender = "female",
|
||||
race = "Demi-Orc",
|
||||
portrait = listOf(
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/889/large/bayard-wu-0716.jpg?1468642855"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/877/large/bayard-wu-0714.jpg?1468642665"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/887/large/bayard-wu-0715.jpg?1468642839"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/891/large/bayard-wu-0623-03.jpg?1468642872"),
|
||||
Uri.parse("https://cdna.artstation.com/p/assets/images/images/002/869/868/large/bayard-wu-0622-03.jpg?1466664135"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/002/869/871/large/bayard-wu-0622-04.jpg?1466664153"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/347/181/large/bayard-wu-1217.jpg?1482770883"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/635/large/bayard-wu-1215.jpg?1482166826"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/631/large/bayard-wu-1209.jpg?1482166803"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/641/large/bayard-wu-1212.jpg?1482166838"),
|
||||
),
|
||||
description = "Brulkhai, ou plus simplement Bru, est solidement bâti. Elle mesure 192 cm pour 110 kg de muscles lorsqu’elle est en bonne santé. Elle a les cheveux châtains, les yeux noisettes et la peau couleur gris-vert typique de son espèce. D’un tempérament taciturne, elle parle peu et de façon concise. Elle est parfois brutale, aussi bien physiquement que verbalement, Elle ne prend cependant aucun plaisir à malmener ceux qu’elle considère plus faibles qu’elle. D’une nature simple et honnête, elle ne mâche pas ses mots et ne dissimule généralement pas ses pensées. Son intelligence modeste est plus le reflet d’un manque d’éducation et d’une capacité limitée à gérer ses émotions qu’à une débilité congénitale. Elle voue à la force un culte car c’est par son expression qu’elle se sent vraiment vivante et éprouve de grandes difficultés vis à vis de ceux qu’elle nomme foshnu (bébé, chouineur en commun).",
|
||||
history = null,
|
||||
),
|
||||
item = character,
|
||||
onBack = { },
|
||||
onItem = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.pixelized.rplexicon.ui.screens.detail
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class CharacterDetailViewModel @Inject constructor() : ViewModel() {
|
||||
|
||||
val character: State<CharacterDetailUio> = mutableStateOf(
|
||||
CharacterDetailUio(
|
||||
name = "Brulkhai",
|
||||
diminutive = "./ Bru",
|
||||
gender = "female",
|
||||
race = "Demi-Orc",
|
||||
portrait = listOf(
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/889/large/bayard-wu-0716.jpg?1468642855"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/877/large/bayard-wu-0714.jpg?1468642665"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/887/large/bayard-wu-0715.jpg?1468642839"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/003/024/891/large/bayard-wu-0623-03.jpg?1468642872"),
|
||||
Uri.parse("https://cdna.artstation.com/p/assets/images/images/002/869/868/large/bayard-wu-0622-03.jpg?1466664135"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/002/869/871/large/bayard-wu-0622-04.jpg?1466664153"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/347/181/large/bayard-wu-1217.jpg?1482770883"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/635/large/bayard-wu-1215.jpg?1482166826"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/631/large/bayard-wu-1209.jpg?1482166803"),
|
||||
Uri.parse("https://cdnb.artstation.com/p/assets/images/images/004/297/641/large/bayard-wu-1212.jpg?1482166838"),
|
||||
),
|
||||
description = "Brulkhai, ou plus simplement Bru, est solidement bâti. Elle mesure 192 cm pour 110 kg de muscles lorsqu’elle est en bonne santé. Elle a les cheveux châtains, les yeux noisettes et la peau couleur gris-vert typique de son espèce. D’un tempérament taciturne, elle parle peu et de façon concise. Elle est parfois brutale, aussi bien physiquement que verbalement, Elle ne prend cependant aucun plaisir à malmener ceux qu’elle considère plus faibles qu’elle. D’une nature simple et honnête, elle ne mâche pas ses mots et ne dissimule généralement pas ses pensées. Son intelligence modeste est plus le reflet d’un manque d’éducation et d’une capacité limitée à gérer ses émotions qu’à une débilité congénitale. Elle voue à la force un culte car c’est par son expression qu’elle se sent vraiment vivante et éprouve de grandes difficultés vis à vis de ceux qu’elle nomme foshnu (bébé, chouineur en commun).",
|
||||
history = null,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique.ui.screens.lexicon
|
||||
package com.pixelized.rplexicon.ui.screens.lexicon
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
|
|
@ -17,7 +17,7 @@ import androidx.compose.ui.text.font.FontStyle
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.lexique.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
@Stable
|
||||
data class LexiconItemUio(
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique.ui.screens.lexicon
|
||||
package com.pixelized.rplexicon.ui.screens.lexicon
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
|
|
@ -18,16 +18,22 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.lexique.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
|
||||
import com.pixelized.rplexicon.ui.navigation.navigateToCharacterDetail
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
@Composable
|
||||
fun LexiconScreen(
|
||||
viewModel: LexiconViewModel = hiltViewModel(),
|
||||
) {
|
||||
val screen = LocalScreenNavHost.current
|
||||
|
||||
Surface {
|
||||
LexiconScreenContent(
|
||||
items = viewModel.items,
|
||||
onItem = { },
|
||||
onItem = {
|
||||
screen.navigateToCharacterDetail(id = "")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package com.pixelized.lexique.ui.screens.lexicon
|
||||
package com.pixelized.rplexicon.ui.screens.lexicon
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.lexique.model.Lexicon
|
||||
import com.pixelized.lexique.repository.LexiconRepository
|
||||
import com.pixelized.rplexicon.model.Lexicon
|
||||
import com.pixelized.rplexicon.repository.LexiconRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique.ui.theme
|
||||
package com.pixelized.rplexicon.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique.ui.theme
|
||||
package com.pixelized.rplexicon.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
|
|
@ -45,22 +45,22 @@ fun LexiconTheme(
|
|||
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)
|
||||
}
|
||||
// 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
|
||||
// window.statusBarColor = colorScheme.primary.toArgb()
|
||||
// WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
||||
// }
|
||||
// }
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.lexique.ui.theme
|
||||
package com.pixelized.rplexicon.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.pixelized.rplexicon.ui.theme.colors
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@Immutable
|
||||
object GoogleColorPalette {
|
||||
val BLUE = Color(0xFF4285F4)
|
||||
val RED = Color(0xFFEA4335)
|
||||
val YELLOW = Color(0xFFFBBC05)
|
||||
val GREEN = Color(0xFF34A853)
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.pixelized.rplexicon.utilitary.extentions
|
||||
|
||||
val String.ARG: String get() = "$this={$this}"
|
||||
5
app/src/main/res/values-fr/strings.xml
Normal file
5
app/src/main/res/values-fr/strings.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<resources>
|
||||
<string name="app_name">Lexique</string>
|
||||
|
||||
<string name="action_google_sign_in">Se connecter avec</string>
|
||||
</resources>
|
||||
4
app/src/main/res/values/google.xml
Normal file
4
app/src/main/res/values/google.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="google_sign_in_id" translatable="false">62913404482-ergqkjiuvint49q8lm555j21vvb6af7s.apps.googleusercontent.com</string>
|
||||
</resources>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
<resources>
|
||||
<string name="app_name">Lexique</string>
|
||||
|
||||
<string name="action_google_sign_in">Sign in with</string>
|
||||
</resources>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id("com.android.application") version "8.1.0-rc01" apply false
|
||||
id("com.google.dagger.hilt.android") version "2.44" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
||||
id("org.jetbrains.kotlin.kapt") version "1.8.22" apply false
|
||||
id("com.google.dagger.hilt.android") version "2.44" apply false
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue