Skip to content

Commit

Permalink
Merge pull request #5 from samAricha/gemini_chat_navigation_plus
Browse files Browse the repository at this point in the history
Gemini chat navigation plus
  • Loading branch information
samAricha authored Feb 13, 2024
2 parents 672491a + 5cc3c09 commit d6346a7
Show file tree
Hide file tree
Showing 15 changed files with 230 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// WindowCompat.setDecorFitsSystemWindows(
// window,
// false
// )

Log.d("TAG1", "WORKINg")

val isLoading = splashViewModel.isLoading.value
Expand All @@ -67,6 +62,7 @@ class MainActivity : ComponentActivity() {
val startDestination by splashViewModel.startDestination
startDestination?.let {
RootNavGraph(
// appState = appState,
navController = rememberNavController(),
startDestination = it
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import teka.android.organiks_platform_android.ui.theme.PrimaryColor
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun MainAppScreen() {
NavigationDrawerM3()
fun MainAppScreen(appState: AppState) {
NavigationDrawerM3(appState)
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,71 @@
package teka.android.organiks_platform_android.navigation

import android.content.res.Resources
import androidx.compose.material.ScaffoldState
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.lifecycle.Lifecycle
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination
import androidx.navigation.NavGraph
import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.CoroutineScope

@Composable
fun rememberAppState(
navHostController: NavHostController = rememberNavController()
) = remember(navHostController) {
AppState(navHostController)
scaffoldState: ScaffoldState = rememberScaffoldState(),
navHostController: NavHostController,
coroutineScope: CoroutineScope = rememberCoroutineScope()
) = remember(scaffoldState, navHostController, coroutineScope) {
AppState(scaffoldState, navHostController, coroutineScope)
}

@Stable
class AppState(
val navHostController: NavHostController
val scaffoldState: ScaffoldState,
val navHostController: NavHostController,
coroutineScope: CoroutineScope
) {

private val routes = BottomBarRoutes.values().map { it.routes }
private val bottomBarRoutes = BottomBarRoutes.values().map { it.routes }

val shouldShowBottomBar: Boolean
@Composable get() =
navHostController.currentBackStackEntryAsState().value?.destination?.route in routes
navHostController.currentBackStackEntryAsState().value?.destination?.route in bottomBarRoutes


val currentRoute: String?
get() = navHostController.currentDestination?.route

fun upPress() {
navHostController.navigateUp()
}

fun navigateToBottomBarRoute(route: String) {
if (route != currentRoute) {
navHostController.navigate(route) {
launchSingleTop = true
restoreState = true
popUpTo(findStartDestination(navHostController.graph).id) {
saveState = true
}
}
}
}
}


private fun NavBackStackEntry.lifecycleIsResumed() =
this.lifecycle.currentState == Lifecycle.State.RESUMED

private val NavGraph.startDestination: NavDestination?
get() = findNode(startDestinationId)

private tailrec fun findStartDestination(graph: NavDestination): NavDestination {
return if (graph is NavGraph) findStartDestination(graph.startDestination!!) else graph
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ enum class BottomBarRoutes(
val routes: String,
@DrawableRes val icon: Int
) {

HOME(1, R.string.homeRoute, "/home", R.drawable.home),
NOTIFICATION(
DASHBOARD(1, R.string.dashboard, Screen.DashboardScreen.route, R.drawable.home),
PRODUCTION_HOME(
2,
R.string.notificationRoute, "/notification", R.drawable.monitoring
R.string.productionHome, Screen.ProductionHome.route, R.drawable.monitoring
),
Profile(3, R.string.profileRoute, "/profile", R.drawable.add_to_list)

PRODUCTION_RECORDING(3, R.string.productionRecording, Screen.ProductionRecording.route, R.drawable.add_to_list)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import teka.android.organiks_platform_android.ui.animations.scaleOutOfContainer

@Composable
fun MainNavGraph(
navController: NavHostController = rememberNavController(),
navController: NavHostController,
) {

NavHost(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ fun RootNavGraph(
navController: NavHostController,
startDestination: String = To_MAIN_GRAPH_ROUTE
) {
val appState = rememberAppState(navHostController = navController)


NavHost(navController = navController,
startDestination = startDestination,
route = ROOT_GRAPH_ROUTE){
Expand All @@ -48,7 +51,7 @@ fun RootNavGraph(

if (isLoggedInState != null) {
if (isLoggedInState as Boolean) {
MainAppScreen()
MainAppScreen(appState)
} else {
LoginScreen(navController)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ sealed class Screen(val route: String) {
object AiSearchScreen: Screen(route = "ai_search_screen")
object GeminiChatScreen: Screen(route = "gemini_chat_screen")
object ProfileScreen: Screen(route = "profile_screen")

object Splash : Screen("splash")
object BottomBar : Screen("bottombar")
object Detail : Screen("detail")
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package teka.android.organiks_platform_android.presentation.aiadvice.chat_screen
import teka.android.organiks_platform_android.domain.models.ChatMessageModel
import teka.android.organiks_platform_android.domain.models.ChatStatusModel


data class ChatUiState(
val messages: List<ChatMessageModel> = emptyList(),
val status: ChatStatusModel = ChatStatusModel.Idle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
Expand Down Expand Up @@ -32,6 +33,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
Expand All @@ -52,6 +54,9 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.bumptech.glide.Glide
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import teka.android.organiks_platform_android.domain.models.ChatStatusModel
import teka.android.organiks_platform_android.ui.theme.Cream1
import teka.android.organiks_platform_android.ui.theme.Cream2
Expand All @@ -63,9 +68,6 @@ import java.io.IOException
import java.io.InputStream


/**
* TODO : allow sending attachments without text
*/
@Composable
fun CustomBottomSearchBar(
modifier: Modifier = Modifier,
Expand All @@ -82,10 +84,14 @@ fun CustomBottomSearchBar(
rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickMultipleVisualMedia(5)
) { uris ->
images.value = uris.mapNotNull { uri -> Glide.with(context).asBitmap().load(uri).submit().get()
scope.launch(Dispatchers.IO) {
images.value = uris.mapNotNull { uri ->
Glide.with(context).asBitmap().load(uri).submit().get()
}
}
}


Column {
LazyRow {
items(images.value.size) { index ->
Expand Down Expand Up @@ -126,11 +132,14 @@ fun CustomBottomSearchBar(
disabledContainerColor = Cream2,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
cursorColor = SecondaryLightColor
),
leadingIcon = {
IconButton(
onClick = {
// pickerLauncher.launch()
pickMultipleMedia.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)
},
content = {
Icon(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package teka.android.organiks_platform_android.presentation.aiadvice.chat_screen

import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
Expand All @@ -18,6 +21,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.dp
Expand All @@ -30,6 +34,7 @@ import teka.android.organiks_platform_android.domain.models.ChatStatusModel
import teka.android.organiks_platform_android.ui.theme.LightGreen
import teka.android.organiks_platform_android.ui.theme.LightRed

@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun GeminiChatScreen(viewModel: ChatViewModel = ChatViewModel()) {
val chatUiState = viewModel.uiState
Expand All @@ -49,7 +54,7 @@ fun GeminiChatScreen(viewModel: ChatViewModel = ChatViewModel()) {
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp)
.padding(bottom = 30.dp, top = 5.dp),
.padding(top = 5.dp),
status = chatUiState.value.status,
onSendClick = { text, images ->
coroutineScope.launch(Dispatchers.IO) {
Expand All @@ -72,14 +77,16 @@ fun GeminiChatScreen(viewModel: ChatViewModel = ChatViewModel()) {
)
}
},
modifier = Modifier.pointerInput(Unit) {
detectTapGestures(onTap = { focusManager.clearFocus() })
},
) { paddingValues ->
modifier = Modifier
.pointerInput(Unit) {
detectTapGestures(onTap = { focusManager.clearFocus() })
}
.padding(bottom = 15.dp)
) {
ChatList(
modifier = Modifier.padding(paddingValues),
messages = chatUiState.value.messages
)
Spacer(modifier = Modifier.height(15.dp))

if (showDialog.value) {
CustomChatDialog(
Expand Down Expand Up @@ -107,7 +114,7 @@ fun GeminiChatScreen(viewModel: ChatViewModel = ChatViewModel()) {


@Composable
fun ChatList(modifier: Modifier, messages: List<ChatMessageModel>) {
fun ChatList(messages: List<ChatMessageModel>) {
val listState = rememberLazyListState()

if (messages.isNotEmpty()) {
Expand All @@ -117,10 +124,13 @@ fun ChatList(modifier: Modifier, messages: List<ChatMessageModel>) {
}
LazyColumn(
state = listState,
modifier = modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(10.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
item{
Spacer(modifier = Modifier.height(25.dp))
}
items(messages.size) {
val message = messages[it]
if (message.images.isNotEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package teka.android.organiks_platform_android.presentation.aiadvice.chat_screen.components

import android.graphics.BitmapFactory
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
Expand All @@ -13,12 +14,15 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.scaleIn
import androidx.compose.animation.slideInHorizontally
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
Expand All @@ -36,6 +40,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
Expand Down Expand Up @@ -77,14 +83,14 @@ fun MessageImagesStack(
cardCount = message.images.size,
cardShape = RoundedCornerShape(20.dp),
cardContent = { index ->
// Image(
// bitmap = message.images[index].toImageBitmap(),
// contentDescription = "Same Card Type with Different Image",
// contentScale = ContentScale.Crop,
// modifier = Modifier
// .heightIn(100.dp, 300.dp)
// .widthIn(50.dp, 200.dp)
// )
Image(
bitmap = BitmapFactory.decodeByteArray(message.images[index], 0, message.images[index].size).asImageBitmap(),
contentDescription = "Same Card Type with Different Image",
contentScale = ContentScale.Crop,
modifier = Modifier
.heightIn(100.dp, 300.dp)
.widthIn(50.dp, 200.dp)
)
},
orientation = Orientation.Horizontal(
alignment = HorizontalAlignment.EndToStart,
Expand Down
Loading

0 comments on commit d6346a7

Please sign in to comment.