Login logic

This commit is contained in:
2021-09-07 14:15:25 +02:00
parent 1a71262008
commit 326cf267d2
20 changed files with 24759 additions and 67 deletions
@@ -3,6 +3,7 @@ package com.ericampire.android.androidstudycase
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface import androidx.compose.material.Surface
@@ -14,10 +15,11 @@ import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@ExperimentalMaterialApi @ExperimentalMaterialApi
@ExperimentalPagerApi @ExperimentalPagerApi
@ExperimentalPermissionsApi @ExperimentalPermissionsApi
@ExperimentalAnimationApi
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
@@ -1,6 +1,8 @@
package com.ericampire.android.androidstudycase.app package com.ericampire.android.androidstudycase.app
import android.app.Application import android.app.Application
import android.content.Context
import android.content.Intent
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp @HiltAndroidApp
@@ -8,4 +10,15 @@ class App : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
} }
companion object {
fun restart(context: Context) {
context.packageManager.getLaunchIntentForPackage(context.packageName)?.apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
addCategory(Intent.CATEGORY_HOME)
context.startActivity(this)
}
}
}
} }
@@ -1,5 +1,6 @@
package com.ericampire.android.androidstudycase.app package com.ericampire.android.androidstudycase.app
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
@@ -11,6 +12,7 @@ import com.ericampire.android.androidstudycase.util.Destination
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
@ExperimentalAnimationApi
@ExperimentalMaterialApi @ExperimentalMaterialApi
fun NavGraphBuilder.addHomeScreen(navController: NavController) { fun NavGraphBuilder.addHomeScreen(navController: NavController) {
composable(Destination.Home.route) { composable(Destination.Home.route) {
@@ -0,0 +1,67 @@
package com.ericampire.android.androidstudycase.presentation.custom
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Facebook
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.ericampire.android.androidstudycase.R
import com.ericampire.android.androidstudycase.presentation.theme.AppColor
@Composable
fun CustomFacebookButton(
modifier: Modifier = Modifier,
enabled: Boolean = true,
onClick: () -> Unit
) {
Button(
enabled = enabled,
colors = ButtonDefaults.buttonColors(backgroundColor = AppColor.BlueFacebook),
modifier = modifier
.fillMaxWidth()
.height(50.dp),
onClick = onClick,
content = {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
content = {
Icon(
tint = Color.White,
imageVector = Icons.Rounded.Facebook,
contentDescription = null,
)
Text(
color = Color.White,
style = MaterialTheme.typography.h5,
text = stringResource(R.string.txt_connect_with_facebook)
)
Icon(
tint = Color.Transparent,
imageVector = Icons.Rounded.Facebook,
contentDescription = null,
)
}
)
}
)
}
@Preview
@Composable
fun CustomFacebookButtonPreview() {
CustomFacebookButton() {
}
}
@@ -0,0 +1,67 @@
package com.ericampire.android.androidstudycase.presentation.custom
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Facebook
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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 com.ericampire.android.androidstudycase.R
@Composable
fun CustomGoogleButton(
modifier: Modifier = Modifier,
enabled: Boolean = true,
onClick: () -> Unit
) {
OutlinedButton(
enabled = enabled,
colors = ButtonDefaults.buttonColors(backgroundColor = Color.White),
modifier = modifier
.fillMaxWidth()
.height(50.dp),
onClick = onClick,
content = {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
content = {
Icon(
tint = Color.Unspecified,
painter = painterResource(id = R.drawable.ic_google),
contentDescription = null,
)
Text(
style = MaterialTheme.typography.h5,
color = MaterialTheme.colors.surface,
text = stringResource(R.string.txt_connect_with_google)
)
Icon(
tint = Color.Transparent,
imageVector = Icons.Rounded.Facebook,
contentDescription = null,
)
}
)
}
)
}
@Preview
@Composable
fun CustomGoogleButtonPreview() {
CustomGoogleButton {
}
}
@@ -140,10 +140,18 @@ fun ExploreScreen(
} }
is Success -> { is Success -> {
val animations = it.invoke() val animations = it.invoke()
if (animations.isEmpty()) {
// Todo: Empty instead of Loading View
LoadingAnimation(
waveColor = MaterialTheme.colors.primary.copy(alpha = 0.5f),
arcColor = MaterialTheme.colors.primaryVariant
)
} else {
HorizontalPager(state = pagerState) { HorizontalPager(state = pagerState) {
ExploreContent(files = animations) ExploreContent(files = animations)
} }
} }
}
is Fail -> { is Fail -> {
Timber.e(it.error.localizedMessage) Timber.e(it.error.localizedMessage)
} }
@@ -2,4 +2,6 @@ package com.ericampire.android.androidstudycase.presentation.screen.home.busines
sealed interface HomeAction { sealed interface HomeAction {
object FetchData : HomeAction object FetchData : HomeAction
object Login : HomeAction
object FetchCurrentUser : HomeAction
} }
@@ -3,17 +3,17 @@ package com.ericampire.android.androidstudycase.presentation.screen.home.busines
import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.MavericksViewModelFactory
import com.ericampire.android.androidstudycase.app.hilt.AssistedViewModelFactory import com.ericampire.android.androidstudycase.app.hilt.AssistedViewModelFactory
import com.ericampire.android.androidstudycase.app.hilt.hiltMavericksViewModelFactory import com.ericampire.android.androidstudycase.app.hilt.hiltMavericksViewModelFactory
import com.ericampire.android.androidstudycase.domain.usecase.FindFeaturedAnimatorUseCase import com.ericampire.android.androidstudycase.domain.usecase.*
import com.ericampire.android.androidstudycase.domain.usecase.FindFeaturedBlogUseCase import com.ericampire.android.androidstudycase.util.PreviewData
import com.ericampire.android.androidstudycase.domain.usecase.FindFeaturedLottieFileUseCase
import com.ericampire.android.androidstudycase.domain.usecase.FindUsersUseCase
import com.ericampire.android.androidstudycase.util.data import com.ericampire.android.androidstudycase.util.data
import com.ericampire.android.androidstudycase.util.mvi.BaseViewModel import com.ericampire.android.androidstudycase.util.mvi.BaseViewModel
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class HomeViewModel @AssistedInject constructor( class HomeViewModel @AssistedInject constructor(
@@ -21,7 +21,8 @@ class HomeViewModel @AssistedInject constructor(
private val findFeaturedBlogUseCase: FindFeaturedBlogUseCase, private val findFeaturedBlogUseCase: FindFeaturedBlogUseCase,
private val findFeaturedAnimatorUseCase: FindFeaturedAnimatorUseCase, private val findFeaturedAnimatorUseCase: FindFeaturedAnimatorUseCase,
private val findUsersUseCase: FindUsersUseCase, private val findUsersUseCase: FindUsersUseCase,
private val findFeaturedLottieFileUseCase: FindFeaturedLottieFileUseCase private val findFeaturedLottieFileUseCase: FindFeaturedLottieFileUseCase,
private val saveUserUseCase: SaveUserUseCase
) : BaseViewModel<HomeViewState, HomeAction>(initialState) { ) : BaseViewModel<HomeViewState, HomeAction>(initialState) {
@@ -30,25 +31,45 @@ class HomeViewModel @AssistedInject constructor(
pendingAction.collectLatest { action -> pendingAction.collectLatest { action ->
when (action) { when (action) {
HomeAction.FetchData -> fetchData() HomeAction.FetchData -> fetchData()
HomeAction.Login -> login()
HomeAction.FetchCurrentUser -> fetchCurrentUser()
} }
} }
} }
} }
private fun login() {
viewModelScope.launch {
suspend {
delay(2000)
saveUserUseCase(PreviewData.User.data.first()).data!!
}.execute {
copy(login = it)
}
}
}
private fun fetchCurrentUser() {
viewModelScope.launch {
findUsersUseCase(Unit).map {
it.data?.firstOrNull()
}.execute {
copy(currentUser = it)
}
}
}
private fun fetchData() { private fun fetchData() {
val userFlow = findUsersUseCase(Unit)
val storiesFlow = findFeaturedBlogUseCase(Unit) val storiesFlow = findFeaturedBlogUseCase(Unit)
val animatorsFlow = findFeaturedAnimatorUseCase(Unit) val animatorsFlow = findFeaturedAnimatorUseCase(Unit)
val animationsFlow = findFeaturedLottieFileUseCase(Unit) val animationsFlow = findFeaturedLottieFileUseCase(Unit)
combine( combine(
userFlow,
storiesFlow, storiesFlow,
animationsFlow, animationsFlow,
animatorsFlow animatorsFlow
) { user, stories, anim, animators -> ) { stories, anim, animators ->
HomeContentData( HomeContentData(
user = user.data?.firstOrNull(),
blog = stories.data ?: emptyList(), blog = stories.data ?: emptyList(),
featuredAnimators = animators.data ?: emptyList(), featuredAnimators = animators.data ?: emptyList(),
featuredLottieFile = anim.data ?: emptyList(), featuredLottieFile = anim.data ?: emptyList(),
@@ -9,12 +9,13 @@ import com.ericampire.android.androidstudycase.domain.entity.Lottiefile
import com.ericampire.android.androidstudycase.domain.entity.User import com.ericampire.android.androidstudycase.domain.entity.User
data class HomeViewState( data class HomeViewState(
val contentData: Async<HomeContentData> = Uninitialized val contentData: Async<HomeContentData> = Uninitialized,
val login: Async<Unit> = Uninitialized,
val currentUser: Async<User?> = Uninitialized,
) : MavericksState ) : MavericksState
data class HomeContentData( data class HomeContentData(
val blog: List<Blog> = emptyList(), val blog: List<Blog> = emptyList(),
val featuredAnimators: List<Animator> = emptyList(), val featuredAnimators: List<Animator> = emptyList(),
val featuredLottieFile: List<Lottiefile> = emptyList(), val featuredLottieFile: List<Lottiefile> = emptyList(),
val user: User? = null,
) : MavericksState ) : MavericksState
@@ -1,6 +1,7 @@
package com.ericampire.android.androidstudycase.presentation.screen.home.ui package com.ericampire.android.androidstudycase.presentation.screen.home.ui
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@@ -9,16 +10,16 @@ import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme import androidx.compose.material.*
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
@@ -29,6 +30,8 @@ import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel import com.airbnb.mvrx.compose.mavericksViewModel
import com.ericampire.android.androidstudycase.R import com.ericampire.android.androidstudycase.R
import com.ericampire.android.androidstudycase.app.App
import com.ericampire.android.androidstudycase.domain.entity.User
import com.ericampire.android.androidstudycase.presentation.custom.CustomImageView import com.ericampire.android.androidstudycase.presentation.custom.CustomImageView
import com.ericampire.android.androidstudycase.presentation.custom.LoadingAnimation import com.ericampire.android.androidstudycase.presentation.custom.LoadingAnimation
import com.ericampire.android.androidstudycase.presentation.custom.TopActionBar import com.ericampire.android.androidstudycase.presentation.custom.TopActionBar
@@ -37,9 +40,10 @@ import com.ericampire.android.androidstudycase.presentation.screen.home.business
import com.ericampire.android.androidstudycase.presentation.screen.home.business.HomeViewModel import com.ericampire.android.androidstudycase.presentation.screen.home.business.HomeViewModel
import com.ericampire.android.androidstudycase.presentation.screen.home.business.HomeViewState import com.ericampire.android.androidstudycase.presentation.screen.home.business.HomeViewState
import com.ericampire.android.androidstudycase.presentation.theme.AppColor import com.ericampire.android.androidstudycase.presentation.theme.AppColor
import com.ericampire.android.androidstudycase.util.Destination import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
@ExperimentalAnimationApi
@ExperimentalMaterialApi @ExperimentalMaterialApi
@Composable @Composable
fun HomeScreen( fun HomeScreen(
@@ -48,11 +52,37 @@ fun HomeScreen(
) { ) {
val state by viewModel.collectAsState(HomeViewState::contentData) val state by viewModel.collectAsState(HomeViewState::contentData)
val loginState by viewModel.collectAsState(HomeViewState::login)
val userState by viewModel.collectAsState(HomeViewState::currentUser)
val bottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
val coroutineScope = rememberCoroutineScope()
val context = LocalContext.current
LaunchedEffect(viewModel) { LaunchedEffect(viewModel) {
viewModel.submitAction(HomeAction.FetchData) viewModel.submitAction(HomeAction.FetchData)
viewModel.submitAction(HomeAction.FetchCurrentUser)
} }
LaunchedEffect(loginState) {
if (loginState is Success) {
App.restart(context)
}
}
ModalBottomSheetLayout(
sheetShape = RoundedCornerShape(topEnd = 24.dp, topStart = 24.dp),
sheetState = bottomSheetState,
sheetContent = {
LoginBottomSheet(
onLoginClick = {
viewModel.submitAction(HomeAction.Login)
},
isLoading = loginState is Loading
)
},
content = {
Scaffold( Scaffold(
topBar = { topBar = {
Column( Column(
@@ -86,8 +116,11 @@ fun HomeScreen(
is Success -> { is Success -> {
HomeContent( HomeContent(
state = it.invoke(), state = it.invoke(),
currentUser = userState.invoke(),
onLoginClick = { onLoginClick = {
navController.navigate(Destination.Login.route) coroutineScope.launch {
bottomSheetState.animateTo(targetValue = ModalBottomSheetValue.Expanded)
}
} }
) )
} }
@@ -100,6 +133,8 @@ fun HomeScreen(
} }
} }
) )
}
)
} }
@ExperimentalMaterialApi @ExperimentalMaterialApi
@@ -107,6 +142,7 @@ fun HomeScreen(
fun HomeContent( fun HomeContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
state: HomeContentData, state: HomeContentData,
currentUser: User? = null,
onLoginClick: () -> Unit onLoginClick: () -> Unit
) { ) {
LazyColumn( LazyColumn(
@@ -117,10 +153,10 @@ fun HomeContent(
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
content = { content = {
item { item {
if (state.user == null) { if (currentUser == null) {
UnLoggedUserHeaderView(onLoginClick = onLoginClick) UnLoggedUserHeaderView(onLoginClick = onLoginClick)
} else { } else {
LoggedUserHeaderView(user = state.user) LoggedUserHeaderView(user = currentUser)
} }
} }
@@ -42,7 +42,7 @@ fun LoggedUserHeaderView(
content = { content = {
Text( Text(
maxLines = 1, maxLines = 1,
text = "Monday September 4", text = "Monday 4 September",
style = MaterialTheme.typography.button.copy( style = MaterialTheme.typography.button.copy(
color = Color.Gray color = Color.Gray
), ),
@@ -0,0 +1,117 @@
package com.ericampire.android.androidstudycase.presentation.screen.home.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.airbnb.lottie.compose.*
import com.ericampire.android.androidstudycase.R
import com.ericampire.android.androidstudycase.presentation.custom.CustomFacebookButton
import com.ericampire.android.androidstudycase.presentation.custom.CustomGoogleButton
import com.ericampire.android.androidstudycase.presentation.theme.AndroidStudyCaseTheme
import com.ericampire.android.androidstudycase.presentation.theme.AppColor
@ExperimentalAnimationApi
@Composable
fun LoginBottomSheet(
modifier: Modifier = Modifier,
isLoading: Boolean = false,
onLoginClick: () -> Unit,
) {
val composition by rememberLottieComposition(
spec = LottieCompositionSpec.RawRes(R.raw.people_communicating)
)
val progress by animateLottieCompositionAsState(
composition = composition,
iterations = LottieConstants.IterateForever,
)
Column(
modifier = modifier
.clip(MaterialTheme.shapes.medium)
.background(AppColor.Black001),
content = {
AnimatedVisibility(isLoading) {
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
}
Column(
modifier = Modifier.padding(24.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
content = {
Text(
textAlign = TextAlign.Center,
text = stringResource(id = R.string.txt_login_title),
style = MaterialTheme.typography.h4.copy(
color = MaterialTheme.colors.onSurface
),
)
Text(
textAlign = TextAlign.Center,
text = stringResource(id = R.string.txt_login_description),
style = MaterialTheme.typography.body1.copy(
color = MaterialTheme.colors.onSurface
),
)
LottieAnimation(
modifier = Modifier
.fillMaxWidth()
.height(200.dp),
composition = composition,
progress = progress,
)
Text(
textAlign = TextAlign.Center,
text = stringResource(id = R.string.txt_get_started),
style = MaterialTheme.typography.body1.copy(
color = MaterialTheme.colors.onSurface
),
)
CustomFacebookButton(
modifier = Modifier.fillMaxWidth(),
onClick = onLoginClick
)
CustomGoogleButton(
modifier = Modifier.fillMaxWidth(),
onClick = onLoginClick
)
}
)
}
)
}
@ExperimentalAnimationApi
@ExperimentalMaterialApi
@Preview()
@Composable
fun LoginDialogViewPreview() {
AndroidStudyCaseTheme(darkTheme = true) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
content = {
LoginBottomSheet(
onLoginClick = {}
)
}
)
}
}
@@ -44,7 +44,7 @@ fun UnLoggedUserHeaderView(
content = { content = {
Text( Text(
maxLines = 1, maxLines = 1,
text = "Monday September 4", text = "Monday 4 September",
style = MaterialTheme.typography.button.copy( style = MaterialTheme.typography.button.copy(
color = Color.Gray color = Color.Gray
), ),
@@ -1,5 +1,6 @@
package com.ericampire.android.androidstudycase.presentation.screen.main.ui package com.ericampire.android.androidstudycase.presentation.screen.main.ui
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -29,7 +30,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
@ExperimentalMaterialApi @ExperimentalMaterialApi
@ExperimentalPagerApi @ExperimentalPagerApi
@ExperimentalPermissionsApi @ExperimentalPermissionsApi
@ExperimentalAnimationApi
@Composable @Composable
fun MainScreen() { fun MainScreen() {
val navController = rememberNavController() val navController = rememberNavController()
@@ -12,7 +12,8 @@ object AppColor {
val Purple700 = Color(0xFF3700B3) val Purple700 = Color(0xFF3700B3)
val Teal200 = Color(0xFF03DAC5) val Teal200 = Color(0xFF03DAC5)
val Black001 = Color(0xFF222222) val Black001 = Color(0xFF222222)
val BlackOverlay = Color(0x4D000000) val BlueFacebook = Color(0xFF3B5998)
val BlackOverlay = Color(0x4DFFFFFF)
val BlackOverlay001 = Color(0x1A000000) val BlackOverlay001 = Color(0x1A000000)
val WhiteTransparent = Color(0x80FFFFFF) val WhiteTransparent = Color(0x80FFFFFF)
} }
+18
View File
@@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M23.745,12.27C23.745,11.48 23.675,10.73 23.555,10L12.255,10L12.255,14.51L18.725,14.51C18.435,15.99 17.585,17.24 16.325,18.09L16.325,21.09L20.185,21.09C22.445,19 23.745,15.92 23.745,12.27Z"
android:fillColor="#4285F4" />
<path
android:pathData="M12.255,24C15.495,24 18.205,22.92 20.185,21.09L16.325,18.09C15.245,18.81 13.875,19.25 12.255,19.25C9.125,19.25 6.475,17.14 5.525,14.29L1.545,14.29L1.545,17.38C3.515,21.3 7.565,24 12.255,24Z"
android:fillColor="#34A853" />
<path
android:pathData="M5.525,14.29C5.275,13.57 5.145,12.8 5.145,12C5.145,11.2 5.285,10.43 5.525,9.71L5.525,6.62L1.545,6.62C0.725,8.24 0.255,10.06 0.255,12C0.255,13.94 0.725,15.76 1.545,17.38L5.525,14.29Z"
android:fillColor="#FBBC05" />
<path
android:pathData="M12.255,4.75C14.025,4.75 15.605,5.36 16.855,6.55L20.275,3.13C18.205,1.19 15.495,0 12.255,0C7.565,0 3.515,2.7 1.545,6.62L5.525,9.71C6.475,6.86 9.125,4.75 12.255,4.75Z"
android:fillColor="#EA4335" />
</vector>
File diff suppressed because it is too large Load Diff
+3
View File
@@ -2,4 +2,7 @@
<string name="txt_featured_animation">Featured Animations</string> <string name="txt_featured_animation">Featured Animations</string>
<string name="txt_open_setting">Open Settings</string> <string name="txt_open_setting">Open Settings</string>
<string name="txt_request">Request permission</string> <string name="txt_request">Request permission</string>
<string name="txt_login_title">1000s of lottie animations</string>
<string name="txt_login_description">from top creators waiting to be discover, save and share from the palm of your hand</string>
<string name="txt_connect_with_facebook">Continue with Facebook</string>
</resources> </resources>
@@ -2,6 +2,7 @@ package com.ericampire.android.androidstudycase.data.room
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy.REPLACE
import androidx.room.Query import androidx.room.Query
import com.ericampire.android.androidstudycase.domain.entity.User import com.ericampire.android.androidstudycase.domain.entity.User
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -9,7 +10,7 @@ import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface UserDao { interface UserDao {
@Insert @Insert(onConflict = REPLACE)
fun save(user: User) fun save(user: User)
@Query("SELECT * FROM User") @Query("SELECT * FROM User")
+2
View File
@@ -21,4 +21,6 @@
<string name="txt_feature_not_available">Feature not available</string> <string name="txt_feature_not_available">Feature not available</string>
<string name="txt_camera_permssion_required">The camera is important for this app. Please grant the permission.</string> <string name="txt_camera_permssion_required">The camera is important for this app. Please grant the permission.</string>
<string name="txt_permission_denied">Camera permission denied. See this FAQ with information about why we need this permission. Please, grant us access on the Settings screen.</string> <string name="txt_permission_denied">Camera permission denied. See this FAQ with information about why we need this permission. Please, grant us access on the Settings screen.</string>
<string name="txt_connect_with_google">Continue with Google</string>
<string name="txt_get_started">Get started for free</string>
</resources> </resources>