feat: add contacts 1

This commit is contained in:
2026-06-13 14:00:59 +02:00
parent c3490808c0
commit f931405c90
19 changed files with 2090 additions and 123 deletions
@@ -57,6 +57,8 @@ import cafe.adriel.lyricist.Lyricist
import com.bitcointxoko.gudariwallet.MainActivity
import com.bitcointxoko.gudariwallet.i18n.AppStrings
import com.bitcointxoko.gudariwallet.LocalAppStrings
import com.bitcointxoko.gudariwallet.ui.contacts.ContactsScreen
import com.bitcointxoko.gudariwallet.ui.contacts.ContactsViewModel
import com.bitcointxoko.gudariwallet.ui.history.HistoryScreen
import com.bitcointxoko.gudariwallet.ui.history.HistoryViewModel
import com.bitcointxoko.gudariwallet.ui.history.HistoryViewModelFactory
@@ -70,6 +72,9 @@ import com.bitcointxoko.gudariwallet.ui.receive.ReceiveScreen
import com.bitcointxoko.gudariwallet.ui.send.SendScreen
import com.bitcointxoko.gudariwallet.ui.send.SendStrings
import com.bitcointxoko.gudariwallet.util.SendInputType
import com.bitcointxoko.gudariwallet.data.ContactRepository
import com.bitcointxoko.gudariwallet.ui.contacts.ContactDetailScreen
import com.bitcointxoko.gudariwallet.ui.contacts.ContactDetailViewModel
import kotlinx.coroutines.delay
import kotlin.time.Duration.Companion.milliseconds
@@ -88,6 +93,9 @@ private const val ROUTE_HISTORY = "history"
private const val ROUTE_PAYMENT_DETAIL = "payment_detail/{checkingId}"
private const val ROUTE_NWC = "nwc"
private const val ROUTE_CONNECTION_DETAIL = "connection_detail/{pubkey}"
private const val ROUTE_CONTACTS = "contacts"
private const val ROUTE_CONTACT_DETAIL = "contacts/{contactId}"
@Composable
fun WalletScreen(
@@ -122,6 +130,7 @@ fun WalletScreen(
repo = vm.repo,
aliasRepo = vm.aliasRepo,
paymentCache = vm.paymentCache,
contactRepo = vm.contactRepo,
fiatCurrency = vm.selectedCurrency,
fiatSatsPerUnit = vm.fiatSatsPerUnit
)
@@ -130,6 +139,9 @@ fun WalletScreen(
val nwcVm: NwcViewModel = viewModel(
factory = NwcViewModel.Factory(repo = vm.repo, cache = vm.nwcCache) // same pattern as historyVm
)
val contactsVm: ContactsViewModel = viewModel(
factory = ContactsViewModel.Factory(vm.contactRepo)
)
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
@@ -139,12 +151,16 @@ fun WalletScreen(
&& currentRoute != ROUTE_HISTORY
&& currentRoute != ROUTE_NWC
&& currentRoute != ROUTE_CONNECTION_DETAIL
&& currentRoute != ROUTE_CONTACTS
&& currentRoute != ROUTE_CONTACT_DETAIL
val isFullScreenDestination = currentRoute == ROUTE_HISTORY
|| currentRoute == ROUTE_PAYMENT_DETAIL
|| currentRoute == ROUTE_SCANNER
|| currentRoute == ROUTE_NWC
|| currentRoute == ROUTE_CONNECTION_DETAIL
|| currentRoute == ROUTE_CONTACTS
|| currentRoute == ROUTE_CONTACT_DETAIL
// ── Notification tap ──────────────────────────────────────────────────────
val hash = pendingPaymentHash.value
@@ -341,6 +357,9 @@ fun WalletScreen(
launchSingleTop = true
}
},
onContactsClick = {
navController.navigate(ROUTE_CONTACTS) { launchSingleTop = true }
},
lyricist = lyricist
)
}
@@ -498,6 +517,39 @@ fun WalletScreen(
}
}
}
composable(
ROUTE_CONTACTS,
enterTransition = { fadeIn(animationSpec = tween(150)) },
popExitTransition = { fadeOut(animationSpec = tween(150)) }
) {
ContactsScreen(
viewModel = contactsVm,
onContactClick = { contactId ->
navController.navigate("contacts/$contactId") {
launchSingleTop = true
}
},
onBack = {
navController.popBackStack(ROUTE_HOME, inclusive = false)
}
)
}
composable(
route = ROUTE_CONTACT_DETAIL,
arguments = listOf(navArgument("contactId") { type = NavType.StringType }),
enterTransition = { fadeIn(animationSpec = tween(150)) },
popExitTransition = { fadeOut(animationSpec = tween(150)) }
) { backStackEntry ->
val contactId = backStackEntry.arguments?.getString("contactId") ?: ""
val detailVm: ContactDetailViewModel = viewModel(
key = contactId,
factory = ContactDetailViewModel.Factory(contactId, vm.contactRepo)
)
ContactDetailScreen(
viewModel = detailVm,
onBack = { navController.popBackStack() }
)
}
}
// ── Clipboard banner — floats over content, slides in from top ────