Skip to content

Commit

Permalink
Added Shimmer effect
Browse files Browse the repository at this point in the history
  • Loading branch information
shahzadafridi committed Aug 30, 2024
1 parent a257f23 commit 932548a
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 29 deletions.
3 changes: 2 additions & 1 deletion composeApp/src/commonMain/composeResources/values/string.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<resources>
<string name="home_tab">Home</string>
<string name="fav_tab">Favourite</string>
<string name="profile_tab">Profile</string>
<string name="profile_tab">Gemini</string>
<string name="cart_tab">Cart</string>
<string name="ratting">RATING</string>
<string name="type">TYPE</string>
Expand All @@ -18,4 +18,5 @@
<string name="category">Category</string>
<string name="all">All</string>
<string name="num_of_people">Number Of People</string>
<string name="gemini">Gemini ChatBot</string>
</resources>
5 changes: 2 additions & 3 deletions composeApp/src/commonMain/kotlin/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import cafe.adriel.voyager.navigator.tab.CurrentTab
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
import cafe.adriel.voyager.navigator.tab.TabNavigator
import coil3.ImageLoader
import coil3.PlatformContext
Expand All @@ -26,7 +25,7 @@ import ui.component.tabs
import ui.screen.CartTab
import ui.screen.FavoriteTab
import ui.screen.HomeTab
import ui.screen.ProfileTab
import ui.screen.GeminiTab
import ui.viewmodel.HomeViewModel
import util.AnimateVisibility

Expand Down Expand Up @@ -58,7 +57,7 @@ internal fun App(
HomeTab -> LocalNavigator.currentOrThrow.push(HomeTab)
FavoriteTab -> LocalNavigator.currentOrThrow.push(FavoriteTab)
CartTab -> LocalNavigator.currentOrThrow.push(CartTab)
ProfileTab -> LocalNavigator.currentOrThrow.push(ProfileTab)
GeminiTab -> LocalNavigator.currentOrThrow.push(GeminiTab)
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions composeApp/src/commonMain/kotlin/model/ChatMessage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package model

data class ChatMessage(val text: String, val isSender: Boolean)
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
Expand Down Expand Up @@ -40,7 +39,7 @@ import theme.SecondTextColor
import ui.screen.CartTab
import ui.screen.FavoriteTab
import ui.screen.HomeTab
import ui.screen.ProfileTab
import ui.screen.GeminiTab

interface Tabx: Tab {
fun defaultTitle(): StringResource
Expand All @@ -51,7 +50,7 @@ val tabs = arrayListOf<Tabx>().apply {
add(HomeTab)
add(FavoriteTab)
add(CartTab)
add(ProfileTab)
add(GeminiTab)
}

@Composable
Expand Down
82 changes: 82 additions & 0 deletions composeApp/src/commonMain/kotlin/ui/component/Shimmer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package ui.component

import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import theme.PrimaryColor

val ShimmerColorShades = listOf(
Color.LightGray.copy(0.9f),
PrimaryColor.copy(0.2f),
Color.LightGray.copy(0.9f)
)
@Composable
fun ShimmerAnimation(
) {
/*
Create InfiniteTransition
which holds child animation like [Transition]
animations start running as soon as they enter
the composition and do not stop unless they are removed
*/
val transition = rememberInfiniteTransition()
val translateAnim by transition.animateFloat(
/*
Specify animation positions,
initial Values 0F means it
starts from 0 position
*/
initialValue = 0f,
targetValue = 1000f,
animationSpec = infiniteRepeatable(


// Tween Animates between values over specified [durationMillis]
tween(durationMillis = 1200, easing = FastOutSlowInEasing),
RepeatMode.Reverse
)
)

/*
Create a gradient using the list of colors
Use Linear Gradient for animating in any direction according to requirement
start=specifies the position to start with in cartesian like system Offset(10f,10f) means x(10,0) , y(0,10)
end = Animate the end position to give the shimmer effect using the transition created above
*/
val brush = Brush.linearGradient(
colors = ShimmerColorShades,
start = Offset(10f, 10f),
end = Offset(translateAnim, translateAnim)
)

ShimmerItem(brush = brush)
}

@Composable
fun ShimmerItem(
brush: Brush
) {
Spacer(
modifier = Modifier
.padding(top = 8.dp)
.fillMaxWidth()
.size(20.dp)
.background(brush = brush, shape = RoundedCornerShape(8.dp))
)
}
2 changes: 1 addition & 1 deletion composeApp/src/commonMain/kotlin/ui/screen/CartTab.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ fun CartScreenView(
modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 36.dp),
text = stringResource(Res.string.cart_tab),
color = TextColor,
style = MaterialTheme.typography.bodySmall,
style = MaterialTheme.typography.headlineMedium,
textAlign = TextAlign.Center
)
}
Expand Down
2 changes: 1 addition & 1 deletion composeApp/src/commonMain/kotlin/ui/screen/FavoriteTab.kt
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ fun FavoriteScreenView(
modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 36.dp),
text = stringResource(Res.string.favorite_destination),
color = TextColor,
style = MaterialTheme.typography.bodySmall,
style = MaterialTheme.typography.headlineMedium,
textAlign = TextAlign.Center
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package ui.screen

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.expandIn
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkOut
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
Expand All @@ -18,7 +24,6 @@ import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
Expand All @@ -32,29 +37,24 @@ import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.TextFieldColors
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.mikepenz.markdown.m3.Markdown
import com.mikepenz.markdown.m3.markdownColor
import com.mikepenz.markdown.m3.markdownTypography
import com.mikepenz.markdown.model.MarkdownTypography
import data.GeminiApi
import dev.shreyaspatil.ai.client.generativeai.type.GenerateContentResponse
import io.github.vinceglb.filekit.compose.rememberFilePickerLauncher
Expand All @@ -63,20 +63,21 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import org.jetbrains.compose.ui.tooling.preview.Preview
import theme.BorderColor
import theme.CodeBackground
import theme.LinkColor
import theme.PrimaryColor
import theme.TextColor
import toComposeImageBitmap
import travelbuddy.composeapp.generated.resources.Res
import travelbuddy.composeapp.generated.resources.gemini
import travelbuddy.composeapp.generated.resources.menu_profile
import travelbuddy.composeapp.generated.resources.profile_tab
import ui.component.ShimmerAnimation
import ui.component.Tabx
import util.BOTTOM_NAV_SPACE

