MemberListFragment.kt (4764B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2021--2025 GNUnet e.V. 4 5 GNUnet is free software: you can redistribute it and/or modify it 6 under the terms of the GNU Affero General Public License as published 7 by the Free Software Foundation, either version 3 of the License, 8 or (at your option) any later version. 9 10 GNUnet is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 SPDX-License-Identifier: AGPL3.0-or-later 19 */ 20 /* 21 * @author t3sserakt 22 * @file GNUnetMessenger/app/src/main/java/org/gnunet/gnunetmessenger/ui/chat/MemberListFragment.kt 23 */ 24 25 package org.gnunet.gnunetmessenger.ui.chat 26 27 import android.os.Bundle 28 import android.util.Log 29 import android.view.View 30 import android.widget.Button 31 import android.widget.TextView 32 import androidx.fragment.app.Fragment 33 import androidx.fragment.app.activityViewModels 34 import androidx.lifecycle.Observer 35 import androidx.lifecycle.lifecycleScope 36 import androidx.navigation.fragment.findNavController 37 import androidx.navigation.fragment.navArgs 38 import androidx.recyclerview.widget.LinearLayoutManager 39 import androidx.recyclerview.widget.RecyclerView 40 import kotlinx.coroutines.launch 41 import org.gnunet.gnunetmessenger.MainActivity 42 import org.gnunet.gnunetmessenger.R 43 import org.gnunet.gnunetmessenger.model.ChatContact 44 import org.gnunet.gnunetmessenger.ui.adapters.ContactListAdapter 45 import org.gnunet.gnunetmessenger.viewmodel.ContactListViewModel 46 47 class MemberListFragment : Fragment(R.layout.fragment_member_list) { 48 49 private val args: MemberListFragmentArgs by navArgs() 50 private lateinit var adapter: ContactListAdapter 51 private val viewModel: ContactListViewModel by activityViewModels() 52 53 private var existingMemberKeys: Set<String> = emptySet() 54 private var latestContacts: List<ChatContact> = emptyList() 55 56 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 57 val chatGroup = args.chatGroup 58 Log.d("MemberListFragment", "Opened for group '${chatGroup.name}' userPointer=${chatGroup.userPointer}") 59 val mainActivity = requireActivity() as MainActivity 60 val gnunetChat = mainActivity.getGnunetChatInstance() 61 62 val recyclerView = view.findViewById<RecyclerView>(R.id.memberRecyclerView) 63 val inviteButton = view.findViewById<Button>(R.id.confirmButton) 64 val hint = view.findViewById<TextView>(R.id.memberListHint) 65 66 recyclerView.layoutManager = LinearLayoutManager(requireContext()) 67 adapter = ContactListAdapter() 68 recyclerView.adapter = adapter 69 70 fun renderList() { 71 val invitable = latestContacts.filter { 72 it.key.isBlank() || it.key !in existingMemberKeys 73 } 74 adapter.submitList(invitable) 75 hint.text = if (invitable.isEmpty()) { 76 "No contacts available to invite. Share your identity via a lobby to add contacts first." 77 } else { 78 "Select contacts to invite" 79 } 80 } 81 82 viewModel.contacts.observe(viewLifecycleOwner, Observer { contactList -> 83 latestContacts = contactList ?: emptyList() 84 renderList() 85 }) 86 87 // Refresh the contact list each time this screen opens so stale/empty 88 // view-model state doesn't leave the list blank. 89 mainActivity.loadChats() 90 91 // Load existing members asynchronously so we can filter them out. 92 viewLifecycleOwner.lifecycleScope.launch { 93 existingMemberKeys = try { 94 gnunetChat.listGroupContacts(chatGroup) 95 .mapNotNull { it.key.takeIf { k -> k.isNotBlank() } } 96 .toSet() 97 } catch (t: Throwable) { 98 Log.w("MemberListFragment", "listGroupContacts failed", t) 99 emptySet() 100 } 101 renderList() 102 } 103 104 inviteButton.setOnClickListener { 105 val selectedContacts = adapter.getSelectedContacts() 106 Log.d("MemberListFragment", "Inviting ${selectedContacts.size} contacts to group '${chatGroup.name}' (groupPtr=${chatGroup.userPointer})") 107 for (contact in selectedContacts) { 108 Log.d("MemberListFragment", " Inviting contact '${contact.name}' (contactPtr=${contact.userPointer}, key=${contact.key.take(8)})") 109 gnunetChat.inviteContactToGroup(chatGroup, contact) 110 } 111 findNavController().popBackStack() 112 } 113 } 114 }