diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostNotifier.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostNotifier.kt index 7bbb64c27..37f57c45e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostNotifier.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostNotifier.kt @@ -39,6 +39,10 @@ import com.vitorpamplona.amethyst.ui.stringRes * now guards against; the notification closes the loop. */ object ScheduledPostNotifier { + // @Volatile so the channel reference is visible across the WorkManager IO + // thread pool — two workers firing in the same window can race on + // ensureChannel. createNotificationChannel itself is idempotent. + @Volatile private var channel: NotificationChannel? = null private const val SCHEDULED_POST_NOT_ID_BASE = 0x70000 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt index a034d52d8..32c5c617f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt @@ -78,6 +78,7 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.semantics.semantics @@ -111,7 +112,6 @@ import java.time.LocalDate import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.format.FormatStyle -import java.util.Locale @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable @@ -460,8 +460,9 @@ private fun ScheduledPostCardExpandedPanel( @Composable private fun SectionLabel(text: String) { + val locale = LocalConfiguration.current.locales[0] Text( - text = text.uppercase(Locale.getDefault()), + text = text.uppercase(locale), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 4.dp), diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt index 4ff97faed..d934b4618 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt @@ -31,6 +31,11 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update class PoolEventOutbox { + // @Volatile so the polling path (INostrClient.pendingPublishRelaysFor) + // sees current state from threads that didn't write the map. Mutations + // still happen on NostrClient's IO scope; this only closes the + // visibility gap for cross-thread readers. + @Volatile private var eventOutbox = mapOf() val relays = MutableStateFlow(setOf()) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxState.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxState.kt index f75f3aa6a..28fb62967 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxState.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxState.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.utils.TimeUtils class PoolEventOutboxState( val event: Event, - var relaysRemaining: Set, + @Volatile var relaysRemaining: Set, ) { private var failures = mapOf()