Polish ItemScreen

This commit is contained in:
Shinokuni 2024-08-13 16:16:36 +02:00
parent 01ce06467d
commit 3417466e30
7 changed files with 114 additions and 53 deletions

View File

@ -8,10 +8,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.readrops.app.R
import com.readrops.app.util.DefaultPreview
import com.readrops.app.util.components.SelectableIconText
import com.readrops.app.util.components.dialog.BaseDialog
import com.readrops.app.util.components.SelectableImageText
import com.readrops.app.util.theme.spacing
enum class ItemImageChoice {
@ -30,25 +30,32 @@ fun ItemImageDialog(
onDismiss = onDismiss
) {
Column {
SelectableImageText(
image = rememberVectorPainter(image = Icons.Default.Share),
SelectableIconText(
icon = rememberVectorPainter(image = Icons.Default.Share),
text = stringResource(id = R.string.share_image),
style = MaterialTheme.typography.titleMedium,
spacing = MaterialTheme.spacing.shortSpacing,
spacing = MaterialTheme.spacing.mediumSpacing,
padding = MaterialTheme.spacing.shortSpacing,
imageSize = 16.dp,
onClick = { onChoice(ItemImageChoice.SHARE) }
)
SelectableImageText(
image = painterResource(id = R.drawable.ic_download),
SelectableIconText(
icon = painterResource(id = R.drawable.ic_download),
text = stringResource(id = R.string.download_image),
style = MaterialTheme.typography.titleMedium,
spacing = MaterialTheme.spacing.shortSpacing,
spacing = MaterialTheme.spacing.mediumSpacing,
padding = MaterialTheme.spacing.shortSpacing,
imageSize = 16.dp,
onClick = { onChoice(ItemImageChoice.DOWNLOAD) }
)
}
}
}
@DefaultPreview
@Composable
private fun ItemImageDialogPreview() {
ItemImageDialog(
onChoice = {},
onDismiss = {}
)
}

View File

@ -13,9 +13,13 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
@ -51,12 +55,15 @@ import androidx.core.net.toUri
import androidx.core.view.children
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import cafe.adriel.voyager.koin.getScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import coil.compose.AsyncImage
import com.readrops.app.R
import com.readrops.app.item.view.ItemNestedScrollView
import com.readrops.app.item.view.ItemWebView
import com.readrops.app.util.components.AndroidScreen
import com.readrops.app.util.components.CenteredProgressIndicator
import com.readrops.app.util.components.FeedIcon
import com.readrops.app.util.components.IconText
import com.readrops.app.util.theme.MediumSpacer
import com.readrops.app.util.theme.ShortSpacer
@ -74,6 +81,7 @@ class ItemScreen(
override fun Content() {
val context = LocalContext.current
val density = LocalDensity.current
val navigator = LocalNavigator.currentOrThrow
val screenModel =
getScreenModel<ItemScreenModel>(parameters = { parametersOf(itemId) })
@ -122,7 +130,7 @@ class ItemScreen(
LaunchedEffect(state.fileDownloadedEvent) {
if (state.fileDownloadedEvent) {
snackbarHostState.showSnackbar("Downloaded file!")
snackbarHostState.showSnackbar(context.getString(R.string.downloaded_file))
}
}
@ -136,6 +144,12 @@ class ItemScreen(
primaryColor
}
val colorScheme = when (state.theme) {
"light" -> CustomTabsIntent.COLOR_SCHEME_LIGHT
"dark" -> CustomTabsIntent.COLOR_SCHEME_DARK
else -> CustomTabsIntent.COLOR_SCHEME_SYSTEM
}
fun openUrl(url: String) {
if (state.openInExternalBrowser) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
@ -150,14 +164,14 @@ class ItemScreen(
)
.setShareState(CustomTabsIntent.SHARE_STATE_ON)
.setUrlBarHidingEnabled(true)
.setColorScheme(colorScheme)
.build()
.launchUrl(context, url.toUri())
}
}
Scaffold(
modifier = Modifier
.nestedScroll(nestedScrollConnection),
modifier = Modifier.nestedScroll(nestedScrollConnection),
snackbarHost = { SnackbarHost(snackbarHostState) },
bottomBar = {
ItemScreenBottomBar(
@ -194,6 +208,7 @@ class ItemScreen(
factory = { context ->
ItemNestedScrollView(
context = context,
useBackgroundTitle = item.imageLink != null,
onGlobalLayoutListener = { viewHeight, contentHeight ->
isScrollable = viewHeight - contentHeight < 0
},
@ -203,19 +218,27 @@ class ItemScreen(
if (item.imageLink != null) {
BackgroundTitle(itemWithFeed = itemWithFeed)
} else {
val tintColor = if (itemWithFeed.color != 0) {
Color(itemWithFeed.color)
} else {
MaterialTheme.colorScheme.onBackground
}
Box {
IconButton(
onClick = { navigator.pop() },
modifier = Modifier
.statusBarsPadding()
.align(Alignment.TopStart)
) {
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = null,
)
}
SimpleTitle(
itemWithFeed = itemWithFeed,
titleColor = tintColor,
accentColor = tintColor,
baseColor = MaterialTheme.colorScheme.onBackground,
bottomPadding = true
)
SimpleTitle(
itemWithFeed = itemWithFeed,
titleColor = accentColor,
accentColor = accentColor,
baseColor = MaterialTheme.colorScheme.onBackground,
bottomPadding = true
)
}
}
}
},
@ -248,6 +271,8 @@ class ItemScreen(
fun BackgroundTitle(
itemWithFeed: ItemWithFeed,
) {
val navigator = LocalNavigator.currentOrThrow
val onScrimColor = Color.White.copy(alpha = 0.85f)
val accentColor = if (itemWithFeed.color != 0) {
Color(itemWithFeed.color)
@ -276,13 +301,28 @@ fun BackgroundTitle(
modifier = Modifier
.fillMaxSize()
) {
SimpleTitle(
itemWithFeed = itemWithFeed,
titleColor = onScrimColor,
accentColor = accentColor,
baseColor = onScrimColor,
bottomPadding = true
)
Box {
IconButton(
onClick = { navigator.pop() },
modifier = Modifier
.statusBarsPadding()
.align(Alignment.TopStart)
) {
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = null,
tint = Color.White
)
}
SimpleTitle(
itemWithFeed = itemWithFeed,
titleColor = onScrimColor,
accentColor = accentColor,
baseColor = onScrimColor,
bottomPadding = true
)
}
}
}
@ -309,14 +349,11 @@ fun SimpleTitle(
bottom = if (bottomPadding) spacing else 0.dp
)
) {
AsyncImage(
model = itemWithFeed.feedIconUrl,
contentDescription = itemWithFeed.feedName,
placeholder = painterResource(id = R.drawable.ic_rss_feed_grey),
error = painterResource(id = R.drawable.ic_rss_feed_grey),
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
FeedIcon(
iconUrl = itemWithFeed.feedIconUrl,
name = itemWithFeed.feedName,
size = 48.dp,
modifier = Modifier.clip(CircleShape)
)
ShortSpacer()

View File

@ -24,6 +24,7 @@ import com.readrops.db.queries.ItemSelectionQueryBuilder
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@ -81,17 +82,22 @@ class ItemScreenModel(
}
screenModelScope.launch(dispatcher) {
preferences.openLinksWith.flow
.collect { value ->
mutableState.update {
it.copy(
openInExternalBrowser = when (value) {
"external_navigator" -> true
else -> false
}
)
}
combine(
preferences.openLinksWith.flow,
preferences.theme.flow
) { openLinksWith, theme ->
openLinksWith to theme
}.collect { (openLinksWith, theme) ->
mutableState.update {
it.copy(
openInExternalBrowser = when (openLinksWith) {
"external_navigator" -> true
else -> false
},
theme = theme
)
}
}
}
}
@ -186,5 +192,6 @@ data class ItemState(
val bottomBarState: BottomBarState = BottomBarState(),
val imageDialogUrl: String? = null,
val fileDownloadedEvent: Boolean = false,
val openInExternalBrowser: Boolean = false
val openInExternalBrowser: Boolean = false,
val theme: String? = ""
)

View File

@ -11,6 +11,7 @@ import androidx.core.widget.NestedScrollView
@SuppressLint("ResourceType", "ViewConstructor")
class ItemNestedScrollView(
context: Context,
useBackgroundTitle: Boolean,
onGlobalLayoutListener: (viewHeight: Int, contentHeight: Int) -> Unit,
onUrlClick: (String) -> Unit,
onImageLongPress: (String) -> Unit,
@ -54,6 +55,12 @@ class ItemNestedScrollView(
webViewParams.addRule(RelativeLayout.BELOW, composeView.id)
webView.layoutParams = webViewParams
if (useBackgroundTitle) {
val density = resources.displayMetrics.density
val dpAsPixels = (8 * density + 0.5f).toInt()
composeView.setPadding(0, 0, 0, dpAsPixels)
}
addView(composeView)
addView(webView)
}

View File

@ -14,6 +14,7 @@ import com.readrops.app.util.FeedKey
fun FeedIcon(
iconUrl: String?,
name: String,
modifier: Modifier = Modifier,
size: Dp = 24.dp
) {
AsyncImage(
@ -22,6 +23,6 @@ fun FeedIcon(
placeholder = painterResource(R.drawable.ic_rss_feed_grey),
fallback = painterResource(id = R.drawable.ic_rss_feed_grey),
contentDescription = name,
modifier = Modifier.size(size)
modifier = modifier.size(size)
)
}

View File

@ -217,4 +217,5 @@
<string name="litecoin_copy_address">Litecoin (copier l\'adresse)</string>
<string name="donation_text">"Si vous considérez que mon travail vous est utile et si vous souhaitez me soutenir, vous pouvez me faire une donation. "</string>
<string name="add_feed">Ajouter un flux</string>
<string name="downloaded_file">Fichier téléchargé !</string>
</resources>

View File

@ -230,4 +230,5 @@
<string name="litecoin_copy_address">Litecoin (copy address)</string>
<string name="donation_text">I you find my work useful and you would like to support me, you can consider making me a donation.</string>
<string name="add_feed">Add feed</string>
<string name="downloaded_file">Downloaded file!</string>
</resources>