diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
index 9e2ecd2a1..9f0a38749 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
@@ -241,7 +241,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private val viewModel: ConversationViewModel by viewModels {
var threadId = intent.getLongExtra(THREAD_ID, -1L)
if (threadId == -1L) {
- intent.getParcelableExtra
(ADDRESS)?.let { it ->
+ intent.getParcelableExtra(ADDRESS, Address::class.java)?.let { it ->
threadId = threadDb.getThreadIdIfExistsFor(it.serialize())
if (threadId == -1L) {
val sessionId = SessionId(it.serialize())
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt
index 4401b4c3c..36f4a9585 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupFragment.kt
@@ -1,14 +1,17 @@
package org.thoughtcrime.securesms.groups
+import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.LocalContext
import androidx.fragment.app.Fragment
import androidx.hilt.navigation.compose.hiltViewModel
import com.ramcosta.composedestinations.DestinationsNavHost
@@ -23,6 +26,7 @@ import kotlinx.parcelize.Parcelize
import network.loki.messenger.databinding.FragmentCreateGroupBinding
import org.session.libsession.messaging.contacts.Contact
import org.thoughtcrime.securesms.conversation.start.NewConversationDelegate
+import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.groups.compose.CreateGroup
import org.thoughtcrime.securesms.groups.compose.CreateGroupNavGraph
import org.thoughtcrime.securesms.groups.compose.SelectContacts
@@ -59,7 +63,7 @@ class CreateGroupFragment : Fragment() {
}
@Parcelize
-data class ContactList(val contacts: List) : Parcelable
+data class ContactList(val contacts: Set) : Parcelable
@CreateGroupNavGraph(start = true)
@Composable
@@ -83,6 +87,18 @@ fun CreateGroupScreen(
}
}
+ val context = LocalContext.current
+
+ viewState.createdGroup?.let { group ->
+ SideEffect {
+ getDelegate().onDialogClosePressed()
+ val intent = Intent(context, ConversationActivityV2::class.java).apply {
+ putExtra(ConversationActivityV2.ADDRESS, group.address)
+ }
+ context.startActivity(intent)
+ }
+ }
+
CreateGroup(
viewState,
viewModel::updateState,
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt
index 8acf79621..72a96a65c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt
@@ -4,9 +4,10 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
+import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
import network.loki.messenger.R
-import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.groups.compose.StateUpdate
import org.thoughtcrime.securesms.groups.compose.ViewState
@@ -17,10 +18,6 @@ class CreateGroupViewModel @Inject constructor(
private val storage: Storage,
) : ViewModel() {
- private fun create() {
- tryCreateGroup()
- }
-
private inline fun MutableLiveData.update(body: T.() -> T) {
this.postValue(body(this.value!!))
}
@@ -35,14 +32,14 @@ class CreateGroupViewModel @Inject constructor(
is StateUpdate.Description -> _viewState.update { copy(description = stateUpdate.value) }
is StateUpdate.Name -> _viewState.update { copy(name = stateUpdate.value) }
is StateUpdate.RemoveContact -> _viewState.update { copy(members = members - stateUpdate.value) }
- StateUpdate.Create -> { tryCreateGroup() }
+ StateUpdate.Create -> { viewModelScope.launch { tryCreateGroup() } }
}
}
val contacts
get() = liveData { emit(storage.getAllContacts()) }
- fun tryCreateGroup(): Recipient? {
+ fun tryCreateGroup() {
val currentState = _viewState.value!!
@@ -55,10 +52,9 @@ class CreateGroupViewModel @Inject constructor(
// do some validation
// need a name
if (name.isEmpty()) {
- _viewState.postValue(
+ return _viewState.postValue(
currentState.copy(isLoading = false, error = R.string.error)
)
- return null
}
storage.getAllContacts().forEach { contact ->
@@ -77,8 +73,14 @@ class CreateGroupViewModel @Inject constructor(
// make a group
val newGroup = storage.createNewGroup(name, description, members)
if (!newGroup.isPresent) {
- _viewState.postValue(currentState.copy(isLoading = false, error = null))
+ // show a generic couldn't create or something?
+ return _viewState.postValue(currentState.copy(isLoading = false, error = null))
+ } else {
+ return _viewState.postValue(currentState.copy(
+ isLoading = false,
+ error = null,
+ createdGroup = newGroup.get())
+ )
}
- return newGroup.orNull()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/Components.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/Components.kt
index ea58ba56c..c46d5b2e5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/Components.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/Components.kt
@@ -14,6 +14,7 @@ import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.MaterialTheme
+import androidx.compose.material.RadioButton
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
@@ -54,10 +55,54 @@ fun EmptyPlaceholder(modifier: Modifier = Modifier) {
}
}
-fun LazyListScope.memberList(
+fun LazyListScope.multiSelectMemberList(
contacts: List,
modifier: Modifier = Modifier,
- onDelete: (Contact) -> Unit
+ selectedContacts: Set = emptySet(),
+ onListUpdated: (Set)->Unit = {},
+) {
+ items(contacts) { contact ->
+ val isSelected = selectedContacts.contains(contact)
+
+ val update = {
+ val newList =
+ if (isSelected) selectedContacts - contact
+ else selectedContacts + contact
+ onListUpdated(newList)
+ }
+
+ Row(modifier = modifier.fillMaxWidth()
+ .clickable(onClick = update)
+ .padding(vertical = 8.dp, horizontal = 24.dp),
+ verticalAlignment = CenterVertically
+ ) {
+ ContactPhoto(
+ contact = contact,
+ modifier = Modifier
+ .size(48.dp)
+ )
+ MemberName(name = contact.getSearchName())
+ RadioButton(selected = isSelected, onClick = update)
+ }
+ }
+}
+
+@Composable
+fun RowScope.MemberName(
+ name: String
+) = Text(
+ text = name,
+ fontWeight = FontWeight.Bold,
+ modifier = Modifier
+ .weight(1f)
+ .padding(16.dp)
+ .align(CenterVertically)
+)
+
+fun LazyListScope.deleteMemberList(
+ contacts: List,
+ modifier: Modifier = Modifier,
+ onDelete: (Contact) -> Unit,
) {
item {
Text(
@@ -80,23 +125,16 @@ fun LazyListScope.memberList(
.size(48.dp)
.align(CenterVertically)
)
- Text(
- text = contact.getSearchName(),
- fontWeight = FontWeight.Bold,
- modifier = Modifier
- .weight(1f)
- .padding(16.dp)
- .align(CenterVertically)
- )
+ MemberName(name = contact.getSearchName())
Image(
painterResource(id = R.drawable.ic_baseline_close_24),
null,
- Modifier
+ modifier = Modifier
.size(32.dp)
.align(CenterVertically)
.clickable {
onDelete(contact)
- }
+ },
)
}
}
@@ -141,12 +179,9 @@ fun PreviewMemberList(
)
PreviewTheme(themeResId = themeResId) {
LazyColumn {
- memberList(
- previewMembers.toList(),
- Modifier.padding(vertical = 8.dp, horizontal = 24.dp)
- ) { deleted ->
-
- }
+ multiSelectMemberList(
+ contacts = previewMembers.toList(),
+ )
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/CreateGroup.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/CreateGroup.kt
index 946fc43eb..663917e2a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/CreateGroup.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/CreateGroup.kt
@@ -32,6 +32,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import network.loki.messenger.R
import org.session.libsession.messaging.contacts.Contact
+import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
import org.thoughtcrime.securesms.ui.Divider
import org.thoughtcrime.securesms.ui.EditableAvatar
@@ -149,7 +150,7 @@ fun CreateGroup(
}
}
// Group list
- memberList(contacts = viewState.members, modifier = Modifier.padding(vertical = 8.dp, horizontal = 24.dp)) { deletedContact ->
+ deleteMemberList(contacts = viewState.members, modifier = Modifier.padding(vertical = 8.dp, horizontal = 24.dp)) { deletedContact ->
updateState(StateUpdate.RemoveContact(deletedContact))
}
}
@@ -218,6 +219,7 @@ data class ViewState(
val name: String = "",
val description: String = "",
val members: List = emptyList(),
+ val createdGroup: Recipient? = null,
) {
val canCreate
@@ -234,5 +236,5 @@ sealed class StateUpdate {
data class Name(val value: String): StateUpdate()
data class Description(val value: String): StateUpdate()
data class RemoveContact(val value: Contact): StateUpdate()
- data class AddContacts(val value: List): StateUpdate()
+ data class AddContacts(val value: Set): StateUpdate()
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/SelectContacts.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/SelectContacts.kt
index 3e407124f..3b717ddf4 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/compose/SelectContacts.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/compose/SelectContacts.kt
@@ -1,26 +1,36 @@
package org.thoughtcrime.securesms.groups.compose
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.OutlinedButton
+import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
import network.loki.messenger.R
import org.session.libsession.messaging.contacts.Contact
import org.thoughtcrime.securesms.home.search.getSearchName
import org.thoughtcrime.securesms.ui.NavigationBar
import org.thoughtcrime.securesms.ui.SearchBar
+@OptIn(ExperimentalFoundationApi::class)
@Composable
fun SelectContacts(
contactListState: Set,
onBack: ()->Unit,
onClose: ()->Unit,
- onContactsSelected: (List) -> Unit,
+ onContactsSelected: (Set) -> Unit,
) {
var queryFilter by remember { mutableStateOf("") }
@@ -30,12 +40,16 @@ fun SelectContacts(
else {
contactListState
.filter { contact ->
- contact.getSearchName()
+ contact.getSearchName().lowercase()
.contains(queryFilter)
}
.toList()
}
+ var selected by remember {
+ mutableStateOf(emptySet())
+ }
+
Column {
NavigationBar(
title = stringResource(id = R.string.activity_create_closed_group_select_contacts),
@@ -43,14 +57,24 @@ fun SelectContacts(
onClose = onClose
)
- LazyColumn {
- item {
+ LazyColumn(modifier = Modifier.weight(1f)) {
+ stickyHeader {
// Search Bar
SearchBar(queryFilter, onValueChanged = { value -> queryFilter = value })
}
- items(filtered) { contact ->
-
+ multiSelectMemberList(
+ contacts = filtered.toList(),
+ selectedContacts = selected,
+ onListUpdated = { selected = it },
+ )
+ }
+ Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth()) {
+ OutlinedButton(
+ onClick = { onContactsSelected(selected) },
+ shape = CircleShape,
+ modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp)) {
+ Text(stringResource(id = R.string.ok))
}
}
}
diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/ConfigurationSyncJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/ConfigurationSyncJob.kt
index 0835b2800..946d3cc64 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/jobs/ConfigurationSyncJob.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/ConfigurationSyncJob.kt
@@ -118,7 +118,7 @@ data class ConfigurationSyncJob(val destination: Destination) : Job {
)
return ConfigMessageInformation(
- if (signingKey != null && ed25519PubKey != null) {
+ if (signingKey != null && ed25519PubKey == null) {
SnodeAPI.buildAuthenticatedStoreBatchInfo(
namespace(),
message,