feat(WIP): group creation / navigation / passing and sharing state in vm
This commit is contained in:
parent
82a55d256c
commit
baf2157331
|
@ -47,12 +47,12 @@ android {
|
|||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = '11'
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
|
@ -207,6 +207,7 @@ dependencies {
|
|||
|
||||
implementation("com.google.dagger:hilt-android:2.46.1")
|
||||
kapt("com.google.dagger:hilt-android-compiler:2.46")
|
||||
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
|
||||
|
||||
implementation "io.github.raamcosta.compose-destinations:core:$composeDestinationsVersion"
|
||||
ksp "io.github.raamcosta.compose-destinations:ksp:$composeDestinationsVersion"
|
||||
|
|
|
@ -1,40 +1,42 @@
|
|||
package org.thoughtcrime.securesms.groups
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import com.ramcosta.composedestinations.navigation.dependency
|
||||
import com.ramcosta.composedestinations.result.ResultBackNavigator
|
||||
import com.ramcosta.composedestinations.result.ResultRecipient
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import network.loki.messenger.databinding.FragmentCreateGroupBinding
|
||||
import org.session.libsession.utilities.Device
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
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.CreateGroupState
|
||||
import org.thoughtcrime.securesms.groups.compose.CreateGroupNavGraph
|
||||
import org.thoughtcrime.securesms.groups.compose.SelectContacts
|
||||
import org.thoughtcrime.securesms.groups.compose.ViewState
|
||||
import org.thoughtcrime.securesms.groups.destinations.SelectContactScreenDestination
|
||||
import org.thoughtcrime.securesms.ui.AppTheme
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class CreateGroupFragment : Fragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var device: Device
|
||||
|
||||
private lateinit var binding: FragmentCreateGroupBinding
|
||||
private val viewModel: CreateGroupViewModel by viewModels()
|
||||
|
||||
lateinit var delegate: NewConversationDelegate
|
||||
|
||||
|
@ -43,49 +45,77 @@ class CreateGroupFragment : Fragment() {
|
|||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
val getDelegate = { delegate }
|
||||
setContent {
|
||||
// this is kind of annoying to require an initial state in the fragment and the VM
|
||||
val currentState = viewModel.viewState.observeAsState(initial = ViewState.DEFAULT)
|
||||
// create group state might be useful in future for adding members and returning
|
||||
// to the create group state with a copy or something
|
||||
CreateGroupScreen(currentState.value, createGroupState = CreateGroupState("", "", emptySet()))
|
||||
AppTheme {
|
||||
DestinationsNavHost(navGraph = NavGraphs.createGroup, dependenciesContainerBuilder = {
|
||||
dependency(getDelegate)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openConversationActivity(context: Context, recipient: Recipient) {
|
||||
val intent = Intent(context, ConversationActivityV2::class.java)
|
||||
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CreateGroupScreen(viewState: ViewState,
|
||||
createGroupState: CreateGroupState,
|
||||
modifier: Modifier = Modifier) {
|
||||
AppTheme {
|
||||
CreateGroup(
|
||||
viewState,
|
||||
createGroupState,
|
||||
onCreate = { newGroup ->
|
||||
// launch something to create here
|
||||
// dunno if we want to key this here as a launched effect on some property :thinking:
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val groupRecipient = viewModel.tryCreateGroup(newGroup)
|
||||
groupRecipient?.let { recipient ->
|
||||
openConversationActivity(requireContext(), recipient)
|
||||
delegate.onDialogClosePressed()
|
||||
}
|
||||
}
|
||||
},
|
||||
onClose = {
|
||||
delegate.onDialogClosePressed()
|
||||
},
|
||||
onBack = {
|
||||
delegate.onDialogBackPressed()
|
||||
@CreateGroupNavGraph(start = true)
|
||||
@Composable
|
||||
@Destination
|
||||
fun CreateGroupScreen(
|
||||
navigator: DestinationsNavigator,
|
||||
resultSelectContact: ResultRecipient<SelectContactScreenDestination, Contact?>,
|
||||
viewModel: CreateGroupViewModel = hiltViewModel(),
|
||||
getDelegate: () -> NewConversationDelegate
|
||||
) {
|
||||
val viewState by viewModel.viewState.observeAsState(ViewState.DEFAULT)
|
||||
val lifecycleScope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val currentGroupState = viewModel.createGroupState
|
||||
|
||||
CreateGroup(
|
||||
viewState,
|
||||
currentGroupState,
|
||||
onCreate = { newGroup ->
|
||||
// launch something to create here
|
||||
// dunno if we want to key this here as a launched effect on some property :thinking:
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val groupRecipient = viewModel.tryCreateGroup(newGroup)
|
||||
groupRecipient?.let { recipient ->
|
||||
// launch conversation with this new group
|
||||
val intent = Intent(context, ConversationActivityV2::class.java)
|
||||
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
|
||||
context.startActivity(intent)
|
||||
getDelegate().onDialogClosePressed()
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
onSelectContact = {
|
||||
navigator.navigate(SelectContactScreenDestination)
|
||||
},
|
||||
onClose = {
|
||||
getDelegate().onDialogClosePressed()
|
||||
},
|
||||
onBack = {
|
||||
getDelegate().onDialogBackPressed()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@CreateGroupNavGraph
|
||||
@Composable
|
||||
@Destination
|
||||
fun SelectContactScreen(
|
||||
resultNavigator: ResultBackNavigator<Contact?>,
|
||||
viewModel: CreateGroupViewModel = hiltViewModel(),
|
||||
getDelegate: () -> NewConversationDelegate
|
||||
) {
|
||||
|
||||
val contacts by viewModel.contacts.observeAsState(initial = emptyList())
|
||||
val currentMembers by viewModel.createGroupState.observeAsState()
|
||||
|
||||
SelectContacts(
|
||||
contacts - currentMembers?.members.orEmpty(),
|
||||
onBack = { resultNavigator.navigateBack(null) },
|
||||
onClose = { getDelegate().onDialogClosePressed() }
|
||||
)
|
||||
}
|
|
@ -3,9 +3,8 @@ package org.thoughtcrime.securesms.groups
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.liveData
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
|
@ -23,8 +22,14 @@ class CreateGroupViewModel @Inject constructor(
|
|||
private val _viewState = MutableLiveData(ViewState.DEFAULT)
|
||||
val viewState: LiveData<ViewState> = _viewState
|
||||
|
||||
val createGroupState: MutableLiveData<CreateGroupState> = MutableLiveData(CreateGroupState("","", emptySet()))
|
||||
|
||||
val contacts = liveData {
|
||||
emit(storage.getAllContacts().toList())
|
||||
}
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
// viewModelScope.launch {
|
||||
// threadDb.approvedConversationList.use { openCursor ->
|
||||
// val reader = threadDb.readerFor(openCursor)
|
||||
// val recipients = mutableListOf<Recipient>()
|
||||
|
@ -36,7 +41,7 @@ class CreateGroupViewModel @Inject constructor(
|
|||
// .filter { !it.isGroupRecipient && it.hasApprovedMe() && it.address.serialize() != textSecurePreferences.getLocalNumber() }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
fun tryCreateGroup(createGroupState: CreateGroupState): Recipient? {
|
||||
|
|
|
@ -2,11 +2,14 @@ package org.thoughtcrime.securesms.groups.compose
|
|||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
|
@ -14,7 +17,7 @@ import androidx.compose.material.MaterialTheme
|
|||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
|
@ -22,49 +25,79 @@ import androidx.compose.ui.layout.ContentScale
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.home.search.getSearchName
|
||||
import org.thoughtcrime.securesms.ui.Avatar
|
||||
import org.thoughtcrime.securesms.ui.LocalPreviewMode
|
||||
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||
import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider
|
||||
|
||||
|
||||
@Composable
|
||||
fun EmptyPlaceholder(modifier: Modifier = Modifier) {
|
||||
Column {
|
||||
Column(modifier) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.conversation_settings_group_members),
|
||||
text = stringResource(id = R.string.activity_create_closed_group_empty_placeholer),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.align(Alignment.Start)
|
||||
.padding(vertical = 8.dp)
|
||||
)
|
||||
// TODO group list representation
|
||||
Text(
|
||||
text = stringResource(id = R.string.activity_create_closed_group_not_enough_group_members_error),
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalGlideComposeApi::class)
|
||||
fun LazyListScope.memberList(
|
||||
contacts: List<Contact>,
|
||||
modifier: Modifier = Modifier,
|
||||
onDelete: (Contact) -> Unit
|
||||
) {
|
||||
item {
|
||||
Text(
|
||||
text = stringResource(id = R.string.conversation_settings_group_members),
|
||||
style = MaterialTheme.typography.subtitle2,
|
||||
modifier = modifier
|
||||
.padding(vertical = 8.dp)
|
||||
)
|
||||
}
|
||||
if (contacts.isEmpty()) {
|
||||
item {
|
||||
EmptyPlaceholder(modifier.fillParentMaxWidth())
|
||||
EmptyPlaceholder(modifier.fillMaxWidth())
|
||||
}
|
||||
} else {
|
||||
items(contacts) { contact ->
|
||||
Row(modifier) {
|
||||
ContactPhoto(contact, modifier = Modifier.size(48.dp))
|
||||
Row(modifier.fillMaxWidth()) {
|
||||
ContactPhoto(
|
||||
contact,
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.align(CenterVertically)
|
||||
)
|
||||
Text(
|
||||
text = contact.getSearchName(),
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(16.dp)
|
||||
.align(CenterVertically)
|
||||
)
|
||||
Image(
|
||||
painterResource(id = R.drawable.ic_baseline_close_24),
|
||||
null,
|
||||
Modifier
|
||||
.size(32.dp)
|
||||
.align(CenterVertically)
|
||||
.clickable {
|
||||
onDelete(contact)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,9 +119,34 @@ fun RowScope.ContactPhoto(contact: Contact, modifier: Modifier = Modifier) {
|
|||
)
|
||||
} else {
|
||||
val context = LocalContext.current
|
||||
// Ideally we migrate to something that doesn't require recipient, or get contact photo another way
|
||||
val recipient = remember(contact) {
|
||||
Recipient.from(context, Address.fromSerialized(contact.sessionID), false)
|
||||
}
|
||||
Avatar(recipient)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewMemberList(
|
||||
@PreviewParameter(ThemeResPreviewParameterProvider::class) themeResId: Int
|
||||
) {
|
||||
val random = "05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234"
|
||||
val previewMembers = setOf(
|
||||
Contact(random).apply {
|
||||
name = "Person"
|
||||
}
|
||||
)
|
||||
PreviewTheme(themeResId = themeResId) {
|
||||
LazyColumn {
|
||||
memberList(
|
||||
previewMembers.toList(),
|
||||
Modifier.padding(vertical = 8.dp, horizontal = 24.dp)
|
||||
) { deleted ->
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,18 @@
|
|||
package org.thoughtcrime.securesms.groups.compose
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.MaterialTheme
|
||||
|
@ -25,42 +27,44 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
|
||||
import org.thoughtcrime.securesms.ui.Divider
|
||||
import org.thoughtcrime.securesms.ui.EditableAvatar
|
||||
import org.thoughtcrime.securesms.ui.NavigationBar
|
||||
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||
import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider
|
||||
|
||||
|
||||
data class CreateGroupState (
|
||||
val groupName: String,
|
||||
val groupDescription: String,
|
||||
val members: Set<Contact>
|
||||
var groupName: String,
|
||||
var groupDescription: String,
|
||||
val members: MutableSet<Contact>
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CreateGroup(
|
||||
viewState: ViewState,
|
||||
createGroupState: CreateGroupState,
|
||||
createGroupState: MutableLiveData<CreateGroupState>,
|
||||
onCreate: (CreateGroupState) -> Unit,
|
||||
onSelectContact: () -> Unit,
|
||||
onBack: () -> Unit,
|
||||
onClose: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
|
||||
var name by remember { mutableStateOf(createGroupState.groupName) }
|
||||
var name by createGroupState
|
||||
var description by remember { mutableStateOf(createGroupState.groupDescription) }
|
||||
var members by remember { mutableStateOf(createGroupState.members) }
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
val lazyState = rememberLazyListState()
|
||||
|
||||
val onDeleteMember = { contact: Contact ->
|
||||
|
@ -112,6 +116,50 @@ fun CreateGroup(
|
|||
contentDescription = descriptionDescription
|
||||
},
|
||||
)
|
||||
|
||||
CellWithPaddingAndMargin(padding = 0.dp) {
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
// Select Contacts
|
||||
val padding = Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxWidth()
|
||||
Row(padding.clickable {
|
||||
onSelectContact()
|
||||
}) {
|
||||
Image(
|
||||
painterResource(id = R.drawable.ic_person_white_24dp),
|
||||
null,
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
)
|
||||
Text(
|
||||
stringResource(id = R.string.activity_create_closed_group_select_contacts),
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
Divider()
|
||||
// Add account ID or ONS
|
||||
Row(padding) {
|
||||
Image(
|
||||
painterResource(id = R.drawable.ic_baseline_add_24),
|
||||
null,
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
)
|
||||
Text(
|
||||
stringResource(id = R.string.activity_create_closed_group_add_account_or_ons),
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// Group list
|
||||
|
@ -155,7 +203,6 @@ fun CreateGroup(
|
|||
@Preview
|
||||
@Composable
|
||||
fun ClosedGroupPreview(
|
||||
@PreviewParameter(ThemeResPreviewParameterProvider::class) themeResId: Int
|
||||
) {
|
||||
val random = "05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234"
|
||||
val previewMembers = setOf(
|
||||
|
@ -163,12 +210,13 @@ fun ClosedGroupPreview(
|
|||
name = "Person"
|
||||
}
|
||||
)
|
||||
PreviewTheme(themeResId) {
|
||||
PreviewTheme(R.style.Theme_Session_DayNight_NoActionBar_Test) {
|
||||
CreateGroup(
|
||||
viewState = ViewState(false, null),
|
||||
createGroupState = CreateGroupState("Group Name", "Test Group Description", previewMembers),
|
||||
onCreate = {},
|
||||
onClose = {},
|
||||
onSelectContact = {},
|
||||
onBack = {},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package org.thoughtcrime.securesms.groups.compose
|
||||
|
||||
import com.ramcosta.composedestinations.annotation.NavGraph
|
||||
|
||||
@NavGraph
|
||||
annotation class CreateGroupNavGraph(
|
||||
val start: Boolean = false
|
||||
)
|
|
@ -0,0 +1,52 @@
|
|||
package org.thoughtcrime.securesms.groups.compose
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
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.res.stringResource
|
||||
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
|
||||
|
||||
@Composable
|
||||
fun SelectContacts(
|
||||
contactListState: List<Contact>,
|
||||
onBack: ()->Unit,
|
||||
onClose: ()->Unit,
|
||||
) {
|
||||
|
||||
var queryFilter by remember { mutableStateOf("") }
|
||||
|
||||
// May introduce more advanced filters
|
||||
val filtered = if (queryFilter.isEmpty()) contactListState
|
||||
else {
|
||||
contactListState
|
||||
.filter { contact ->
|
||||
contact.getSearchName()
|
||||
.contains(queryFilter)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
NavigationBar(
|
||||
title = stringResource(id = R.string.activity_create_closed_group_select_contacts),
|
||||
onBack = onBack,
|
||||
onClose = onClose
|
||||
)
|
||||
|
||||
LazyColumn {
|
||||
item {
|
||||
// Search Bar
|
||||
SearchBar(queryFilter, onValueChanged = { value -> queryFilter = value })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.wrapContentHeight
|
|||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material.ButtonColors
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.Colors
|
||||
|
@ -34,6 +35,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -225,6 +227,41 @@ fun EditableAvatar(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
query: String,
|
||||
onValueChanged: (String) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp)
|
||||
.background(MaterialTheme.colors.primaryVariant, RoundedCornerShape(100))
|
||||
) {
|
||||
Image(
|
||||
painterResource(id = R.drawable.ic_search_24),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
MaterialTheme.colors.onPrimary
|
||||
),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
|
||||
BasicTextField(
|
||||
singleLine = true,
|
||||
// label = { Text(text = stringResource(id = R.string.search_contacts_hint),modifier=Modifier.padding(0.dp)) },
|
||||
value = query,
|
||||
onValueChange = onValueChanged,
|
||||
modifier = Modifier
|
||||
.padding(start = 8.dp)
|
||||
.padding(4.dp)
|
||||
.weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NavigationBar(
|
||||
//
|
||||
|
@ -296,3 +333,11 @@ fun PreviewNavigationBar(@PreviewParameter(provider = ThemeResPreviewParameterPr
|
|||
NavigationBar(title = "Create Group", onBack = {}, onClose = {})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun PreviewSearchBar(@PreviewParameter(provider = ThemeResPreviewParameterProvider::class) themeResId: Int) {
|
||||
PreviewTheme(themeResId = themeResId) {
|
||||
SearchBar("", {})
|
||||
}
|
||||
}
|
|
@ -778,6 +778,7 @@
|
|||
<string name="activity_create_closed_group_group_name_missing_error">Please enter a group name</string>
|
||||
<string name="activity_create_closed_group_group_name_too_long_error">Please enter a shorter group name</string>
|
||||
<string name="activity_create_closed_group_not_enough_group_members_error">Please pick at least 1 group member</string>
|
||||
<string name="activity_create_closed_group_empty_placeholer">You haven\'t added any members</string>
|
||||
<string name="activity_create_closed_group_too_many_group_members_error">A closed group cannot have more than 100 members</string>
|
||||
<string name="activity_join_public_chat_title">Join Open Group</string>
|
||||
<string name="activity_join_public_chat_error">Couldn\'t join group</string>
|
||||
|
@ -1073,4 +1074,6 @@
|
|||
<string name="dialog_clear_all_messages_clear">Clear</string>
|
||||
<string name="dialog_clear_all_messages_cancel">Cancel</string>
|
||||
<string name="media_overview_activity__clear_media">Clear All</string>
|
||||
<string name="activity_create_closed_group_select_contacts">Select Contacts</string>
|
||||
<string name="activity_create_closed_group_add_account_or_ons">Add Account ID or ONS</string>
|
||||
</resources>
|
||||
|
|
|
@ -30,11 +30,11 @@ android {
|
|||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = '11'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ android {
|
|||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ android {
|
|||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue