yayan 1 anno fa
parent
commit
c2f9f89b59

+ 137 - 0
app/src/main/java/io/nexilis/alpha/ui/components/BubleChat.kt

@@ -0,0 +1,137 @@
+package io.nexilis.alpha.ui.components
+
+import android.text.format.DateUtils
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.AccessTime
+import androidx.compose.material.icons.filled.Done
+import androidx.compose.material.icons.filled.DoneAll
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
+import io.nexilis.service.core.BlueSky
+import io.nexilis.service.data.entities.Message
+import io.nexilis.service.data.viewmodels.MessageStatusViewModel
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun RightBubbleChat(
+    modifier: Modifier,
+    message: Message?,
+    messageStatusModel: MessageStatusViewModel = hiltViewModel(),
+    content: @Composable () -> Unit
+) {
+    Column(
+        modifier = modifier
+    ) {
+        Box(
+            modifier = Modifier
+                .align(Alignment.End)
+                .graphicsLayer {
+                    shape = RoundedCornerShape(16.dp)
+                    clip = true
+                }
+                .combinedClickable(onLongClick = {}, onClick = {})
+                .background(color = MaterialTheme.colorScheme.primaryContainer)
+                .padding(8.dp),
+        ) {
+            content()
+        }
+        Row(
+            modifier = Modifier
+                .padding(3.dp)
+                .align(Alignment.End)
+        ) {
+            Text(
+                text = DateUtils.formatDateTime(
+                    LocalContext.current,
+                    message?.server_date ?: 0,
+                    DateUtils.FORMAT_SHOW_TIME
+                ),
+                color = MaterialTheme.colorScheme.onPrimaryContainer,
+                style = MaterialTheme.typography.bodySmall,
+            )
+            Spacer(modifier = Modifier.width(6.dp))
+            message?.message_id?.let {
+                message.opposite_pin.let { pin ->
+                    val messageStatus by messageStatusModel.get(it, pin)
+                        .observeAsState()
+                    Icon(
+                        imageVector = when (messageStatus?.status) {
+                            1, 2 -> Icons.Default.Done
+                            3 -> Icons.Default.DoneAll
+                            4 -> Icons.Default.DoneAll
+                            else -> Icons.Default.AccessTime
+                        },
+                        contentDescription = "",
+                        modifier = Modifier
+                            .align(Alignment.Bottom)
+                            .size(16.dp),
+                        tint = if (messageStatus?.status == 4) Color.BlueSky else Color.Gray
+                    )
+                }
+            }
+        }
+    }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun LeftBubbleChat(
+    modifier: Modifier,
+    message: Message?,
+    content: @Composable () -> Unit
+) {
+    Column(
+        modifier = modifier
+    ) {
+        Box(
+            modifier = Modifier
+                .align(Alignment.Start)
+                .graphicsLayer {
+                    shape = RoundedCornerShape(16.dp)
+                    clip = true
+                }
+                .combinedClickable(onLongClick = {}, onClick = {})
+                .background(color = MaterialTheme.colorScheme.surface)
+                .padding(8.dp),
+        ) {
+            content()
+        }
+        Row(
+            modifier = Modifier
+                .padding(3.dp)
+                .align(Alignment.End)
+        ) {
+            Text(
+                text = DateUtils.formatDateTime(
+                    LocalContext.current,
+                    message?.server_date ?: 0,
+                    DateUtils.FORMAT_SHOW_TIME
+                ),
+                color = MaterialTheme.colorScheme.onSurface,
+                style = MaterialTheme.typography.bodySmall,
+            )
+        }
+    }
+}

+ 1 - 7
app/src/main/java/io/nexilis/alpha/ui/main/Menu.kt → app/src/main/java/io/nexilis/alpha/ui/components/Menu.kt

@@ -1,4 +1,4 @@
-package io.nexilis.alpha.ui.main
+package io.nexilis.alpha.ui.components
 
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Call
@@ -12,14 +12,8 @@ import io.nexilis.alpha.ui.screen.Screen
 
 @Composable
 fun ActionsMenu(navController: NavHostController, navMainController: NavHostController) {
-    val navBackStackEntry by navController.currentBackStackEntryAsState()
     val navMainBackStackEntry by navMainController.currentBackStackEntryAsState()
     var isChat = false
-    navBackStackEntry?.destination?.route.let {
-        it?.let {
-            isChat = it.startsWith("${Screen.Chat.route}/")
-        }
-    }
     navMainBackStackEntry?.destination?.route.let {
         it?.let {
             isChat = it.startsWith("${Screen.Chat.route}/")

+ 71 - 0
app/src/main/java/io/nexilis/alpha/ui/components/Title.kt

@@ -0,0 +1,71 @@
+package io.nexilis.alpha.ui.components
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Person
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.rememberVectorPainter
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.currentBackStackEntryAsState
+import coil.compose.AsyncImage
+import coil.request.ImageRequest
+import io.nexilis.alpha.ui.screen.Screen
+import io.nexilis.service.data.viewmodels.BuddyViewModel
+
+@Composable
+fun Title(navMainController: NavHostController, title: String) {
+    val navMainBackStackEntry by navMainController.currentBackStackEntryAsState()
+    val buddyViewModel: BuddyViewModel = hiltViewModel()
+    var isChat = false
+    var pin = ""
+    navMainBackStackEntry?.destination?.route?.let {
+        isChat = it.startsWith("${Screen.Chat.route}/")
+    }
+    navMainBackStackEntry?.arguments?.getString("pin")
+        ?.let {
+            pin = it
+        }
+    if (isChat) {
+        Row {
+            if (pin.isNotEmpty()) {
+                val buddy by buddyViewModel.getBuddy(pin).observeAsState()
+                AsyncImage(
+                    model = ImageRequest.Builder(LocalContext.current)
+                        .data("https://digixplatform.com/filepalio/image/${buddy?.image_id}")
+                        .addHeader("Cookie", "PHPSESSID=123;MOBILE=123")
+                        .crossfade(true)
+                        .build(),
+                    placeholder = rememberVectorPainter(image = Icons.Default.Person),
+                    contentDescription = "",
+                    contentScale = ContentScale.Crop,
+                    modifier = Modifier
+                        .align(Alignment.CenterVertically)
+                        .size(48.dp)
+                        .clip(CircleShape)
+                        .background(Color.LightGray),
+                    error = rememberVectorPainter(image = Icons.Default.Person),
+                )
+            }
+            Spacer(modifier = Modifier.width(8.dp))
+            Text(modifier = Modifier.align(Alignment.CenterVertically), text = title)
+        }
+    } else {
+        Text(text = title)
+    }
+}

+ 19 - 89
app/src/main/java/io/nexilis/alpha/ui/main/Chat.kt

@@ -1,10 +1,8 @@
 package io.nexilis.alpha.ui.main
 
 import Attachments
-import android.text.format.DateUtils
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.background
-import androidx.compose.foundation.combinedClickable
 import androidx.compose.foundation.layout.*
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.rememberLazyListState
@@ -13,41 +11,41 @@ import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.automirrored.filled.Send
-import androidx.compose.material.icons.filled.AccessTime
-import androidx.compose.material.icons.filled.Done
-import androidx.compose.material.icons.filled.DoneAll
 import androidx.compose.material3.*
 import androidx.compose.runtime.*
 import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.layout.onSizeChanged
-import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.input.KeyboardCapitalization
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.dp
 import androidx.hilt.navigation.compose.hiltViewModel
 import androidx.navigation.NavHostController
+import io.nexilis.alpha.ui.components.LeftBubbleChat
+import io.nexilis.alpha.ui.components.RightBubbleChat
 import io.nexilis.alpha.ui.viewmodel.MainViewModel
-import io.nexilis.service.core.BlueSky
 import io.nexilis.service.core.WhiteTransparent
+import io.nexilis.service.data.entities.Buddy
 import io.nexilis.service.data.entities.Message
 import io.nexilis.service.data.viewmodels.BuddyViewModel
 import io.nexilis.service.data.viewmodels.MessageStatusViewModel
 import io.nexilis.service.data.viewmodels.MessageViewModel
 
-@OptIn(ExperimentalFoundationApi::class)
 @Composable
-fun Chat(navController: NavHostController, pin: String, mainViewModel: MainViewModel) {
+fun Chat(
+    navController: NavHostController,
+    pin: String,
+    mainViewModel: MainViewModel,
+    buddyViewModel: BuddyViewModel,
+    me: Buddy?
+) {
     var textInput by rememberSaveable(stateSaver = TextFieldValue.Saver) {
         mutableStateOf(TextFieldValue("", TextRange(0, 7)))
     }
-    val buddyViewModel: BuddyViewModel = hiltViewModel()
-    val me by buddyViewModel.me.observeAsState()
     val buddy by buddyViewModel.getBuddy(pin).observeAsState()
     val messageModel: MessageViewModel = hiltViewModel()
     val list by messageModel.getOpposite(pin).observeAsState()
@@ -83,96 +81,28 @@ fun Chat(navController: NavHostController, pin: String, mainViewModel: MainViewM
                         horizontalArrangement = if (message?.f_pin == me?.f_pin) Arrangement.End else Arrangement.Start
                     ) {
                         if (message?.f_pin == me?.f_pin) {
-                            Spacer(modifier = Modifier.weight(0.2f))
-                            Column(
-                                modifier = Modifier
-                                    .weight(weight = 0.8f, fill = false)
+                            Spacer(modifier = Modifier.weight(0.1f))
+                            RightBubbleChat(
+                                modifier = Modifier.weight(weight = 0.9f, fill = false),
+                                message = message,
+                                messageStatusModel = messageStatusModel
                             ) {
                                 Text(
-                                    modifier = Modifier
-                                        .align(Alignment.End)
-                                        .graphicsLayer {
-//                                            shadowElevation = 2.dp.toPx()
-                                            shape = RoundedCornerShape(16.dp)
-                                            clip = true
-                                        }
-                                        .combinedClickable(onLongClick = {}, onClick = {})
-                                        .background(color = MaterialTheme.colorScheme.primaryContainer)
-                                        .padding(8.dp),
                                     text = list?.get(it)?.message_text ?: "",
                                     style = MaterialTheme.typography.bodyMedium,
                                 )
-                                Row(
-                                    modifier = Modifier
-                                        .padding(3.dp)
-                                        .align(Alignment.End)
-                                ) {
-                                    Text(
-                                        text = DateUtils.formatDateTime(
-                                            LocalContext.current,
-                                            list?.get(it)?.server_date ?: 0,
-                                            DateUtils.FORMAT_SHOW_TIME
-                                        ),
-                                        color = MaterialTheme.colorScheme.onPrimaryContainer,
-                                        style = MaterialTheme.typography.bodySmall,
-                                    )
-                                    Spacer(modifier = Modifier.width(6.dp))
-                                    message?.message_id?.let {
-                                        val messageStatus by messageStatusModel.get(it, pin)
-                                            .observeAsState()
-                                        Icon(
-                                            imageVector = when (messageStatus?.status) {
-                                                1, 2 -> Icons.Default.Done
-                                                3 -> Icons.Default.DoneAll
-                                                4 -> Icons.Default.DoneAll
-                                                else -> Icons.Default.AccessTime
-                                            },
-                                            contentDescription = "",
-                                            modifier = Modifier
-                                                .align(Alignment.Bottom)
-                                                .size(16.dp),
-                                            tint = if (messageStatus?.status == 4) Color.BlueSky else Color.Gray
-                                        )
-                                    }
-
-                                }
                             }
                         } else {
-                            Column(
-                                modifier = Modifier
-                                    .weight(weight = 0.8f, fill = false)
+                            LeftBubbleChat(
+                                modifier = Modifier.weight(weight = 0.9f, fill = false),
+                                message = message
                             ) {
                                 Text(
-                                    modifier = Modifier
-                                        .align(Alignment.Start)
-                                        .graphicsLayer {
-//                                            shadowElevation = 2.dp.toPx()
-                                            shape = RoundedCornerShape(16.dp)
-                                            clip = true
-                                        }
-                                        .combinedClickable(onLongClick = {}, onClick = {})
-                                        .background(color = MaterialTheme.colorScheme.surface)
-                                        .padding(8.dp),
                                     text = list?.get(it)?.message_text ?: "",
                                     style = MaterialTheme.typography.bodyMedium,
                                 )
-                                Row(
-                                    modifier = Modifier
-                                        .padding(3.dp)
-                                        .align(Alignment.End)
-                                ) {
-                                    Text(
-                                        text = DateUtils.formatDateTime(
-                                            LocalContext.current,
-                                            list?.get(it)?.server_date ?: 0,
-                                            DateUtils.FORMAT_SHOW_TIME
-                                        ),
-                                        color = MaterialTheme.colorScheme.onSurface,
-                                        style = MaterialTheme.typography.bodySmall,
-                                    )
-                                }
                             }
-                            Spacer(modifier = Modifier.weight(0.2f))
+                            Spacer(modifier = Modifier.weight(0.1f))
                         }
                     }
                 }, colors = ListItemDefaults.colors(containerColor = Color.Transparent))

+ 18 - 4
app/src/main/java/io/nexilis/alpha/ui/main/Main.kt

@@ -20,12 +20,16 @@ import androidx.navigation.compose.currentBackStackEntryAsState
 import androidx.navigation.compose.rememberNavController
 import androidx.navigation.navArgument
 import androidx.navigation.navigation
+import io.nexilis.alpha.ui.components.ActionsMenu
+import io.nexilis.alpha.ui.components.Title
 import io.nexilis.alpha.ui.screen.Screen
 import io.nexilis.alpha.ui.viewmodel.MainViewModel
+import io.nexilis.service.data.entities.Buddy
+import io.nexilis.service.data.viewmodels.BuddyViewModel
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
-fun Main(navController: NavHostController) {
+fun Main(navController: NavHostController, buddyViewModel: BuddyViewModel, me: Buddy?) {
     val navMainController = rememberNavController()
     val hostState = remember { SnackbarHostState() }
     val navBackStackEntry by navMainController.currentBackStackEntryAsState()
@@ -43,12 +47,20 @@ fun Main(navController: NavHostController) {
         modifier = Modifier.fillMaxSize(),
         topBar = {
             TopAppBar(
-                title = { Text(text = title) },
+                title = {
+                    Title(
+                        navMainController = navMainController,
+                        title
+                    )
+                },
                 navigationIcon = {
                     NavigationIcon(navController = navMainController, isHome = isHome)
                 },
                 actions = {
-                    ActionsMenu(navController = navController, navMainController = navMainController)
+                    ActionsMenu(
+                        navController = navController,
+                        navMainController = navMainController
+                    )
                 }
             )
         },
@@ -95,7 +107,9 @@ fun Main(navController: NavHostController) {
                             Chat(
                                 navController = navMainController,
                                 pin = pin,
-                                mainViewModel = mainViewModel
+                                mainViewModel = mainViewModel,
+                                buddyViewModel = buddyViewModel,
+                                me = me
                             )
                         }
                 }

+ 0 - 32
app/src/main/java/io/nexilis/alpha/ui/main/Profile.kt

@@ -32,7 +32,6 @@ import io.nexilis.service.core.createImageFile
 import io.nexilis.service.data.viewmodels.BuddyViewModel
 import java.util.Objects
 
-
 @Composable
 fun Profile(contentPadding: PaddingValues = PaddingValues(0.dp), mainViewModel: MainViewModel) {
     SideEffect {
@@ -124,36 +123,5 @@ fun Profile(contentPadding: PaddingValues = PaddingValues(0.dp), mainViewModel:
                 Icon(imageVector = Icons.Default.Person, contentDescription = "")
             }
         )
-        ListItem(
-            headlineContent = { Text("About", style = MaterialTheme.typography.bodySmall) },
-            supportingContent = { Text("Yahoo", style = MaterialTheme.typography.titleMedium) },
-            leadingContent = {
-                Icon(imageVector = Icons.Default.Info, contentDescription = "")
-            }
-        )
-        ListItem(
-            headlineContent = { Text("Phone", style = MaterialTheme.typography.bodySmall) },
-            supportingContent = {
-                Text(
-                    "08112345678",
-                    style = MaterialTheme.typography.titleMedium
-                )
-            },
-            leadingContent = {
-                Icon(imageVector = Icons.Default.Call, contentDescription = "")
-            }
-        )
-        ListItem(
-            headlineContent = { Text("Email", style = MaterialTheme.typography.bodySmall) },
-            supportingContent = {
-                Text(
-                    "yayandw@gmail.com",
-                    style = MaterialTheme.typography.titleMedium
-                )
-            },
-            leadingContent = {
-                Icon(imageVector = Icons.Default.Email, contentDescription = "")
-            }
-        )
     }
 }

+ 1 - 1
app/src/main/java/io/nexilis/alpha/ui/main/Root.kt

@@ -36,7 +36,7 @@ fun Root(navController: NavHostController = rememberNavController()) {
             }
         }
         composable(route = Graph.home) {
-            Main(navController = navController)
+            Main(navController = navController, buddyViewModel = viewModel, me = me)
         }
         composable(route = Screen.Friend.route) {
             Friend(navController = navController)