|
|
|
|
@ -18,6 +18,7 @@ package com.google.samples.apps.nowinandroid.feature.bookmarks.impl
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.VisibleForTesting
|
|
|
|
|
import androidx.compose.foundation.Image
|
|
|
|
|
import androidx.compose.foundation.clickable
|
|
|
|
|
import androidx.compose.foundation.gestures.Orientation
|
|
|
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
|
|
|
import androidx.compose.foundation.layout.Box
|
|
|
|
|
@ -38,21 +39,28 @@ import androidx.compose.foundation.layout.wrapContentSize
|
|
|
|
|
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
|
|
|
|
|
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
|
|
|
|
|
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan
|
|
|
|
|
import androidx.compose.foundation.lazy.staggeredgrid.items
|
|
|
|
|
import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridState
|
|
|
|
|
import androidx.compose.material3.MaterialTheme
|
|
|
|
|
import androidx.compose.material3.Text
|
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
|
|
|
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.graphics.Color
|
|
|
|
|
import androidx.compose.ui.graphics.ColorFilter
|
|
|
|
|
import androidx.compose.ui.graphics.toArgb
|
|
|
|
|
import androidx.compose.ui.platform.LocalContext
|
|
|
|
|
import androidx.compose.ui.platform.testTag
|
|
|
|
|
import androidx.compose.ui.res.painterResource
|
|
|
|
|
import androidx.compose.ui.res.stringResource
|
|
|
|
|
import androidx.compose.ui.text.font.FontWeight
|
|
|
|
|
import androidx.compose.ui.text.style.TextAlign
|
|
|
|
|
import androidx.compose.ui.text.style.TextOverflow
|
|
|
|
|
import androidx.compose.ui.tooling.preview.Preview
|
|
|
|
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
|
|
|
|
import androidx.compose.ui.unit.dp
|
|
|
|
|
@ -60,6 +68,7 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
|
|
|
|
import androidx.lifecycle.Lifecycle
|
|
|
|
|
import androidx.lifecycle.compose.LifecycleEventEffect
|
|
|
|
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.analytics.LocalAnalyticsHelper
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollbar.DraggableScrollbar
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollbar.rememberDraggableScroller
|
|
|
|
|
@ -67,13 +76,16 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollba
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalTintTheme
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.BookmarkNoteDialog
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.NewsResourceCardExpanded
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.TrackScrollJank
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParameterProvider
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.newsFeed
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.launchCustomChromeTab
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.ui.logNewsResourceOpened
|
|
|
|
|
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.R
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
|
@ -84,6 +96,8 @@ internal fun BookmarksScreen(
|
|
|
|
|
viewModel: BookmarksViewModel = hiltViewModel(),
|
|
|
|
|
) {
|
|
|
|
|
val feedState by viewModel.feedUiState.collectAsStateWithLifecycle()
|
|
|
|
|
var editingNoteId by remember { mutableStateOf<String?>(null) }
|
|
|
|
|
|
|
|
|
|
BookmarksScreen(
|
|
|
|
|
feedState = feedState,
|
|
|
|
|
onShowSnackbar = onShowSnackbar,
|
|
|
|
|
@ -94,7 +108,19 @@ internal fun BookmarksScreen(
|
|
|
|
|
shouldDisplayUndoBookmark = viewModel.shouldDisplayUndoBookmark,
|
|
|
|
|
undoBookmarkRemoval = viewModel::undoBookmarkRemoval,
|
|
|
|
|
clearUndoState = viewModel::clearUndoState,
|
|
|
|
|
onEditNote = { editingNoteId = it },
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
editingNoteId?.let { id ->
|
|
|
|
|
val currentNote = (feedState as? Success)?.feed?.find { it.id == id }?.bookmarkNote ?: ""
|
|
|
|
|
BookmarkNoteDialog(
|
|
|
|
|
initialNote = currentNote,
|
|
|
|
|
onDismiss = { note ->
|
|
|
|
|
viewModel.updateNote(id, note)
|
|
|
|
|
editingNoteId = null
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -112,6 +138,7 @@ internal fun BookmarksScreen(
|
|
|
|
|
shouldDisplayUndoBookmark: Boolean = false,
|
|
|
|
|
undoBookmarkRemoval: () -> Unit = {},
|
|
|
|
|
clearUndoState: () -> Unit = {},
|
|
|
|
|
onEditNote: (String) -> Unit = {},
|
|
|
|
|
) {
|
|
|
|
|
val bookmarkRemovedMessage = stringResource(id = R.string.feature_bookmarks_api_removed)
|
|
|
|
|
val undoText = stringResource(id = R.string.feature_bookmarks_api_undo)
|
|
|
|
|
@ -139,6 +166,7 @@ internal fun BookmarksScreen(
|
|
|
|
|
removeFromBookmarks,
|
|
|
|
|
onNewsResourceViewed,
|
|
|
|
|
onTopicClick,
|
|
|
|
|
onEditNote,
|
|
|
|
|
modifier,
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
@ -166,6 +194,7 @@ private fun BookmarksGrid(
|
|
|
|
|
removeFromBookmarks: (String) -> Unit,
|
|
|
|
|
onNewsResourceViewed: (String) -> Unit,
|
|
|
|
|
onTopicClick: (String) -> Unit,
|
|
|
|
|
onEditNote: (String) -> Unit,
|
|
|
|
|
modifier: Modifier = Modifier,
|
|
|
|
|
) {
|
|
|
|
|
val scrollableState = rememberLazyStaggeredGridState()
|
|
|
|
|
@ -184,12 +213,55 @@ private fun BookmarksGrid(
|
|
|
|
|
.fillMaxSize()
|
|
|
|
|
.testTag("bookmarks:feed"),
|
|
|
|
|
) {
|
|
|
|
|
newsFeed(
|
|
|
|
|
feedState = feedState,
|
|
|
|
|
onNewsResourcesCheckedChanged = { id, _ -> removeFromBookmarks(id) },
|
|
|
|
|
onNewsResourceViewed = onNewsResourceViewed,
|
|
|
|
|
onTopicClick = onTopicClick,
|
|
|
|
|
)
|
|
|
|
|
if (feedState is Success) {
|
|
|
|
|
items(
|
|
|
|
|
items = feedState.feed,
|
|
|
|
|
key = { it.id },
|
|
|
|
|
contentType = { "newsFeedItem" },
|
|
|
|
|
) { userNewsResource ->
|
|
|
|
|
val context = LocalContext.current
|
|
|
|
|
val analyticsHelper = LocalAnalyticsHelper.current
|
|
|
|
|
val backgroundColor =
|
|
|
|
|
MaterialTheme.colorScheme.background.toArgb()
|
|
|
|
|
Column(
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
.padding(horizontal = 8.dp)
|
|
|
|
|
.animateItem(),
|
|
|
|
|
) {
|
|
|
|
|
NewsResourceCardExpanded(
|
|
|
|
|
userNewsResource = userNewsResource,
|
|
|
|
|
isBookmarked = userNewsResource.isSaved,
|
|
|
|
|
onClick = {
|
|
|
|
|
analyticsHelper.logNewsResourceOpened(
|
|
|
|
|
newsResourceId = userNewsResource.id,
|
|
|
|
|
)
|
|
|
|
|
launchCustomChromeTab(
|
|
|
|
|
context,
|
|
|
|
|
android.net.Uri.parse(userNewsResource.url),
|
|
|
|
|
backgroundColor,
|
|
|
|
|
)
|
|
|
|
|
onNewsResourceViewed(userNewsResource.id)
|
|
|
|
|
},
|
|
|
|
|
hasBeenViewed = userNewsResource.hasBeenViewed,
|
|
|
|
|
onToggleBookmark = { removeFromBookmarks(userNewsResource.id) },
|
|
|
|
|
onTopicClick = onTopicClick,
|
|
|
|
|
)
|
|
|
|
|
val note = userNewsResource.bookmarkNote
|
|
|
|
|
if (note != null) {
|
|
|
|
|
Text(
|
|
|
|
|
text = note,
|
|
|
|
|
style = MaterialTheme.typography.bodySmall,
|
|
|
|
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
|
|
maxLines = 1,
|
|
|
|
|
overflow = TextOverflow.Ellipsis,
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
.fillMaxWidth()
|
|
|
|
|
.clickable { onEditNote(userNewsResource.id) },
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
item(span = StaggeredGridItemSpan.FullLine) {
|
|
|
|
|
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.safeDrawing))
|
|
|
|
|
}
|
|
|
|
|
@ -275,6 +347,7 @@ private fun BookmarksGridPreview(
|
|
|
|
|
removeFromBookmarks = {},
|
|
|
|
|
onNewsResourceViewed = {},
|
|
|
|
|
onTopicClick = {},
|
|
|
|
|
onEditNote = {},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|