diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/App.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/App.kt index 1b246d3..ed281a6 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/App.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/App.kt @@ -44,6 +44,7 @@ import su.reya.coop.screens.NewIdentityScreen import su.reya.coop.screens.OnboardingScreen import su.reya.coop.screens.ProfileScreen import su.reya.coop.screens.RelayScreen +import su.reya.coop.screens.RequestListScreen import su.reya.coop.screens.ScanScreen import su.reya.coop.screens.UpdateProfileScreen @@ -164,6 +165,9 @@ fun App(viewModel: NostrViewModel) { entry { HomeScreen() } + entry { + RequestListScreen() + } entry { OnboardingScreen() } diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/Navigation.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/Navigation.kt index 50aca39..6a53f67 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/Navigation.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/Navigation.kt @@ -23,6 +23,9 @@ sealed interface Screen : NavKey { @Serializable data object Home : Screen + @Serializable + data object RequestList : Screen + @Serializable data class Chat(val id: Long) : Screen diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/RequestListScreen.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/RequestListScreen.kt new file mode 100644 index 0000000..75ee8da --- /dev/null +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/RequestListScreen.kt @@ -0,0 +1,155 @@ +package su.reya.coop.screens + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.pulltorefresh.PullToRefreshBox +import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import coop.composeapp.generated.resources.Res +import coop.composeapp.generated.resources.ic_arrow_back +import kotlinx.coroutines.launch +import su.reya.coop.LocalNavigator +import su.reya.coop.LocalNostrViewModel +import su.reya.coop.LocalSnackbarHostState +import su.reya.coop.RoomKind +import su.reya.coop.Screen + +@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class) +@Composable +fun RequestListScreen() { + val navigator = LocalNavigator.current + val snackbarHostState = LocalSnackbarHostState.current + val viewModel = LocalNostrViewModel.current + + val scope = rememberCoroutineScope() + val listState = rememberLazyListState() + val pullToRefreshState = rememberPullToRefreshState() + + var isRefreshing by remember { mutableStateOf(false) } + val chatRooms by viewModel.chatRooms.collectAsStateWithLifecycle() + + // Get all request rooms + val requests = remember(chatRooms) { + chatRooms.filter { it.kind == RoomKind.Request } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + containerColor = MaterialTheme.colorScheme.surfaceContainer, + topBar = { + TopAppBar( + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.surfaceContainer, + ), + title = { + Text("New Requests", style = MaterialTheme.typography.titleMediumEmphasized) + }, + navigationIcon = { + IconButton(onClick = { navigator.goBack() }) { + Icon( + painter = org.jetbrains.compose.resources.painterResource(Res.drawable.ic_arrow_back), + contentDescription = "Back" + ) + } + }, + ) + }, + ) { innerPadding -> + Column( + modifier = Modifier.padding(top = innerPadding.calculateTopPadding()), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.surface, + shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp), + ) { + PullToRefreshBox( + modifier = Modifier.fillMaxSize(), + isRefreshing = isRefreshing, + state = pullToRefreshState, + onRefresh = { + scope.launch { + isRefreshing = true + viewModel.refreshChatRooms() + isRefreshing = false + } + }, + indicator = { + PullToRefreshDefaults.LoadingIndicator( + state = pullToRefreshState, + isRefreshing = isRefreshing, + modifier = Modifier.align(Alignment.TopCenter), + ) + } + ) { + if (requests.isEmpty()) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + Text( + text = "No requests yet", + style = MaterialTheme.typography.titleLargeEmphasized.copy( + fontWeight = FontWeight.SemiBold + ), + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = "New chat requests will appear here.", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.outline + ) + } + } + } else { + LazyColumn( + state = listState, + modifier = Modifier.fillMaxSize() + ) { + items(requests.toList(), key = { it.id }) { room -> + ChatRoom( + room = room, + onClick = { navigator.navigate(Screen.Chat(room.id)) } + ) + } + } + } + } + } + } + } +} \ No newline at end of file