diff --git a/features/home/src/main/AndroidManifest.xml b/features/home/src/main/AndroidManifest.xml index ccee295..e9b8247 100644 --- a/features/home/src/main/AndroidManifest.xml +++ b/features/home/src/main/AndroidManifest.xml @@ -3,7 +3,6 @@ - \ No newline at end of file diff --git a/features/home/src/main/kotlin/app/dapk/st/home/MainActivity.kt b/features/home/src/main/kotlin/app/dapk/st/home/MainActivity.kt index 1ff20c1..c308346 100644 --- a/features/home/src/main/kotlin/app/dapk/st/home/MainActivity.kt +++ b/features/home/src/main/kotlin/app/dapk/st/home/MainActivity.kt @@ -1,7 +1,6 @@ package app.dapk.st.home import android.os.Bundle -import android.widget.Toast import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.AlertDialog import androidx.compose.material3.Surface @@ -11,15 +10,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.lifecycleScope import app.dapk.st.core.DapkActivity -import app.dapk.st.core.Lce import app.dapk.st.core.module import app.dapk.st.core.viewModel -import app.dapk.st.design.components.Route -import app.dapk.st.design.components.SpiderPage import app.dapk.st.directory.DirectoryModule -import app.dapk.st.home.gallery.Folder -import app.dapk.st.home.gallery.GetImageFromGallery -import app.dapk.st.home.gallery.Media import app.dapk.st.login.LoginModule import app.dapk.st.profile.ProfileModule import kotlinx.coroutines.flow.launchIn @@ -41,11 +34,6 @@ class MainActivity : DapkActivity() { } }.launchIn(lifecycleScope) - registerForActivityResult(GetImageFromGallery()) { - Toast.makeText(this, it.toString(), Toast.LENGTH_SHORT).show() - }.launch(null) - - setContent { if (homeViewModel.hasVersionChanged()) { BetaUpgradeDialog() @@ -73,22 +61,3 @@ class MainActivity : DapkActivity() { ) } } - - -data class ImageGalleryState( - val page: SpiderPage, -) - - -sealed interface ImageGalleryPage { - data class Folders(val content: Lce>) : ImageGalleryPage - data class Files(val content: Lce>) : ImageGalleryPage - - object Routes { - val folders = Route("Folders") - val files = Route("Files") - } -} - - -sealed interface ImageGalleryEvent diff --git a/features/messenger/src/main/AndroidManifest.xml b/features/messenger/src/main/AndroidManifest.xml index 41b5625..d81f786 100644 --- a/features/messenger/src/main/AndroidManifest.xml +++ b/features/messenger/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ android:windowSoftInputMode="adjustResize"/> + diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerActivity.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerActivity.kt index a648dee..6849d35 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerActivity.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerActivity.kt @@ -5,16 +5,16 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable +import android.widget.Toast import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Surface import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.Modifier -import app.dapk.st.core.DapkActivity +import app.dapk.st.core.* import app.dapk.st.core.extensions.unsafeLazy -import app.dapk.st.core.module -import app.dapk.st.core.viewModel import app.dapk.st.matrix.common.RoomId +import app.dapk.st.messenger.gallery.GetImageFromGallery import app.dapk.st.navigator.MessageAttachment import kotlinx.parcelize.Parcelize @@ -51,10 +51,25 @@ class MessengerActivity : DapkActivity() { super.onCreate(savedInstanceState) val payload = readPayload() val factory = module.decryptingFetcherFactory(RoomId(payload.roomId)) + + val galleryLauncher = registerForActivityResult(GetImageFromGallery()) { + it?.let { uri -> + viewModel.post( + MessengerAction.ComposerImageUpdate( + MessageAttachment( + AndroidUri(it.toString()), + MimeType.Image, + ) + ) + ) + } + } + + setContent { Surface(Modifier.fillMaxSize()) { CompositionLocalProvider(LocalDecyptingFetcherFactory provides factory) { - MessengerScreen(RoomId(payload.roomId), payload.attachments, viewModel, navigator) + MessengerScreen(RoomId(payload.roomId), payload.attachments, viewModel, navigator, galleryLauncher) } } } diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerScreen.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerScreen.kt index a1e98f8..7e9d8ae 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerScreen.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerScreen.kt @@ -1,9 +1,11 @@ package app.dapk.st.messenger import android.content.res.Configuration +import androidx.activity.result.ActivityResultLauncher import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* import androidx.compose.foundation.shape.CircleShape @@ -11,9 +13,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Check -import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.filled.Send +import androidx.compose.material.icons.filled.* import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -47,10 +47,16 @@ import coil.request.ImageRequest import kotlinx.coroutines.launch @Composable -internal fun MessengerScreen(roomId: RoomId, attachments: List?, viewModel: MessengerViewModel, navigator: Navigator) { +internal fun MessengerScreen( + roomId: RoomId, + attachments: List?, + viewModel: MessengerViewModel, + navigator: Navigator, + galleryLauncher: ActivityResultLauncher<*> +) { val state = viewModel.state - viewModel.ObserveEvents() + viewModel.ObserveEvents(galleryLauncher) LifecycleEffect( onStart = { viewModel.post(MessengerAction.OnMessengerVisible(roomId, attachments)) }, onStop = { viewModel.post(MessengerAction.OnMessengerGone) } @@ -74,6 +80,7 @@ internal fun MessengerScreen(roomId: RoomId, attachments: List) { StartObserving { this@ObserveEvents.events.launch { - // TODO() + when (it) { + MessengerEvent.SelectImageAttachment -> galleryLauncher.launch(null) + } } } } @@ -553,7 +562,7 @@ private fun RowScope.SendStatus(message: RoomEvent) { } @Composable -private fun TextComposer(state: ComposerState.Text, onTextChange: (String) -> Unit, onSend: () -> Unit) { +private fun TextComposer(state: ComposerState.Text, onTextChange: (String) -> Unit, onSend: () -> Unit, onAttach: () -> Unit) { Row( Modifier .fillMaxWidth() @@ -579,7 +588,16 @@ private fun TextComposer(state: ComposerState.Text, onTextChange: (String) -> Un onValueChange = { onTextChange(it) }, cursorBrush = SolidColor(MaterialTheme.colorScheme.primary), textStyle = LocalTextStyle.current.copy(color = SmallTalkTheme.extendedColors.onOthersBubble), - keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences, autoCorrect = true) + keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences, autoCorrect = true), + decorationBox = { + Box { + Icon( + modifier = Modifier.align(Alignment.CenterEnd).clickable { onAttach() }, + imageVector = Icons.Filled.Image, + contentDescription = "", + ) + } + } ) } } diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerState.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerState.kt index 17bcd11..cf335e6 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerState.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerState.kt @@ -10,7 +10,9 @@ data class MessengerScreenState( val composerState: ComposerState, ) -sealed interface MessengerEvent +sealed interface MessengerEvent { + object SelectImageAttachment : MessengerEvent +} sealed interface ComposerState { diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerViewModel.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerViewModel.kt index 86930b0..aead223 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerViewModel.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerViewModel.kt @@ -48,6 +48,7 @@ internal class MessengerViewModel( is MessengerAction.ComposerTextUpdate -> updateState { copy(composerState = ComposerState.Text(action.newValue)) } MessengerAction.ComposerSendText -> sendMessage() MessengerAction.ComposerClear -> updateState { copy(composerState = ComposerState.Text("")) } + is MessengerAction.ComposerImageUpdate -> updateState { copy(composerState = ComposerState.Attachments(listOf(action.newValue))) } } } @@ -100,6 +101,7 @@ internal class MessengerViewModel( } } } + is ComposerState.Attachments -> { val copy = composerState.copy() updateState { copy(composerState = ComposerState.Text("")) } @@ -123,6 +125,10 @@ internal class MessengerViewModel( } } + fun startAttachment() { + _events.tryEmit(MessengerEvent.SelectImageAttachment) + } + } private fun MessengerState.latestMessageEventFromOthers(self: UserId) = this.roomState.events @@ -133,6 +139,7 @@ private fun MessengerState.latestMessageEventFromOthers(self: UserId) = this.roo sealed interface MessengerAction { data class ComposerTextUpdate(val newValue: String) : MessengerAction + data class ComposerImageUpdate(val newValue: MessageAttachment) : MessengerAction object ComposerSendText : MessengerAction object ComposerClear : MessengerAction data class OnMessengerVisible(val roomId: RoomId, val attachments: List?) : MessengerAction diff --git a/features/home/src/main/kotlin/app/dapk/st/home/gallery/FetchMediaFoldersUseCase.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/FetchMediaFoldersUseCase.kt similarity index 99% rename from features/home/src/main/kotlin/app/dapk/st/home/gallery/FetchMediaFoldersUseCase.kt rename to features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/FetchMediaFoldersUseCase.kt index d4d0e66..8d08c97 100644 --- a/features/home/src/main/kotlin/app/dapk/st/home/gallery/FetchMediaFoldersUseCase.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/FetchMediaFoldersUseCase.kt @@ -1,4 +1,4 @@ -package app.dapk.st.home.gallery +package app.dapk.st.messenger.gallery import android.content.ContentResolver import android.content.ContentUris diff --git a/features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryActivity.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryActivity.kt similarity index 96% rename from features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryActivity.kt rename to features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryActivity.kt index 00275ea..53430dc 100644 --- a/features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryActivity.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryActivity.kt @@ -1,4 +1,4 @@ -package app.dapk.st.home.gallery +package app.dapk.st.messenger.gallery import android.Manifest import android.app.Activity @@ -15,7 +15,6 @@ import androidx.lifecycle.lifecycleScope import app.dapk.st.core.DapkActivity import app.dapk.st.core.Lce import app.dapk.st.core.PermissionResult -import app.dapk.st.home.ImageGalleryScreen import kotlinx.coroutines.launch class ImageGalleryActivity : DapkActivity() { diff --git a/features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryScreen.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryScreen.kt similarity index 97% rename from features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryScreen.kt rename to features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryScreen.kt index d9fcc2a..acb46c1 100644 --- a/features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryScreen.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryScreen.kt @@ -1,4 +1,4 @@ -package app.dapk.st.home +package app.dapk.st.messenger.gallery import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -24,9 +24,6 @@ import app.dapk.st.core.components.CenteredLoading import app.dapk.st.design.components.GenericError import app.dapk.st.design.components.Spider import app.dapk.st.design.components.SpiderPage -import app.dapk.st.home.gallery.Folder -import app.dapk.st.home.gallery.ImageGalleryViewModel -import app.dapk.st.home.gallery.Media import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest diff --git a/features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryViewModel.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryViewModel.kt similarity index 80% rename from features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryViewModel.kt rename to features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryViewModel.kt index a8107b9..1a6d3b1 100644 --- a/features/home/src/main/kotlin/app/dapk/st/home/gallery/ImageGalleryViewModel.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/ImageGalleryViewModel.kt @@ -1,11 +1,9 @@ -package app.dapk.st.home.gallery +package app.dapk.st.messenger.gallery import androidx.lifecycle.viewModelScope import app.dapk.st.core.Lce +import app.dapk.st.design.components.Route import app.dapk.st.design.components.SpiderPage -import app.dapk.st.home.ImageGalleryEvent -import app.dapk.st.home.ImageGalleryPage -import app.dapk.st.home.ImageGalleryState import app.dapk.st.viewmodel.DapkViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -70,4 +68,21 @@ class ImageGalleryViewModel( updateState { copy(page = (page as SpiderPage).copy(state = block(page.state))) } } -} \ No newline at end of file +} + +data class ImageGalleryState( + val page: SpiderPage, +) + + +sealed interface ImageGalleryPage { + data class Folders(val content: Lce>) : ImageGalleryPage + data class Files(val content: Lce>) : ImageGalleryPage + + object Routes { + val folders = Route("Folders") + val files = Route("Files") + } +} + +sealed interface ImageGalleryEvent