@@ -31,6 +31,8 @@ import androidx.compose.material3.Scaffold
3131import androidx.compose.material3.Text
3232import androidx.compose.material3.TextButton
3333import androidx.compose.material3.TopAppBar
34+import androidx.compose.material3.pulltorefresh.PullToRefreshBox
35+import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
3436import androidx.compose.runtime.Composable
3537import androidx.compose.runtime.getValue
3638import androidx.compose.runtime.mutableStateOf
@@ -38,6 +40,8 @@ import androidx.compose.runtime.remember
3840import androidx.compose.runtime.setValue
3941import androidx.compose.ui.Alignment
4042import androidx.compose.ui.Modifier
43+import androidx.compose.ui.hapticfeedback.HapticFeedbackType
44+import androidx.compose.ui.platform.LocalHapticFeedback
4145import androidx.compose.ui.text.style.TextOverflow
4246import androidx.compose.ui.unit.dp
4347import soy.iko.opencode.core.Event
@@ -47,6 +51,7 @@ import soy.iko.opencode.core.UiState
4751@OptIn(ExperimentalMaterial3Api::class)
4852@Composable
4953fun SessionsScreen(state: UiState, dispatch: (Event) -> Unit) {
54+ val haptic = LocalHapticFeedback.current
5055 var pendingDeleteId by remember { mutableStateOf<String?>(null) }
5156
5257 pendingDeleteId?.let { deleteId ->
@@ -57,6 +62,7 @@ fun SessionsScreen(state: UiState, dispatch: (Event) -> Unit) {
5762 text = { Text(pendingSession?.title ?: deleteId) },
5863 confirmButton = {
5964 TextButton(onClick = {
65+ haptic.performHapticFeedback(HapticFeedbackType.LongPress)
6066 dispatch(Event.DeleteSession(deleteId))
6167 pendingDeleteId = null
6268 }) {
@@ -101,17 +107,24 @@ fun SessionsScreen(state: UiState, dispatch: (Event) -> Unit) {
101107 }
102108 when {
103109 state.sessions.isEmpty() && !state.loading -> EmptySessions()
104− else -> LazyColumn(
110+ else -> PullToRefreshBox(
111+ isRefreshing = state.loading,
112+ onRefresh = { dispatch(Event.LoadSessions) },
105113 modifier = Modifier.fillMaxSize(),
106− contentPadding = PaddingValues(bottom = 88.dp),
114+ state = rememberPullToRefreshState(),
107115 ) {
108− items(state.sessions, key = { it.id }) { session ->
109− SessionRow(
110− session = session,
111− onOpen = { dispatch(Event.SelectSession(session.id)) },
112− onDelete = { pendingDeleteId = session.id },
113− )
114− HorizontalDivider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.25f))
116+ LazyColumn(
117+ modifier = Modifier.fillMaxSize(),
118+ contentPadding = PaddingValues(bottom = 88.dp),
119+ ) {
120+ items(state.sessions, key = { it.id }) { session ->
121+ SessionRow(
122+ session = session,
123+ onOpen = { dispatch(Event.SelectSession(session.id)) },
124+ onDelete = { pendingDeleteId = session.id },
125+ )
126+ HorizontalDivider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.25f))
127+ }
115128 }
116129 }
117130 }