data object ProfileTab : Tabx {
data object GeminiTab : Tabx {
override fun defaultTitle(): StringResource = Res.string.profile_tab
override fun defaultIcon(): DrawableResource = Res.drawable.menu_profile

Expand All @@ -98,13 +99,13 @@ data object ProfileTab : Tabx {
@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
ProfileScreenView(navigator)
GeminiScreenView(navigator)
}
}

@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
@Composable
fun ProfileScreenView(navigator: Navigator){
fun GeminiScreenView(navigator: Navigator){
val api = remember { GeminiApi() }
val coroutineScope = rememberCoroutineScope()
var prompt by remember { mutableStateOf("") }
Expand All @@ -113,11 +114,7 @@ fun ProfileScreenView(navigator: Navigator){
var showProgress by remember { mutableStateOf(false) }
var filePath by remember { mutableStateOf("") }
var image by remember { mutableStateOf<ImageBitmap?>(null) }
val canClearPrompt by remember {
derivedStateOf {
prompt.isNotBlank()
}
}
val canClearPrompt by remember { derivedStateOf { prompt.isNotBlank() } }

Surface(modifier = Modifier.fillMaxWidth().padding(bottom = BOTTOM_NAV_SPACE)) {
val imagePickerLauncher = rememberFilePickerLauncher(PickerType.Image) { selectedImage ->
Expand All @@ -134,7 +131,17 @@ fun ProfileScreenView(navigator: Navigator){
.verticalScroll(rememberScrollState())
.fillMaxWidth().padding(16.dp)
) {
FlowRow {
Text(
modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 26.dp),
text = stringResource(Res.string.gemini),
color = TextColor,
style = MaterialTheme.typography.headlineMedium,
textAlign = TextAlign.Center
)

FlowRow(
modifier = Modifier.fillMaxWidth().padding(top = 16.dp),
) {
OutlinedTextField(
value = prompt,
onValueChange = { prompt = it },
Expand Down Expand Up @@ -181,6 +188,7 @@ fun ProfileScreenView(navigator: Navigator){
.onStart { showProgress = true }
.onCompletion { showProgress = false }
.collect {
showProgress = false
println("response = ${it.text}")
content += it.text
}
Expand Down Expand Up @@ -237,7 +245,13 @@ fun ProfileScreenView(navigator: Navigator){
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
Column(
modifier = Modifier.fillMaxSize()
) {
repeat(5) {
ShimmerAnimation()
}
}
}
} else {
SelectionContainer {
Expand Down Expand Up @@ -268,4 +282,4 @@ fun generateContentAsFlow(
api.generateContent(prompt, imageByteArray)
} ?: run {
api.generateContent(prompt)
}
}

0 comments on commit 932548a

Please sign in to comment.