2022-08-09 15:26:52 +01:00
|
|
|
package com.geeksville.mesh.ui
|
|
|
|
|
|
2022-08-11 16:43:26 +01:00
|
|
|
import android.content.Context
|
2022-08-09 15:26:52 +01:00
|
|
|
import android.os.Bundle
|
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
|
import android.view.View
|
|
|
|
|
import android.view.ViewGroup
|
2022-08-11 16:43:26 +01:00
|
|
|
import android.widget.EditText
|
2022-08-16 12:25:10 +01:00
|
|
|
import android.widget.ImageView
|
2024-07-04 09:23:24 -03:00
|
|
|
import androidx.annotation.StringRes
|
|
|
|
|
import androidx.compose.animation.core.animateDpAsState
|
|
|
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
|
|
|
import androidx.compose.foundation.layout.Column
|
|
|
|
|
import androidx.compose.foundation.layout.Row
|
|
|
|
|
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.rememberLazyListState
|
|
|
|
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
|
|
import androidx.compose.material.Card
|
|
|
|
|
import androidx.compose.material.Icon
|
|
|
|
|
import androidx.compose.material.IconButton
|
|
|
|
|
import androidx.compose.material.LocalContentColor
|
|
|
|
|
import androidx.compose.material.Surface
|
|
|
|
|
import androidx.compose.material.Text
|
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
|
import androidx.compose.runtime.getValue
|
|
|
|
|
import androidx.compose.ui.Alignment
|
|
|
|
|
import androidx.compose.ui.Modifier
|
|
|
|
|
import androidx.compose.ui.graphics.Color
|
|
|
|
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
|
|
|
|
import androidx.compose.ui.res.painterResource
|
|
|
|
|
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
|
|
|
|
import androidx.compose.ui.unit.Dp
|
|
|
|
|
import androidx.compose.ui.unit.dp
|
|
|
|
|
import androidx.compose.ui.unit.sp
|
2022-08-11 16:43:26 +01:00
|
|
|
import androidx.core.widget.addTextChangedListener
|
2022-08-09 15:26:52 +01:00
|
|
|
import androidx.fragment.app.activityViewModels
|
2024-07-04 09:23:24 -03:00
|
|
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
2022-09-04 22:52:40 -03:00
|
|
|
import com.geeksville.mesh.android.Logging
|
2022-08-11 16:43:26 +01:00
|
|
|
import com.geeksville.mesh.R
|
|
|
|
|
import com.geeksville.mesh.database.entity.QuickChatAction
|
2022-08-16 11:46:57 +01:00
|
|
|
import com.geeksville.mesh.databinding.QuickChatSettingsFragmentBinding
|
2022-08-09 15:26:52 +01:00
|
|
|
import com.geeksville.mesh.model.UIViewModel
|
2024-07-04 09:23:24 -03:00
|
|
|
import com.geeksville.mesh.ui.components.dragContainer
|
|
|
|
|
import com.geeksville.mesh.ui.components.dragDropItemsIndexed
|
|
|
|
|
import com.geeksville.mesh.ui.components.rememberDragDropState
|
|
|
|
|
import com.geeksville.mesh.ui.theme.AppTheme
|
2022-08-11 16:43:26 +01:00
|
|
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
|
|
|
import com.google.android.material.switchmaterial.SwitchMaterial
|
2022-08-09 15:26:52 +01:00
|
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
|
|
|
|
|
|
|
|
@AndroidEntryPoint
|
2022-12-28 17:37:25 -03:00
|
|
|
class QuickChatSettingsFragment : ScreenFragment("Quick Chat Settings"), Logging {
|
2022-08-09 15:26:52 +01:00
|
|
|
private var _binding: QuickChatSettingsFragmentBinding? = null
|
|
|
|
|
|
|
|
|
|
private val binding get() = _binding!!
|
|
|
|
|
|
|
|
|
|
private val model: UIViewModel by activityViewModels()
|
|
|
|
|
|
|
|
|
|
override fun onCreateView(
|
|
|
|
|
inflater: LayoutInflater, container: ViewGroup?,
|
|
|
|
|
savedInstanceState: Bundle?
|
|
|
|
|
): View {
|
|
|
|
|
_binding = QuickChatSettingsFragmentBinding.inflate(inflater, container, false)
|
|
|
|
|
return binding.root
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
|
|
|
super.onViewCreated(view, savedInstanceState)
|
|
|
|
|
|
2024-07-04 09:23:24 -03:00
|
|
|
binding.quickChatSettingsToolbar.setNavigationOnClickListener {
|
|
|
|
|
parentFragmentManager.popBackStack()
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-10 17:34:18 +01:00
|
|
|
binding.quickChatSettingsCreateButton.setOnClickListener {
|
2024-07-04 09:23:24 -03:00
|
|
|
val builder = createEditDialog(requireContext(), R.string.quick_chat_new)
|
2022-08-10 17:34:18 +01:00
|
|
|
|
2022-12-28 17:37:25 -03:00
|
|
|
builder.builder.setPositiveButton(R.string.add) { _, _ ->
|
2022-08-10 17:34:18 +01:00
|
|
|
|
|
|
|
|
val name = builder.nameInput.text.toString().trim()
|
|
|
|
|
val message = builder.messageInput.text.toString()
|
2022-08-11 16:43:26 +01:00
|
|
|
if (builder.isNotEmpty())
|
2022-08-10 17:34:18 +01:00
|
|
|
model.addQuickChatAction(
|
|
|
|
|
name, message,
|
|
|
|
|
if (builder.modeSwitch.isChecked) QuickChatAction.Mode.Instant else QuickChatAction.Mode.Append
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val dialog = builder.builder.create()
|
|
|
|
|
dialog.show()
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-04 09:23:24 -03:00
|
|
|
binding.quickChatSettingsView.setContent {
|
|
|
|
|
val actions by model.quickChatActions.collectAsStateWithLifecycle()
|
|
|
|
|
|
|
|
|
|
val listState = rememberLazyListState()
|
|
|
|
|
val dragDropState = rememberDragDropState(listState) { fromIndex, toIndex ->
|
|
|
|
|
val list = actions.toMutableList().apply { add(toIndex, removeAt(fromIndex)) }
|
|
|
|
|
model.updateActionPositions(list)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AppTheme {
|
|
|
|
|
LazyColumn(
|
|
|
|
|
modifier = Modifier.dragContainer(
|
|
|
|
|
dragDropState = dragDropState,
|
|
|
|
|
haptics = LocalHapticFeedback.current,
|
|
|
|
|
),
|
|
|
|
|
state = listState,
|
|
|
|
|
// contentPadding = PaddingValues(16.dp),
|
|
|
|
|
) {
|
|
|
|
|
dragDropItemsIndexed(
|
|
|
|
|
items = actions,
|
|
|
|
|
dragDropState = dragDropState,
|
|
|
|
|
key = { _, item -> item.uuid },
|
|
|
|
|
) { _, action, isDragging ->
|
|
|
|
|
val elevation by animateDpAsState(if (isDragging) 8.dp else 4.dp)
|
|
|
|
|
QuickChatItem(
|
|
|
|
|
elevation = elevation,
|
|
|
|
|
action = action,
|
|
|
|
|
onEditClick = ::onEditAction,
|
2022-08-11 16:43:26 +01:00
|
|
|
)
|
|
|
|
|
}
|
2022-08-10 17:34:18 +01:00
|
|
|
}
|
2022-08-16 11:46:57 +01:00
|
|
|
}
|
2022-08-11 16:43:26 +01:00
|
|
|
}
|
2022-08-10 17:34:18 +01:00
|
|
|
}
|
|
|
|
|
|
2023-04-03 18:03:55 -03:00
|
|
|
override fun onDestroyView() {
|
|
|
|
|
super.onDestroyView()
|
|
|
|
|
_binding = null
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-10 17:34:18 +01:00
|
|
|
data class DialogBuilder(
|
|
|
|
|
val builder: MaterialAlertDialogBuilder,
|
|
|
|
|
val nameInput: EditText,
|
|
|
|
|
val messageInput: EditText,
|
2022-08-16 12:25:10 +01:00
|
|
|
val modeSwitch: SwitchMaterial,
|
|
|
|
|
val instantImage: ImageView
|
2022-08-11 16:43:26 +01:00
|
|
|
) {
|
|
|
|
|
fun isNotEmpty(): Boolean = nameInput.text.isNotEmpty() and messageInput.text.isNotEmpty()
|
|
|
|
|
}
|
2022-08-10 17:34:18 +01:00
|
|
|
|
|
|
|
|
private fun getMessageName(message: String): String {
|
|
|
|
|
return if (message.length <= 3) {
|
|
|
|
|
message.uppercase()
|
|
|
|
|
} else {
|
|
|
|
|
buildString {
|
|
|
|
|
append(message.first().uppercase())
|
|
|
|
|
append(message[message.length / 2].uppercase())
|
|
|
|
|
append(message.last().uppercase())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-04 09:23:24 -03:00
|
|
|
private fun createEditDialog(context: Context, @StringRes title: Int): DialogBuilder {
|
2022-08-10 17:34:18 +01:00
|
|
|
val builder = MaterialAlertDialogBuilder(context)
|
|
|
|
|
builder.setTitle(title)
|
|
|
|
|
|
2023-05-08 17:34:06 -03:00
|
|
|
val layout = LayoutInflater.from(context).inflate(R.layout.dialog_add_quick_chat, null)
|
2022-08-10 17:34:18 +01:00
|
|
|
|
|
|
|
|
val nameInput: EditText = layout.findViewById(R.id.addQuickChatName)
|
|
|
|
|
val messageInput: EditText = layout.findViewById(R.id.addQuickChatMessage)
|
|
|
|
|
val modeSwitch: SwitchMaterial = layout.findViewById(R.id.addQuickChatMode)
|
2022-08-16 12:25:10 +01:00
|
|
|
val instantImage: ImageView = layout.findViewById(R.id.addQuickChatInsant)
|
|
|
|
|
instantImage.visibility = if (modeSwitch.isChecked) View.VISIBLE else View.INVISIBLE
|
2022-08-10 17:34:18 +01:00
|
|
|
|
2023-05-08 17:34:06 -03:00
|
|
|
// don't change action name on edits
|
2024-07-04 09:23:24 -03:00
|
|
|
var nameHasChanged = title == R.string.quick_chat_edit
|
2022-08-10 17:34:18 +01:00
|
|
|
|
|
|
|
|
modeSwitch.setOnCheckedChangeListener { _, _ ->
|
2022-08-16 12:25:10 +01:00
|
|
|
if (modeSwitch.isChecked) {
|
2022-12-28 17:37:25 -03:00
|
|
|
modeSwitch.setText(R.string.quick_chat_instant)
|
2022-08-16 12:25:10 +01:00
|
|
|
instantImage.visibility = View.VISIBLE
|
|
|
|
|
} else {
|
2022-12-28 17:37:25 -03:00
|
|
|
modeSwitch.setText(R.string.quick_chat_append)
|
2022-08-16 12:25:10 +01:00
|
|
|
instantImage.visibility = View.INVISIBLE
|
|
|
|
|
}
|
2022-08-10 17:34:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
messageInput.addTextChangedListener { text ->
|
|
|
|
|
if (!nameHasChanged) {
|
|
|
|
|
nameInput.setText(getMessageName(text.toString()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nameInput.addTextChangedListener {
|
|
|
|
|
if (nameInput.isFocused) nameHasChanged = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
builder.setView(layout)
|
|
|
|
|
|
2022-08-16 12:25:10 +01:00
|
|
|
return DialogBuilder(builder, nameInput, messageInput, modeSwitch, instantImage)
|
2022-08-09 15:26:52 +01:00
|
|
|
}
|
2024-07-04 09:23:24 -03:00
|
|
|
|
|
|
|
|
private fun onEditAction(action: QuickChatAction) {
|
|
|
|
|
val builder = createEditDialog(requireContext(), R.string.quick_chat_edit)
|
|
|
|
|
builder.nameInput.setText(action.name)
|
|
|
|
|
builder.messageInput.setText(action.message)
|
|
|
|
|
val isInstant = action.mode == QuickChatAction.Mode.Instant
|
|
|
|
|
builder.modeSwitch.isChecked = isInstant
|
|
|
|
|
builder.instantImage.visibility = if (isInstant) View.VISIBLE else View.INVISIBLE
|
|
|
|
|
|
|
|
|
|
builder.builder.setNegativeButton(R.string.delete) { _, _ ->
|
|
|
|
|
model.deleteQuickChatAction(action)
|
|
|
|
|
}
|
|
|
|
|
builder.builder.setPositiveButton(R.string.save) { _, _ ->
|
|
|
|
|
if (builder.isNotEmpty()) {
|
|
|
|
|
model.updateQuickChatAction(
|
|
|
|
|
action,
|
|
|
|
|
builder.nameInput.text.toString(),
|
|
|
|
|
builder.messageInput.text.toString(),
|
|
|
|
|
if (builder.modeSwitch.isChecked) {
|
|
|
|
|
QuickChatAction.Mode.Instant
|
|
|
|
|
} else {
|
|
|
|
|
QuickChatAction.Mode.Append
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
val dialog = builder.builder.create()
|
|
|
|
|
dialog.show()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
|
internal fun QuickChatItem(
|
|
|
|
|
action: QuickChatAction,
|
|
|
|
|
modifier: Modifier = Modifier,
|
|
|
|
|
onEditClick: (QuickChatAction) -> Unit = {},
|
|
|
|
|
elevation: Dp = 4.dp,
|
|
|
|
|
) {
|
|
|
|
|
Card(
|
|
|
|
|
modifier = modifier
|
|
|
|
|
.fillMaxWidth()
|
|
|
|
|
.padding(8.dp),
|
|
|
|
|
elevation = elevation,
|
|
|
|
|
shape = RoundedCornerShape(12.dp),
|
|
|
|
|
) {
|
|
|
|
|
Surface {
|
|
|
|
|
Row(
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
.fillMaxWidth()
|
|
|
|
|
.padding(8.dp),
|
|
|
|
|
verticalAlignment = Alignment.CenterVertically,
|
|
|
|
|
horizontalArrangement = Arrangement.SpaceBetween
|
|
|
|
|
) {
|
|
|
|
|
val showInstantIcon = action.mode == QuickChatAction.Mode.Instant
|
|
|
|
|
Icon(
|
|
|
|
|
painter = painterResource(id = R.drawable.ic_baseline_fast_forward_24),
|
|
|
|
|
contentDescription = null,
|
|
|
|
|
modifier = Modifier.padding(start = 8.dp),
|
|
|
|
|
tint = if (showInstantIcon) LocalContentColor.current else Color.Transparent,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
Column(
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
.weight(1f)
|
|
|
|
|
.padding(start = 8.dp)
|
|
|
|
|
) {
|
|
|
|
|
Text(
|
|
|
|
|
text = action.name,
|
|
|
|
|
fontSize = 20.sp,
|
|
|
|
|
modifier = Modifier.padding(top = 8.dp)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
Text(
|
|
|
|
|
text = action.message,
|
|
|
|
|
modifier = Modifier.padding(vertical = 8.dp)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IconButton(
|
|
|
|
|
onClick = { onEditClick(action) },
|
|
|
|
|
modifier = Modifier.size(48.dp)
|
|
|
|
|
) {
|
|
|
|
|
Icon(
|
|
|
|
|
painter = painterResource(id = R.drawable.ic_baseline_edit_24),
|
|
|
|
|
contentDescription = null
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Icon(
|
|
|
|
|
painter = painterResource(id = R.drawable.ic_baseline_drag_handle_24),
|
|
|
|
|
contentDescription = null,
|
|
|
|
|
modifier = Modifier.padding(end = 8.dp),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PreviewLightDark
|
|
|
|
|
@Composable
|
|
|
|
|
private fun QuickChatItemPreview() {
|
|
|
|
|
AppTheme {
|
|
|
|
|
QuickChatItem(
|
|
|
|
|
action = QuickChatAction(
|
|
|
|
|
uuid = 0L,
|
|
|
|
|
name = "TST",
|
|
|
|
|
message = "Test",
|
|
|
|
|
mode = QuickChatAction.Mode.Instant,
|
|
|
|
|
position = 0,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|