Skip to content

Commit

Permalink
Merge pull request #116 from Tiebe/messages
Browse files Browse the repository at this point in the history
Messages
  • Loading branch information
Tiebe authored Apr 14, 2024
2 parents ce386ce + 0a223b6 commit 7de2282
Show file tree
Hide file tree
Showing 29 changed files with 2,383 additions and 142 deletions.
2 changes: 1 addition & 1 deletion libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ wear_sdk-compile = "33"

ios_target = "11.0"

magister = "1.2.0"
magister = "1.3.0"

work-android = "2.9.0"

Expand Down
2 changes: 1 addition & 1 deletion shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ android {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

}

@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
Expand Down Expand Up @@ -78,7 +79,6 @@ kotlin {
implementation(libs.color.math)

implementation(libs.skiko)

}
}
androidMain {
Expand Down
2 changes: 1 addition & 1 deletion shared/shared.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'shared'
spec.version = '4.1.0'
spec.version = '4.1.1'
spec.homepage = 'https://otarium.groosman.nl'
spec.source = { :http=> ''}
spec.authors = ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,8 @@ actual fun dynamicColorsPossible(): Boolean {
actual fun convertImageByteArrayToBitmap(imageData: ByteArray): ImageBitmap {
val image = BitmapFactory.decodeByteArray(imageData, 0, imageData.size)
return image.asImageBitmap()
}

actual suspend fun awaitFrame() {
kotlinx.coroutines.android.awaitFrame()
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class DefaultMessagesComponent(
componentContext: ComponentContext,
subject: String,
body: String,
receivers: List<String>
receivers: List<Int>
) =
DefaultMessageComposeComponent(
componentContext = componentContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,59 @@ package nl.tiebe.otarium.logic.default.home.children.messages.children.composing
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.value.MutableValue
import dev.tiebe.magisterapi.api.account.ProfileInfoFlow
import dev.tiebe.magisterapi.api.messages.MessageFlow
import dev.tiebe.magisterapi.response.profileinfo.Contact
import io.ktor.http.*
import kotlinx.coroutines.launch
import nl.tiebe.otarium.Data
import nl.tiebe.otarium.logic.default.componentCoroutineScope
import nl.tiebe.otarium.logic.default.home.children.messages.DefaultMessagesComponent
import nl.tiebe.otarium.logic.root.home.children.messages.children.composing.MessageComposeComponent
import nl.tiebe.otarium.ui.utils.ContactChip
import nl.tiebe.otarium.ui.utils.chips.ChipTextFieldState

class DefaultMessageComposeComponent(
componentContext: ComponentContext,
override val parentComponent: DefaultMessagesComponent,
prefilledSubject: String? = null,
prefilledBody: String? = null,
prefilledTo: List<String>? = null,
prefilledCc: List<String>? = null,
prefilledBcc: List<String>? = null,
prefilledTo: List<Int> = emptyList(),
prefilledCc: List<Int> = emptyList(),
prefilledBcc: List<Int> = emptyList(),
): MessageComposeComponent, ComponentContext by componentContext {
val scope = componentCoroutineScope()
override val contactList: MutableValue<List<Contact>> = MutableValue(listOf())

override val toList: MutableValue<List<String>> = MutableValue(prefilledTo ?: listOf())
override val ccList: MutableValue<List<String>> = MutableValue(prefilledCc ?: listOf())
override val bccList: MutableValue<List<String>> = MutableValue(prefilledBcc ?: listOf())
override val toList = ChipTextFieldState<ContactChip>()
override val ccList = ChipTextFieldState<ContactChip>()
override val bccList = ChipTextFieldState<ContactChip>()
override val subject: MutableValue<String> = MutableValue(prefilledSubject ?: "")
override val body: MutableValue<String> = MutableValue(prefilledBody ?: "")

override fun send() {
TODO("Not yet implemented")
override suspend fun send() {
MessageFlow.sendMessage(
Url(Data.selectedAccount.tenantUrl),
Data.selectedAccount.tokens.accessToken,
subject.value,
body.value,
toList.chips.map { it.contact.id },
ccList.chips.map { it.contact.id },
bccList.chips.map { it.contact.id }
)
}

init {
scope.launch {
contactList.value = ProfileInfoFlow.getContacts(Data.selectedAccount.tenantUrl, Data.selectedAccount.tokens.accessToken)
prefilledTo.mapNotNull { id -> contactList.value.find { it.id == id } }.forEach {
toList.addChip(ContactChip(it))
}
prefilledCc.mapNotNull { id -> contactList.value.find { it.id == id } }.forEach {
ccList.addChip(ContactChip(it))
}
prefilledBcc.mapNotNull { id -> contactList.value.find { it.id == id } }.forEach {
bccList.addChip(ContactChip(it))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ interface MessagesComponent: HomeComponent.MenuItemComponent, BackHandlerOwner {
@Serializable
data class ReceiverInfo(val messageLink: String, val receiverType: ReceiverInfoComponent.ReceiverType) : Config()
@Serializable
data class Compose(val receivers: List<String>, val subject: String, val body: String) : Config()
data class Compose(val receivers: List<Int>, val subject: String, val body: String) : Config()
}

fun back()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
package nl.tiebe.otarium.logic.root.home.children.messages.children.composing

import com.arkivanov.decompose.value.MutableValue
import com.arkivanov.decompose.value.Value
import dev.tiebe.magisterapi.response.profileinfo.Contact
import nl.tiebe.otarium.logic.root.home.children.messages.MessagesComponent
import nl.tiebe.otarium.ui.utils.ContactChip
import nl.tiebe.otarium.ui.utils.chips.ChipTextFieldState

interface MessageComposeComponent {
val parentComponent: MessagesComponent

val contactList: Value<List<Contact>>

val toList: Value<List<String>>
val ccList: Value<List<String>>
val bccList: Value<List<String>>
val toList: ChipTextFieldState<ContactChip>
val ccList: ChipTextFieldState<ContactChip>
val bccList: ChipTextFieldState<ContactChip>

val subject: Value<String>
val body: Value<String>
val subject: MutableValue<String>
val body: MutableValue<String>

fun back() = parentComponent::back

fun send()
suspend fun send()

}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ private fun FolderContent(
component: MessagesComponent,
drawerState: DrawerState
) {
val scope = rememberCoroutineScope()

Scaffold(
topBar = {
when (val instance = screen.value.active.instance) {
Expand All @@ -129,23 +131,23 @@ private fun FolderContent(
}
},
floatingActionButton = {
// if (screen.value.active.instance is MessagesComponent.Child.FolderChild) {
// FloatingActionButton(
// onClick = {
// scope.launch {
// component.navigate(MessagesComponent.Config.Compose(listOf(), "", ""))
// }
// },
// content = {
// Icon(
// imageVector = OtariumIcons.Email.Pencil,
// contentDescription = "Compose new message"
// )
// },
// containerColor = MaterialTheme.colorScheme.primary,
// contentColor = MaterialTheme.colorScheme.onPrimary
// )
// }
if (screen.value.active.instance is MessagesComponent.Child.FolderChild) {
FloatingActionButton(
onClick = {
scope.launch {
component.navigate(MessagesComponent.Config.Compose(listOf(), "", ""))
}
},
content = {
Icon(
imageVector = OtariumIcons.Email.Pencil,
contentDescription = "Compose new message"
)
},
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary
)
}
},
contentWindowInsets = WindowInsets(0)
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,61 +1,92 @@
package nl.tiebe.otarium.ui.home.messages.composing

import androidx.compose.foundation.layout.*
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
import dev.tiebe.magisterapi.response.profileinfo.Contact
import nl.tiebe.otarium.logic.root.home.children.messages.children.composing.MessageComposeComponent
import nl.tiebe.otarium.ui.utils.AutoCompleteTextView
import nl.tiebe.otarium.ui.utils.ContactChip
import nl.tiebe.otarium.ui.utils.chips.ChipTextFieldState

@Composable
fun MessageComposeScreen(component: MessageComposeComponent) {
Column(Modifier.fillMaxSize()) {
ToInputField(component)
Column(Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
ToInputField(component, component.toList, "To")
ToInputField(component, component.ccList, "CC")
ToInputField(component, component.bccList, "BCC")

SubjectInputField(component)

/* CcInputField(component)
BccInputField(component)
BodyInputField(component)
SendButton(component)*/
BodyInputField(component)
}
}


@Composable
fun ToInputField(component: MessageComposeComponent) {
var toText by remember { mutableStateOf("") }

Box(Modifier.padding(start= 16.dp, end = 16.dp, top = 24.dp)) {
fun ToInputField(component: MessageComposeComponent, state: ChipTextFieldState<ContactChip>, label: String) {
Box(Modifier.padding(start= 16.dp, end = 16.dp)) {
var query by remember { mutableStateOf("") }

AutoCompleteTextView(
query = query,
onQueryChanged = { query = it },
predictions = component.contactList.subscribeAsState().value.map { it }, //todo
queryLabel = "Test"
predictions = component.contactList.subscribeAsState().value.filter { contact ->
if (query.isEmpty() || state.chips.any { it.contact == contact }) return@filter false
getName(contact).contains(query, ignoreCase = true)
}.sortedBy { getName(it) },
queryLabel = label,
itemContent = { Text(getName(it)) },
onItemClick = { clickedItem ->
if (state.chips.any { it.contact == clickedItem }) return@AutoCompleteTextView
state.addChip(ContactChip(clickedItem))
query = ""
},
state = state
)
}

}

@OptIn(ExperimentalMaterial3Api::class)
fun getName(contact: Contact): String {
var searchTerm =
"${contact.roepnaam ?: contact.voorletters} ${contact.tussenvoegsel?.plus(" ") ?: ""}${contact.achternaam}"
if (contact.klas != null) {
searchTerm += " (${contact.klas})"
}

return searchTerm
}

@Composable
fun SubjectInputField(component: MessageComposeComponent) {
var subjectText by remember { mutableStateOf("") }

Box(Modifier.padding(start= 16.dp, end = 16.dp, top = 24.dp)) {
Box(Modifier.padding(start = 16.dp, end = 16.dp)) {
OutlinedTextField(
value = subjectText,
onValueChange = { subjectText = it },
value = component.subject.subscribeAsState().value,
onValueChange = { component.subject.value = it },
modifier = Modifier.fillMaxWidth(),
label = { Text("Subject") },
singleLine = true,

singleLine = true
)
}
}

@Composable
fun BodyInputField(component: MessageComposeComponent) {
Box(Modifier.padding(start = 16.dp, end = 16.dp)) {
OutlinedTextField(
value = component.body.subscribeAsState().value,
onValueChange = { component.body.value = it },
modifier = Modifier.fillMaxWidth(),
label = { Text("Body") },
singleLine = false,
)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,37 @@ package nl.tiebe.otarium.ui.home.messages.composing
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.runtime.rememberCoroutineScope
import kotlinx.coroutines.launch
import nl.tiebe.otarium.logic.root.home.children.messages.children.composing.MessageComposeComponent

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MessageComposeTopAppBar(component: MessageComposeComponent) {
val scope = rememberCoroutineScope()

TopAppBar(
title = { Text("Compose message REPLACE THIS", overflow = TextOverflow.Ellipsis, maxLines = 1) },
title = {},
navigationIcon = {
IconButton(onClick = { component.parentComponent.back() }) {
Icon(Icons.Default.ArrowBack, contentDescription = "Back")
}
},
actions = {
// send
IconButton(onClick = { scope.launch {
component.parentComponent.back()
component.send()
}}) {
Icon(Icons.Default.Send, contentDescription = "Send")
}
},
windowInsets = WindowInsets(0)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ fun MessageTopAppBar(component: MessageComponent) {
component.parentComponent.navigate(
MessagesComponent.Config.Compose(
subject = "RE: ${message.subject}",
body = "On ${message.sender.naam} ${message.sender} wrote:\n${message.content}",
receivers = listOf()
body = "\n\n${message.sender.naam} wrote:\n\n${message.content}",
receivers = listOf(message.sender.id)
)
)
} }) {
Expand All @@ -53,8 +53,8 @@ fun MessageTopAppBar(component: MessageComponent) {
IconButton(onClick = { scope.launch {
component.parentComponent.navigate(
MessagesComponent.Config.Compose(
subject = "FWD: ${message.subject}",
body = "On ${message.sender.naam} ${message.sender} wrote:\n${message.content}",
subject = "FW: ${message.subject}",
body = "\n\n${message.sender.naam} wrote:\n\n${message.content}",
receivers = listOf()
)
)
Expand Down
Loading

0 comments on commit 7de2282

Please sign in to comment.