mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-08 09:18:39 +01:00
Add call link details screen scaffolding.
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
package org.thoughtcrime.securesms.calls.links
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility object for call links to try to keep some common logic in one place.
|
||||||
|
*/
|
||||||
|
object CallLinks {
|
||||||
|
fun url(identifier: String) = "https://calls.signal.org/#$identifier"
|
||||||
|
}
|
||||||
+11
-9
@@ -28,18 +28,21 @@ import androidx.compose.ui.text.TextRange
|
|||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.setFragmentResult
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
import org.signal.core.ui.Buttons
|
import org.signal.core.ui.Buttons
|
||||||
import org.signal.core.ui.Scaffolds
|
import org.signal.core.ui.Scaffolds
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.calls.links.create.CreateCallLinkViewModel
|
|
||||||
import org.thoughtcrime.securesms.compose.ComposeDialogFragment
|
import org.thoughtcrime.securesms.compose.ComposeDialogFragment
|
||||||
|
|
||||||
class EditCallLinkNameDialogFragment : ComposeDialogFragment() {
|
class EditCallLinkNameDialogFragment : ComposeDialogFragment() {
|
||||||
|
|
||||||
private val viewModel: CreateCallLinkViewModel by viewModels(
|
companion object {
|
||||||
ownerProducer = { requireParentFragment() }
|
const val RESULT_KEY = "edit_call_link_name"
|
||||||
)
|
}
|
||||||
|
|
||||||
|
private val args: EditCallLinkNameDialogFragmentArgs by navArgs()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -57,12 +60,11 @@ class EditCallLinkNameDialogFragment : ComposeDialogFragment() {
|
|||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
override fun DialogContent() {
|
override fun DialogContent() {
|
||||||
val viewModelCallName by viewModel.callName
|
|
||||||
var callName by remember {
|
var callName by remember {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
TextFieldValue(
|
TextFieldValue(
|
||||||
text = viewModelCallName,
|
text = args.name,
|
||||||
selection = TextRange(viewModelCallName.length)
|
selection = TextRange(args.name.length)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -97,7 +99,7 @@ class EditCallLinkNameDialogFragment : ComposeDialogFragment() {
|
|||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Buttons.MediumTonal(
|
Buttons.MediumTonal(
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.setCallName(callName.text)
|
setFragmentResult(RESULT_KEY, bundleOf(RESULT_KEY to callName.text))
|
||||||
dismiss()
|
dismiss()
|
||||||
},
|
},
|
||||||
modifier = Modifier.align(End)
|
modifier = Modifier.align(End)
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.dimensionResource
|
import androidx.compose.ui.res.dimensionResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
@@ -29,14 +31,25 @@ import androidx.compose.ui.unit.dp
|
|||||||
import org.signal.core.ui.Buttons
|
import org.signal.core.ui.Buttons
|
||||||
import org.signal.core.ui.theme.SignalTheme
|
import org.signal.core.ui.theme.SignalTheme
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||||
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColorPair
|
||||||
|
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun SignalCallRowPreview() {
|
private fun SignalCallRowPreview() {
|
||||||
|
val avatarColor = remember { AvatarColor.random() }
|
||||||
|
val callLink = remember {
|
||||||
|
CallLinkTable.CallLink(
|
||||||
|
name = "Call Name",
|
||||||
|
identifier = "blahblahblah",
|
||||||
|
avatarColor = avatarColor,
|
||||||
|
isApprovalRequired = false
|
||||||
|
)
|
||||||
|
}
|
||||||
SignalTheme(false) {
|
SignalTheme(false) {
|
||||||
SignalCallRow(
|
SignalCallRow(
|
||||||
callName = "Call Name",
|
callLink = callLink,
|
||||||
callLink = "https://call.signal.org#blahblahblah",
|
|
||||||
onJoinClicked = {}
|
onJoinClicked = {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -44,8 +57,7 @@ private fun SignalCallRowPreview() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SignalCallRow(
|
fun SignalCallRow(
|
||||||
callName: String,
|
callLink: CallLinkTable.CallLink,
|
||||||
callLink: String,
|
|
||||||
onJoinClicked: () -> Unit,
|
onJoinClicked: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
@@ -60,15 +72,17 @@ fun SignalCallRow(
|
|||||||
)
|
)
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
) {
|
) {
|
||||||
|
val callColorPair = AvatarColorPair.create(LocalContext.current, callLink.avatarColor)
|
||||||
|
|
||||||
Image(
|
Image(
|
||||||
imageVector = ImageVector.vectorResource(id = R.drawable.symbol_video_display_bold_40),
|
imageVector = ImageVector.vectorResource(id = R.drawable.symbol_video_display_bold_40),
|
||||||
contentScale = ContentScale.Inside,
|
contentScale = ContentScale.Inside,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(Color(0xFF5151F6)),
|
colorFilter = ColorFilter.tint(Color(callColorPair.foregroundColor)),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(64.dp)
|
.size(64.dp)
|
||||||
.background(
|
.background(
|
||||||
color = Color(0xFFE5E5FE),
|
color = Color(callColorPair.backgroundColor),
|
||||||
shape = CircleShape
|
shape = CircleShape
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -81,10 +95,10 @@ fun SignalCallRow(
|
|||||||
.align(CenterVertically)
|
.align(CenterVertically)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = callName.ifEmpty { stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__signal_call) }
|
text = callLink.name.ifEmpty { stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__signal_call) }
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = callLink,
|
text = CallLinks.url(callLink.identifier),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
|
|||||||
+22
-9
@@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.calls.links.create
|
|||||||
|
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -25,15 +27,18 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.app.ShareCompat
|
import androidx.core.app.ShareCompat
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
import org.signal.core.ui.Buttons
|
import org.signal.core.ui.Buttons
|
||||||
import org.signal.core.ui.Dividers
|
import org.signal.core.ui.Dividers
|
||||||
import org.signal.core.ui.Rows
|
import org.signal.core.ui.Rows
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
|
import org.thoughtcrime.securesms.calls.links.CallLinks
|
||||||
import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment
|
import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment
|
||||||
import org.thoughtcrime.securesms.calls.links.SignalCallRow
|
import org.thoughtcrime.securesms.calls.links.SignalCallRow
|
||||||
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
|
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment
|
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
||||||
|
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||||
import org.thoughtcrime.securesms.sharing.MultiShareArgs
|
import org.thoughtcrime.securesms.sharing.MultiShareArgs
|
||||||
import org.thoughtcrime.securesms.util.Util
|
import org.thoughtcrime.securesms.util.Util
|
||||||
|
|
||||||
@@ -46,6 +51,14 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||||||
|
|
||||||
override val peekHeightPercentage: Float = 1f
|
override val peekHeightPercentage: Float = 1f
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
parentFragmentManager.setFragmentResultListener(EditCallLinkNameDialogFragment.RESULT_KEY, viewLifecycleOwner) { resultKey, bundle ->
|
||||||
|
if (bundle.containsKey(resultKey)) {
|
||||||
|
viewModel.setCallName(bundle.getString(resultKey)!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun SheetContent() {
|
override fun SheetContent() {
|
||||||
Column(
|
Column(
|
||||||
@@ -53,9 +66,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentSize(Alignment.Center)
|
.wrapContentSize(Alignment.Center)
|
||||||
) {
|
) {
|
||||||
val callName: String by viewModel.callName
|
val callLink: CallLinkTable.CallLink by viewModel.callLink
|
||||||
val callLink: String by viewModel.callLink
|
|
||||||
val approveAllMembers: Boolean by viewModel.approveAllMembers
|
|
||||||
|
|
||||||
Handle(modifier = Modifier.align(Alignment.CenterHorizontally))
|
Handle(modifier = Modifier.align(Alignment.CenterHorizontally))
|
||||||
|
|
||||||
@@ -71,7 +82,6 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||||||
Spacer(modifier = Modifier.height(24.dp))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
SignalCallRow(
|
SignalCallRow(
|
||||||
callName = callName,
|
|
||||||
callLink = callLink,
|
callLink = callLink,
|
||||||
onJoinClicked = this@CreateCallLinkBottomSheetDialogFragment::onJoinClicked
|
onJoinClicked = this@CreateCallLinkBottomSheetDialogFragment::onJoinClicked
|
||||||
)
|
)
|
||||||
@@ -84,7 +94,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||||||
)
|
)
|
||||||
|
|
||||||
Rows.ToggleRow(
|
Rows.ToggleRow(
|
||||||
checked = approveAllMembers,
|
checked = callLink.isApprovalRequired,
|
||||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__approve_all_members),
|
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__approve_all_members),
|
||||||
onCheckChanged = viewModel::setApproveAllMembers,
|
onCheckChanged = viewModel::setApproveAllMembers,
|
||||||
modifier = Modifier.clickable(onClick = viewModel::toggleApproveAllMembers)
|
modifier = Modifier.clickable(onClick = viewModel::toggleApproveAllMembers)
|
||||||
@@ -124,7 +134,10 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onAddACallNameClicked() {
|
private fun onAddACallNameClicked() {
|
||||||
EditCallLinkNameDialogFragment().show(childFragmentManager, null)
|
val snapshot = viewModel.callLink.value
|
||||||
|
findNavController().navigate(
|
||||||
|
CreateCallLinkBottomSheetDialogFragmentDirections.actionCreateCallLinkBottomSheetToEditCallLinkNameDialogFragment(snapshot.name)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onJoinClicked() {
|
private fun onJoinClicked() {
|
||||||
@@ -142,7 +155,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||||||
canSendToNonPush = false,
|
canSendToNonPush = false,
|
||||||
multiShareArgs = listOf(
|
multiShareArgs = listOf(
|
||||||
MultiShareArgs.Builder()
|
MultiShareArgs.Builder()
|
||||||
.withDraftText(snapshot)
|
.withDraftText(snapshot.identifier)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -151,7 +164,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||||||
|
|
||||||
private fun onCopyLinkClicked() {
|
private fun onCopyLinkClicked() {
|
||||||
val snapshot = viewModel.callLink.value
|
val snapshot = viewModel.callLink.value
|
||||||
Util.copyToClipboard(requireContext(), snapshot)
|
Util.copyToClipboard(requireContext(), CallLinks.url(snapshot.identifier))
|
||||||
Toast.makeText(requireContext(), R.string.CreateCallLinkBottomSheetDialogFragment__copied_to_clipboard, Toast.LENGTH_LONG).show()
|
Toast.makeText(requireContext(), R.string.CreateCallLinkBottomSheetDialogFragment__copied_to_clipboard, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +172,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||||||
val snapshot = viewModel.callLink.value
|
val snapshot = viewModel.callLink.value
|
||||||
val mimeType = Intent.normalizeMimeType("text/plain")
|
val mimeType = Intent.normalizeMimeType("text/plain")
|
||||||
val shareIntent = ShareCompat.IntentBuilder(requireContext())
|
val shareIntent = ShareCompat.IntentBuilder(requireContext())
|
||||||
.setText(snapshot)
|
.setText(CallLinks.url(snapshot.identifier))
|
||||||
.setType(mimeType)
|
.setType(mimeType)
|
||||||
.createChooserIntent()
|
.createChooserIntent()
|
||||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
|||||||
+9
-14
@@ -4,29 +4,24 @@ import androidx.compose.runtime.MutableState
|
|||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||||
|
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||||
|
|
||||||
class CreateCallLinkViewModel : ViewModel() {
|
class CreateCallLinkViewModel : ViewModel() {
|
||||||
private val _callName: MutableState<String> = mutableStateOf("")
|
private val _callLink: MutableState<CallLinkTable.CallLink> = mutableStateOf(
|
||||||
private val _callLink: MutableState<String> = mutableStateOf("")
|
CallLinkTable.CallLink("", "", AvatarColor.random(), false)
|
||||||
private val _approveAllMembers: MutableState<Boolean> = mutableStateOf(false)
|
)
|
||||||
|
val callLink: State<CallLinkTable.CallLink> = _callLink
|
||||||
val callName: State<String> = _callName
|
|
||||||
val callLink: State<String> = _callLink
|
|
||||||
val approveAllMembers: State<Boolean> = _approveAllMembers
|
|
||||||
|
|
||||||
fun setApproveAllMembers(approveAllMembers: Boolean) {
|
fun setApproveAllMembers(approveAllMembers: Boolean) {
|
||||||
_approveAllMembers.value = approveAllMembers
|
_callLink.value = _callLink.value.copy(isApprovalRequired = approveAllMembers)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleApproveAllMembers() {
|
fun toggleApproveAllMembers() {
|
||||||
_approveAllMembers.value = !_approveAllMembers.value
|
_callLink.value = _callLink.value.copy(isApprovalRequired = _callLink.value.isApprovalRequired)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setCallName(callName: String) {
|
fun setCallName(callName: String) {
|
||||||
_callName.value = callName
|
_callLink.value = _callLink.value.copy(name = callName)
|
||||||
}
|
|
||||||
|
|
||||||
fun setCallLink(callLink: String) {
|
|
||||||
_callLink.value = callLink
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package org.thoughtcrime.securesms.calls.links.details
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import org.thoughtcrime.securesms.R
|
||||||
|
import org.thoughtcrime.securesms.components.FragmentWrapperActivity
|
||||||
|
|
||||||
|
class CallLinkDetailsActivity : FragmentWrapperActivity() {
|
||||||
|
override fun getFragment(): Fragment = NavHostFragment.create(R.navigation.call_link_details)
|
||||||
|
}
|
||||||
+179
@@ -0,0 +1,179 @@
|
|||||||
|
package org.thoughtcrime.securesms.calls.links.details
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.fragment.app.setFragmentResultListener
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import org.signal.core.ui.Dividers
|
||||||
|
import org.signal.core.ui.Rows
|
||||||
|
import org.signal.core.ui.Scaffolds
|
||||||
|
import org.signal.core.ui.theme.SignalTheme
|
||||||
|
import org.thoughtcrime.securesms.R
|
||||||
|
import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment
|
||||||
|
import org.thoughtcrime.securesms.calls.links.SignalCallRow
|
||||||
|
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||||
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||||
|
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides detailed info about a call link and allows the owner of that link
|
||||||
|
* to modify call properties.
|
||||||
|
*/
|
||||||
|
class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback {
|
||||||
|
|
||||||
|
private val viewModel: CallLinkViewModel by viewModels()
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
parentFragmentManager.setFragmentResultListener(EditCallLinkNameDialogFragment.RESULT_KEY, viewLifecycleOwner) { resultKey, bundle ->
|
||||||
|
if (bundle.containsKey(resultKey)) {
|
||||||
|
viewModel.setName(bundle.getString(resultKey)!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun FragmentContent() {
|
||||||
|
val isLoading by viewModel.isLoading
|
||||||
|
val callLink by viewModel.callLink
|
||||||
|
|
||||||
|
CallLinkDetails(
|
||||||
|
isLoading,
|
||||||
|
callLink,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNavigationClicked() {
|
||||||
|
findNavController().popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onJoinClicked() {
|
||||||
|
// TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEditNameClicked() {
|
||||||
|
val name = viewModel.callLink.value.name
|
||||||
|
findNavController().navigate(
|
||||||
|
CallLinkDetailsFragmentDirections.actionCallLinkDetailsFragmentToEditCallLinkNameDialogFragment(name)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onShareClicked() {
|
||||||
|
// TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeleteClicked() {
|
||||||
|
// TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onApproveAllMembersChanged(checked: Boolean) {
|
||||||
|
// TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface CallLinkDetailsCallback {
|
||||||
|
fun onNavigationClicked()
|
||||||
|
fun onJoinClicked()
|
||||||
|
fun onEditNameClicked()
|
||||||
|
fun onShareClicked()
|
||||||
|
fun onDeleteClicked()
|
||||||
|
fun onApproveAllMembersChanged(checked: Boolean)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun CallLinkDetailsPreview() {
|
||||||
|
val avatarColor = remember {
|
||||||
|
AvatarColor.random()
|
||||||
|
}
|
||||||
|
|
||||||
|
val callLink = remember {
|
||||||
|
CallLinkTable.CallLink(
|
||||||
|
name = "Call Name",
|
||||||
|
identifier = "call-id-1",
|
||||||
|
isApprovalRequired = false,
|
||||||
|
avatarColor = avatarColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalTheme(false) {
|
||||||
|
CallLinkDetails(
|
||||||
|
false,
|
||||||
|
callLink,
|
||||||
|
object : CallLinkDetailsCallback {
|
||||||
|
override fun onNavigationClicked() = Unit
|
||||||
|
override fun onJoinClicked() = Unit
|
||||||
|
override fun onEditNameClicked() = Unit
|
||||||
|
override fun onShareClicked() = Unit
|
||||||
|
override fun onDeleteClicked() = Unit
|
||||||
|
override fun onApproveAllMembersChanged(checked: Boolean) = Unit
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun CallLinkDetails(
|
||||||
|
isLoading: Boolean,
|
||||||
|
callLink: CallLinkTable.CallLink,
|
||||||
|
callback: CallLinkDetailsCallback
|
||||||
|
) {
|
||||||
|
Scaffolds.Settings(
|
||||||
|
title = stringResource(id = R.string.CallLinkDetailsFragment__call_details),
|
||||||
|
onNavigationClick = callback::onNavigationClicked,
|
||||||
|
navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24)
|
||||||
|
) { paddingValues ->
|
||||||
|
if (isLoading) {
|
||||||
|
return@Settings
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(modifier = Modifier.padding(paddingValues)) {
|
||||||
|
SignalCallRow(
|
||||||
|
callLink = callLink,
|
||||||
|
onJoinClicked = callback::onJoinClicked,
|
||||||
|
modifier = Modifier.padding(top = 16.dp, bottom = 12.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Rows.TextRow(
|
||||||
|
text = stringResource(id = R.string.CallLinkDetailsFragment__add_call_name),
|
||||||
|
modifier = Modifier.clickable(onClick = callback::onEditNameClicked)
|
||||||
|
)
|
||||||
|
|
||||||
|
Rows.ToggleRow(
|
||||||
|
checked = callLink.isApprovalRequired,
|
||||||
|
text = stringResource(id = R.string.CallLinkDetailsFragment__approve_all_members),
|
||||||
|
onCheckChanged = callback::onApproveAllMembersChanged
|
||||||
|
)
|
||||||
|
|
||||||
|
Dividers.Default()
|
||||||
|
|
||||||
|
Rows.TextRow(
|
||||||
|
text = stringResource(id = R.string.CallLinkDetailsFragment__share_link),
|
||||||
|
icon = ImageVector.vectorResource(id = R.drawable.symbol_link_24),
|
||||||
|
modifier = Modifier.clickable(onClick = callback::onShareClicked)
|
||||||
|
)
|
||||||
|
|
||||||
|
Rows.TextRow(
|
||||||
|
text = stringResource(id = R.string.CallLinkDetailsFragment__delete_call_link),
|
||||||
|
icon = ImageVector.vectorResource(id = R.drawable.symbol_trash_24),
|
||||||
|
foregroundTint = MaterialTheme.colorScheme.error,
|
||||||
|
modifier = Modifier.clickable(onClick = callback::onDeleteClicked)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.thoughtcrime.securesms.calls.links.details
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||||
|
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||||
|
|
||||||
|
class CallLinkViewModel : ViewModel() {
|
||||||
|
private val isLoadingState: MutableState<Boolean> = mutableStateOf(true)
|
||||||
|
val isLoading: State<Boolean> = isLoadingState
|
||||||
|
|
||||||
|
private val callLinkState: MutableState<CallLinkTable.CallLink> = mutableStateOf(
|
||||||
|
CallLinkTable.CallLink("", "", AvatarColor.A120, false)
|
||||||
|
)
|
||||||
|
val callLink: State<CallLinkTable.CallLink> = callLinkState
|
||||||
|
|
||||||
|
fun setName(name: String) {
|
||||||
|
callLinkState.value = callLinkState.value.copy(name = name)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,4 +29,22 @@ class AvatarColorPair private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as AvatarColorPair
|
||||||
|
|
||||||
|
if (foregroundColor != other.foregroundColor) return false
|
||||||
|
if (backgroundColor != other.backgroundColor) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = foregroundColor
|
||||||
|
result = 31 * result + backgroundColor
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.database
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table containing ad-hoc call link details
|
* Table containing ad-hoc call link details
|
||||||
@@ -21,4 +22,11 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
|
|||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class CallLink(
|
||||||
|
val name: String,
|
||||||
|
val identifier: String,
|
||||||
|
val avatarColor: AvatarColor,
|
||||||
|
val isApprovalRequired: Boolean
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/call_link_details"
|
||||||
|
app:startDestination="@id/callLinkDetailsFragment">
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/callLinkDetailsFragment"
|
||||||
|
android:name="org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsFragment"
|
||||||
|
android:label="call_link_details">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_callLinkDetailsFragment_to_editCallLinkNameDialogFragment"
|
||||||
|
app:destination="@id/editCallLinkNameDialogFragment" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<dialog
|
||||||
|
android:id="@+id/editCallLinkNameDialogFragment"
|
||||||
|
android:name="org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment"
|
||||||
|
android:label="edit_call_link_name_dialog">
|
||||||
|
<argument
|
||||||
|
android:name="name"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false" />
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
</navigation>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/storiesLandingFragment"
|
android:id="@+id/storiesLandingFragment"
|
||||||
android:name="org.thoughtcrime.securesms.stories.landing.StoriesLandingFragment"
|
android:name="org.thoughtcrime.securesms.stories.landing.StoriesLandingFragment"
|
||||||
android:label="stories_landing_fragment" >
|
android:label="stories_landing_fragment">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_storiesLandingFragment_to_callLogFragment"
|
android:id="@+id/action_storiesLandingFragment_to_callLogFragment"
|
||||||
app:destination="@id/callLogFragment" />
|
app:destination="@id/callLogFragment" />
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/callLogFragment"
|
android:id="@+id/callLogFragment"
|
||||||
android:name="org.thoughtcrime.securesms.calls.log.CallLogFragment"
|
android:name="org.thoughtcrime.securesms.calls.log.CallLogFragment"
|
||||||
android:label="call_log_fragment" >
|
android:label="call_log_fragment">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_callLogFragment_to_storiesLandingFragment"
|
android:id="@+id/action_callLogFragment_to_storiesLandingFragment"
|
||||||
app:destination="@id/storiesLandingFragment" />
|
app:destination="@id/storiesLandingFragment" />
|
||||||
@@ -52,6 +52,21 @@
|
|||||||
<dialog
|
<dialog
|
||||||
android:id="@+id/createCallLinkBottomSheet"
|
android:id="@+id/createCallLinkBottomSheet"
|
||||||
android:name="org.thoughtcrime.securesms.calls.links.create.CreateCallLinkBottomSheetDialogFragment"
|
android:name="org.thoughtcrime.securesms.calls.links.create.CreateCallLinkBottomSheetDialogFragment"
|
||||||
android:label="create_call_link_bottom_sheet" />
|
android:label="create_call_link_bottom_sheet">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_createCallLinkBottomSheet_to_editCallLinkNameDialogFragment"
|
||||||
|
app:destination="@id/editCallLinkNameDialogFragment" />
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog
|
||||||
|
android:id="@+id/editCallLinkNameDialogFragment"
|
||||||
|
android:name="org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment"
|
||||||
|
android:label="edit_call_link_name_fragment">
|
||||||
|
<argument
|
||||||
|
android:name="name"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false" />
|
||||||
|
|
||||||
|
</dialog>
|
||||||
|
|
||||||
</navigation>
|
</navigation>
|
||||||
@@ -5960,5 +5960,17 @@
|
|||||||
<!-- Title shown at top of bottom sheet dialog for displaying a message\'s edit history -->
|
<!-- Title shown at top of bottom sheet dialog for displaying a message\'s edit history -->
|
||||||
<string name="EditMessageHistoryDialog_title">Edit history</string>
|
<string name="EditMessageHistoryDialog_title">Edit history</string>
|
||||||
|
|
||||||
|
<!-- CallLinkDetailsFragment -->
|
||||||
|
<!-- Displayed in action bar at the top of the fragment -->
|
||||||
|
<string name="CallLinkDetailsFragment__call_details">Call details</string>
|
||||||
|
<!-- Displayed in a text row, allowing the user to click and add a call name -->
|
||||||
|
<string name="CallLinkDetailsFragment__add_call_name">Add call name</string>
|
||||||
|
<!-- Displayed in a toggle row, allowing the user to click to enable or disable member approval -->
|
||||||
|
<string name="CallLinkDetailsFragment__approve_all_members">Approve all members</string>
|
||||||
|
<!-- Displayed in a text row, allowing the user to share the call link -->
|
||||||
|
<string name="CallLinkDetailsFragment__share_link">Share link</string>
|
||||||
|
<!-- Displayed in a text row, allowing the user to delete the call link -->
|
||||||
|
<string name="CallLinkDetailsFragment__delete_call_link">Delete call link</string>
|
||||||
|
|
||||||
<!-- EOF -->
|
<!-- EOF -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.dimensionResource
|
import androidx.compose.ui.res.dimensionResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
@@ -102,7 +103,8 @@ object Rows {
|
|||||||
fun TextRow(
|
fun TextRow(
|
||||||
text: String,
|
text: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
icon: ImageVector? = null
|
icon: ImageVector? = null,
|
||||||
|
foregroundTint: Color = MaterialTheme.colorScheme.onSurface
|
||||||
) {
|
) {
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
Row(
|
Row(
|
||||||
@@ -113,14 +115,15 @@ object Rows {
|
|||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = MaterialTheme.colorScheme.onSurface
|
tint = foregroundTint
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(24.dp))
|
Spacer(modifier = Modifier.width(24.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f),
|
||||||
|
color = foregroundTint
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user