diff --git a/core-ui/build.gradle b/core-ui/build.gradle index 10b1d72d7..1dc0f71c9 100644 --- a/core-ui/build.gradle +++ b/core-ui/build.gradle @@ -28,6 +28,7 @@ android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 + coreLibraryDesugaringEnabled true } kotlinOptions { jvmTarget = '1.8' @@ -43,6 +44,8 @@ android { dependencies { implementation project(':core-model') + coreLibraryDesugaring libs.android.desugarJdkLibs + implementation libs.androidx.core.ktx implementation libs.coil.kt implementation libs.coil.kt.compose diff --git a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt index a616c5419..f824b075c 100644 --- a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt +++ b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt @@ -37,11 +37,17 @@ import androidx.compose.material3.IconToggleButton import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.semantics @@ -54,7 +60,10 @@ import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Article import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme +import java.time.ZoneId +import java.time.format.DateTimeFormatter import kotlinx.datetime.Instant +import kotlinx.datetime.toJavaInstant /** * [NewsResource] card used on the following screens: For You, Episodes, Saved @@ -90,6 +99,8 @@ fun NewsResourceCardExpanded( BookmarkButton(isBookmarked, onToggleBookmark) } Spacer(modifier = Modifier.height(12.dp)) + NewsResourceDate(newsResource.publishDate) + Spacer(modifier = Modifier.height(12.dp)) NewsResourceShortDescription(newsResource.content) } } @@ -181,11 +192,31 @@ fun BookmarkButton( } } +@Composable +private fun dateFormatted(publishDate: Instant): String { + var zoneId by remember { mutableStateOf(ZoneId.systemDefault()) } + + val context = LocalContext.current + + DisposableEffect(context) { + val receiver = TimeZoneBroadcastReceiver( + onTimeZoneChanged = { zoneId = ZoneId.systemDefault() } + ) + receiver.register(context) + onDispose { + receiver.unregister(context) + } + } + + return DateTimeFormatter.ofPattern("MMM d, yyyy") + .withZone(zoneId).format(publishDate.toJavaInstant()) +} + @Composable fun NewsResourceDate( - newsResource: NewsResource + publishDate: Instant ) { - TODO() + Text(dateFormatted(publishDate), style = MaterialTheme.typography.body2) } @Composable diff --git a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/TimeZoneBroadcastReceiver.kt b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/TimeZoneBroadcastReceiver.kt new file mode 100644 index 000000000..0e3fc6d1c --- /dev/null +++ b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/TimeZoneBroadcastReceiver.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.samples.apps.nowinandroid.core.ui + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter + +class TimeZoneBroadcastReceiver( + val onTimeZoneChanged: () -> Unit +) : BroadcastReceiver() { + private var registered = false + + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == Intent.ACTION_TIMEZONE_CHANGED) { + onTimeZoneChanged() + } + } + + fun register(context: Context) { + if (!registered) { + val filter = IntentFilter() + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED) + context.registerReceiver(this, filter) + registered = true + } + } + + fun unregister(context: Context) { + if (registered) { + context.unregisterReceiver(this) + registered = false + } + } +}