diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt index ea5e2a137..ee39b03b7 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -190,9 +190,27 @@ class UIViewModel @Inject constructor( debug("ViewModel created") } - private val contactKey: MutableStateFlow = MutableStateFlow(DataPacket.ID_BROADCAST) + private val _contactKey = MutableStateFlow("0${DataPacket.ID_BROADCAST}") + val contactKey: StateFlow = _contactKey fun setContactKey(contact: String) { - contactKey.value = contact + _contactKey.value = contact + } + + fun getContactName(contactKey: String): String { + val (channel, dest) = contactKey[0].digitToIntOrNull() to contactKey.substring(1) + + return if (channel == null || dest == DataPacket.ID_BROADCAST) { + // grab channel names from ChannelSet + val channelName = with(channelSet) { + if (channel != null && settingsCount > channel) + Channel(settingsList[channel], loraConfig).name else null + } + channelName ?: app.getString(R.string.channel_name) + } else { + // grab usernames from NodeInfo + val node = nodeDB.nodes.value[dest] + node?.user?.longName ?: app.getString(R.string.unknown_username) + } } @OptIn(ExperimentalCoroutinesApi::class) @@ -237,7 +255,7 @@ class UIViewModel @Inject constructor( } } - fun sendMessage(str: String, contactKey: String = "0${DataPacket.ID_BROADCAST}") { + fun sendMessage(str: String, contactKey: String = this.contactKey.value) { // contactKey: unique contact key filter (channel)+(nodeId) val channel = contactKey[0].digitToIntOrNull() val dest = if (channel != null) contactKey.substring(1) else contactKey diff --git a/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt index fd16f3ce1..b3ba69892 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt @@ -7,9 +7,7 @@ import android.view.* import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf import androidx.fragment.app.activityViewModels -import androidx.fragment.app.setFragmentResult import androidx.lifecycle.asLiveData import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -122,10 +120,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging { if (actionMode != null) clickItem(holder, packet.contact_key) else { debug("calling MessagesFragment filter:${packet.contact_key}") - setFragmentResult( - "requestKey", - bundleOf("contactKey" to packet.contact_key, "contactName" to longName) - ) + model.setContactKey(packet.contact_key) parentFragmentManager.beginTransaction() .replace(R.id.mainActivityLayout, MessagesFragment()) .addToBackStack(null) diff --git a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt index 5d10862d0..f151ec670 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -13,7 +13,6 @@ import androidx.core.content.ContextCompat import androidx.core.view.allViews import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.fragment.app.setFragmentResultListener import androidx.lifecycle.asLiveData import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -43,13 +42,9 @@ class MessagesFragment : Fragment(), Logging { // This property is only valid between onCreateView and onDestroyView. private val binding get() = _binding!! - private var contactKey: String = DataPacket.ID_BROADCAST - private var contactName: String = DataPacket.ID_BROADCAST private val model: UIViewModel by activityViewModels() - private var isConnected = false - // Provide a direct reference to each of the views within a data item // Used to cache the views within the item layout for fast access class ViewHolder(itemView: AdapterMessageLayoutBinding) : @@ -240,12 +235,6 @@ class MessagesFragment : Fragment(), Logging { return binding.root } - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putString("contactKey", contactKey) - outState.putString("contactName", contactName) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -253,25 +242,12 @@ class MessagesFragment : Fragment(), Logging { parentFragmentManager.popBackStack() } - setFragmentResultListener("requestKey") { _, bundle-> - // get the result from bundle - contactKey = bundle.getString("contactKey").toString() - contactName = bundle.getString("contactName").toString() - model.setContactKey(contactKey) - binding.messageTitle.text = contactName - } - if (savedInstanceState != null) { - contactKey = savedInstanceState.getString("contactKey").toString() - contactName = savedInstanceState.getString("contactName").toString() - binding.messageTitle.text = contactName - } - binding.sendButton.setOnClickListener { debug("User clicked sendButton") val str = binding.messageInputText.text.toString().trim() if (str.isNotEmpty()) - model.sendMessage(str, contactKey) + model.sendMessage(str) binding.messageInputText.setText("") // blow away the string the user just entered // requireActivity().hideKeyboard() @@ -281,7 +257,7 @@ class MessagesFragment : Fragment(), Logging { debug("received IME_ACTION_SEND") val str = binding.messageInputText.text.toString().trim() - if (str.isNotEmpty()) model.sendMessage(str, contactKey) + if (str.isNotEmpty()) model.sendMessage(str) binding.messageInputText.setText("") // blow away the string the user just entered // requireActivity().hideKeyboard() @@ -300,7 +276,7 @@ class MessagesFragment : Fragment(), Logging { // If connection state _OR_ myID changes we have to fix our ability to edit outgoing messages model.connectionState.observe(viewLifecycleOwner) { // If we don't know our node ID and we are offline don't let user try to send - isConnected = model.isConnected() + val isConnected = model.isConnected() binding.textInputLayout.isEnabled = isConnected binding.sendButton.isEnabled = isConnected for (subView: View in binding.quickChatLayout.allViews) { @@ -310,6 +286,10 @@ class MessagesFragment : Fragment(), Logging { } } + model.contactKey.asLiveData().observe(viewLifecycleOwner) { + binding.messageTitle.text = model.getContactName(it) + } + model.quickChatActions.asLiveData().observe(viewLifecycleOwner) { actions -> actions?.let { // This seems kinda hacky it might be better to replace with a recycler view @@ -317,7 +297,7 @@ class MessagesFragment : Fragment(), Logging { for (action in actions) { val button = Button(context) button.text = action.name - button.isEnabled = isConnected + button.isEnabled = model.isConnected() if (action.mode == QuickChatAction.Mode.Instant) { button.backgroundTintList = ContextCompat.getColorStateList(requireActivity(), R.color.colorMyMsg) } @@ -333,7 +313,7 @@ class MessagesFragment : Fragment(), Logging { binding.messageInputText.setText(newText) binding.messageInputText.setSelection(newText.length) } else { - model.sendMessage(action.message, contactKey) + model.sendMessage(action.message) } } binding.quickChatLayout.addView(button) diff --git a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt index 52ea1ee7b..94a5ed948 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt @@ -15,10 +15,8 @@ import android.view.animation.LinearInterpolator import androidx.appcompat.widget.PopupMenu import androidx.core.animation.doOnEnd import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf import androidx.core.text.HtmlCompat import androidx.fragment.app.activityViewModels -import androidx.fragment.app.setFragmentResult import androidx.lifecycle.asLiveData import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager @@ -119,13 +117,7 @@ class UsersFragment : ScreenFragment("Users"), Logging { when (item.itemId) { R.id.direct_message -> { debug("calling MessagesFragment filter: ${node.channel}${user.id}") - setFragmentResult( - "requestKey", - bundleOf( - "contactKey" to "${node.channel}${user.id}", - "contactName" to user.longName - ) - ) + model.setContactKey("${node.channel}${user.id}") parentFragmentManager.beginTransaction() .replace(R.id.mainActivityLayout, MessagesFragment()) .addToBackStack(null) diff --git a/app/src/main/java/com/geeksville/mesh/ui/map/MapFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/map/MapFragment.kt index 2db00e42d..b0247f78e 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/map/MapFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/map/MapFragment.kt @@ -31,9 +31,7 @@ import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.os.bundleOf import androidx.fragment.app.activityViewModels -import androidx.fragment.app.setFragmentResult import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.geeksville.mesh.BuildConfig @@ -115,13 +113,7 @@ class MapFragment : ScreenFragment("Map Fragment"), Logging { private fun openDirectMessage(node: NodeInfo) { val user = node.user ?: return - setFragmentResult( - "requestKey", - bundleOf( - "contactKey" to "${node.channel}${user.id}", - "contactName" to user.longName - ) - ) + model.setContactKey("${node.channel}${user.id}") parentFragmentManager.beginTransaction() .replace(R.id.mainActivityLayout, MessagesFragment()) .addToBackStack(null)