A cheap attempt at a native Bluesky client for Android
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'worktree-typed-snacking-peach'

geesawra 4b88d7c7 f1a09dee

+21 -5
+2 -1
app/src/main/java/industries/geesawra/monarch/LoginView.kt
··· 49 49 @Composable 50 50 fun LoginView( 51 51 modifier: Modifier = Modifier, 52 + blueskyConn: BlueskyConn? = null, 52 53 navigate: () -> Unit 53 54 ) { 54 55 var password by remember { mutableStateOf("") } ··· 56 57 var passwordVisible by remember { mutableStateOf(false) } 57 58 val scope = rememberCoroutineScope() 58 59 val ctx = LocalContext.current 59 - val bc = BlueskyConn(ctx) 60 + val bc = blueskyConn ?: BlueskyConn(ctx) 60 61 val appPasswordRegex = "[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}".toRegex() 61 62 var currentPDS by remember { mutableStateOf("") } 62 63 var lookingUpPDS by remember { mutableStateOf(false) }
+8 -2
app/src/main/java/industries/geesawra/monarch/MainActivity.kt
··· 243 243 .verticalScroll(rememberScrollState()), 244 244 contentAlignment = Alignment.Center 245 245 ) { 246 - LoginView { 247 - navController.navigate(ViewList.Main.name) 246 + LoginView( 247 + blueskyConn = conn, 248 + ) { 249 + timelineViewModel.onNewLogin() 250 + firstLoadDone.value = false 251 + navController.navigate(ViewList.Main.name) { 252 + popUpTo(0) { inclusive = true } 253 + } 248 254 } 249 255 } 250 256 }
+6 -2
app/src/main/java/industries/geesawra/monarch/MainView.kt
··· 92 92 import androidx.compose.material3.AlertDialog 93 93 import androidx.compose.material3.OutlinedTextField 94 94 import androidx.compose.material3.TextButton 95 + import androidx.compose.foundation.shape.RoundedCornerShape 96 + import industries.geesawra.monarch.datalayer.AvatarShape 95 97 import industries.geesawra.monarch.datalayer.SettingsState 96 98 import industries.geesawra.monarch.datalayer.SkeetData 97 99 import industries.geesawra.monarch.datalayer.TimelineViewModel ··· 412 414 val user = timelineViewModel.uiState.user!! 413 415 var showAccountSwitcher by remember { mutableStateOf(false) } 414 416 417 + val avatarClipShape = if (settingsState.avatarShape == AvatarShape.RoundedSquare) RoundedCornerShape(8.dp) else CircleShape 418 + 415 419 AsyncImage( 416 420 model = ImageRequest.Builder(LocalContext.current) 417 421 .data(user.avatar?.uri) ··· 421 425 contentDescription = "${user.displayName ?: user.handle.handle}'s avatar", 422 426 contentScale = ContentScale.Crop, 423 427 modifier = Modifier 424 - .size(55.dp) 425 - .clip(CircleShape) 428 + .size(40.dp) 429 + .clip(avatarClipShape) 426 430 .combinedClickable( 427 431 onClick = { onProfileTap(user.did) }, 428 432 onLongClick = { showAccountSwitcher = true }
+5
app/src/main/java/industries/geesawra/monarch/datalayer/TimelineViewModel.kt
··· 204 204 } 205 205 } 206 206 207 + fun onNewLogin() { 208 + bskyConn.resetClients() 209 + uiState = TimelineUiState(authenticated = true, sessionChecked = true) 210 + } 211 + 207 212 fun loadSession() { 208 213 viewModelScope.launch { 209 214 if (!bskyConn.hasSession()) {