A cheap attempt at a native Bluesky client for Android

Compose: Use CircularWavyProgressIndicator

Replace `CircularProgressIndicator` with the new `CircularWavyProgressIndicator` from Material 3 Expressive when a post is being uploaded.

This change provides a more modern-looking progress indicator. The `@OptIn` for `ExperimentalMaterial3ExpressiveApi` has been added to support this.

+17 -18
+17 -18
app/src/main/java/industries/geesawra/monarch/ComposeView.kt
··· 42 42 import androidx.compose.material3.Button 43 43 import androidx.compose.material3.ButtonDefaults 44 44 import androidx.compose.material3.Card 45 - import androidx.compose.material3.CircularProgressIndicator 45 + import androidx.compose.material3.CircularWavyProgressIndicator 46 46 import androidx.compose.material3.ExperimentalMaterial3Api 47 + import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi 47 48 import androidx.compose.material3.Icon 48 49 import androidx.compose.material3.MaterialTheme 49 50 import androidx.compose.material3.OutlinedCard ··· 131 132 when (transferableContent.hasMediaType(MediaType.Image)) { 132 133 true -> transferableContent.consume { 133 134 val uri = it.uri 134 - val mimeType: String? = context.contentResolver.getType(uri) 135 135 mediaSelected.value = listOf(uri) 136 136 true 137 137 } ··· 335 335 } 336 336 } 337 337 338 - @OptIn(ExperimentalMaterial3Api::class) 338 + @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) 339 339 @Composable 340 340 fun ActionRow( 341 341 context: Context, ··· 352 352 isQuotePost: Boolean = false, 353 353 facets: List<Facet> = listOf() 354 354 ) { 355 - 356 355 Row( 357 356 modifier = Modifier 358 357 .fillMaxWidth() ··· 370 369 Icon(Icons.Default.CameraRoll, contentDescription = "Attach media") 371 370 } 372 371 373 - if (uploadingPost.value) { 374 - CircularProgressIndicator() 375 - } 376 - 377 372 val postButtonEnabled = remember(postText, mediaSelected.value) { 378 373 (postText.isNotBlank() || mediaSelected.value.isNotEmpty()) && postText.length <= maxChars 379 374 } 380 - 381 - Button( 382 - onClick = { 375 + 376 + if (uploadingPost.value) { 377 + CircularWavyProgressIndicator() 378 + } else { 379 + Button( 380 + onClick = { 383 381 coroutineScope.launch { 384 382 uploadingPost.value = true // Show progress immediately 385 383 timelineViewModel.post( ··· 420 418 uploadingPost.value = false // Hide progress after completion 421 419 } 422 420 } 423 - }, 424 - modifier = Modifier.padding(end = 8.dp), 425 - enabled = postButtonEnabled && !uploadingPost.value // Disable while uploading 426 - ) { 427 - Icon(Icons.AutoMirrored.Filled.Send, contentDescription = "Post") 428 - Spacer(Modifier.size(ButtonDefaults.IconSpacing)) 429 - Text("Skeet") 421 + }, 422 + modifier = Modifier.padding(end = 8.dp), 423 + enabled = postButtonEnabled && !uploadingPost.value // Disable while uploading 424 + ) { 425 + Icon(Icons.AutoMirrored.Filled.Send, contentDescription = "Post") 426 + Spacer(Modifier.size(ButtonDefaults.IconSpacing)) 427 + Text("Skeet") 428 + } 430 429 } 431 430 } 432 431 }