mirror of
https://github.com/Aviortheking/Neo-Store.git
synced 2025-04-23 19:32:16 +00:00
Create AppDetail Header
Add InstallState enum { TODO(Replace with sealed class) } Use string in image loading { Uri handling is not good in Compose } Make Zoomable image more performant Add few strings { Might Change }
This commit is contained in:
parent
12ad62e948
commit
c64fff0a4a
@ -12,4 +12,11 @@ enum class UpdateCategory(val id: Int) {
|
|||||||
ALL(0),
|
ALL(0),
|
||||||
UPDATED(1),
|
UPDATED(1),
|
||||||
NEW(2)
|
NEW(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class InstallState {
|
||||||
|
INSTALL,
|
||||||
|
INSTALLING,
|
||||||
|
INSTALLED,
|
||||||
|
PENDING
|
||||||
}
|
}
|
@ -36,7 +36,7 @@ fun ProductCard(
|
|||||||
item.metadataIcon,
|
item.metadataIcon,
|
||||||
repo?.address,
|
repo?.address,
|
||||||
repo?.authentication
|
repo?.authentication
|
||||||
)
|
).toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ fun ProductsListItem(
|
|||||||
item.metadataIcon,
|
item.metadataIcon,
|
||||||
repo?.address,
|
repo?.address,
|
||||||
repo?.authentication
|
repo?.authentication
|
||||||
)
|
).toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ fun ScreenshotList(
|
|||||||
.wrapContentWidth()
|
.wrapContentWidth()
|
||||||
.requiredHeight(120.dp)
|
.requiredHeight(120.dp)
|
||||||
.clickable { onScreenShotClick(it) },
|
.clickable { onScreenShotClick(it) },
|
||||||
data = it.path.toUri(),
|
data = it.path,
|
||||||
shape = RoundedCornerShape(LocalShapes.current.large)
|
shape = RoundedCornerShape(LocalShapes.current.large)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
package com.looker.droidify.ui.compose.pages.app_detail
|
||||||
|
|
@ -0,0 +1,186 @@
|
|||||||
|
package com.looker.droidify.ui.compose.pages.app_detail.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.Close
|
||||||
|
import androidx.compose.material.icons.rounded.Download
|
||||||
|
import androidx.compose.material.icons.rounded.Launch
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.looker.droidify.R
|
||||||
|
import com.looker.droidify.entity.InstallState
|
||||||
|
import com.looker.droidify.ui.compose.theme.LocalShapes
|
||||||
|
import com.looker.droidify.ui.compose.utils.NetworkImage
|
||||||
|
import com.looker.droidify.utility.extension.text.formatSize
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Header(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
icon: String?,
|
||||||
|
appName: String,
|
||||||
|
packageName: String,
|
||||||
|
versionCode: String,
|
||||||
|
appSize: String,
|
||||||
|
appDev: String
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(LocalShapes.current.large)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.SpaceEvenly
|
||||||
|
) {
|
||||||
|
HeaderTitle(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = icon,
|
||||||
|
appName = appName,
|
||||||
|
packageName = packageName
|
||||||
|
)
|
||||||
|
HeaderExtra(
|
||||||
|
versionCode = versionCode,
|
||||||
|
appSize = appSize,
|
||||||
|
appDev = appDev
|
||||||
|
)
|
||||||
|
DownloadProgress(totalSize = 69420)
|
||||||
|
InstallButton(installState = InstallState.PENDING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HeaderTitle(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
icon: String? = null,
|
||||||
|
appName: String,
|
||||||
|
packageName: String,
|
||||||
|
actions: @Composable () -> Unit = {}
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier.padding(16.dp),
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
NetworkImage(
|
||||||
|
modifier = Modifier.size(56.dp),
|
||||||
|
data = icon
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.Start,
|
||||||
|
verticalArrangement = Arrangement.SpaceAround
|
||||||
|
) {
|
||||||
|
Text(text = appName, style = MaterialTheme.typography.titleLarge)
|
||||||
|
Text(text = packageName, style = MaterialTheme.typography.bodyMedium)
|
||||||
|
}
|
||||||
|
Box { actions() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HeaderExtra(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
versionCode: String,
|
||||||
|
appSize: String,
|
||||||
|
appDev: String
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.wrapContentHeight()
|
||||||
|
) {
|
||||||
|
HeaderExtrasCard(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
title = stringResource(id = R.string.version),
|
||||||
|
text = versionCode
|
||||||
|
)
|
||||||
|
HeaderExtrasCard(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
title = stringResource(id = R.string.size),
|
||||||
|
text = appSize
|
||||||
|
)
|
||||||
|
HeaderExtrasCard(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
title = stringResource(id = R.string.source_code),
|
||||||
|
text = appDev
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HeaderExtrasCard(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
extra: @Composable () -> Unit = {},
|
||||||
|
title: String,
|
||||||
|
text: String,
|
||||||
|
onClick: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
modifier = modifier
|
||||||
|
.clip(RoundedCornerShape(50))
|
||||||
|
.clickable { onClick() }
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.SpaceEvenly,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
extra()
|
||||||
|
Text(text = title, style = MaterialTheme.typography.labelLarge)
|
||||||
|
Text(text = text, style = MaterialTheme.typography.bodyMedium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DownloadProgress(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
downloading: Float = 0f,
|
||||||
|
totalSize: Long
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.Start
|
||||||
|
) {
|
||||||
|
Text(text = totalSize.div(downloading).toLong().formatSize() + "/" + totalSize.formatSize())
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
LinearProgressIndicator(progress = downloading)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun InstallButton(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
installState: InstallState,
|
||||||
|
onClick: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
modifier = modifier,
|
||||||
|
onClick = onClick
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = when (installState) {
|
||||||
|
InstallState.INSTALLING -> Icons.Rounded.Close
|
||||||
|
InstallState.INSTALLED -> Icons.Rounded.Launch
|
||||||
|
InstallState.PENDING -> Icons.Rounded.Close
|
||||||
|
InstallState.INSTALL -> Icons.Rounded.Download
|
||||||
|
},
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = when (installState) {
|
||||||
|
InstallState.INSTALLING -> stringResource(id = R.string.installing)
|
||||||
|
InstallState.INSTALLED -> stringResource(id = R.string.launch)
|
||||||
|
InstallState.PENDING -> stringResource(id = R.string.pending)
|
||||||
|
InstallState.INSTALL -> stringResource(id = R.string.install)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +1,30 @@
|
|||||||
package com.looker.droidify.ui.compose.utils
|
package com.looker.droidify.ui.compose.utils
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.gestures.detectTransformGestures
|
import androidx.compose.foundation.gestures.rememberTransformableState
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.gestures.transformable
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import coil.annotation.ExperimentalCoilApi
|
|
||||||
import coil.compose.SubcomposeAsyncImage
|
import coil.compose.SubcomposeAsyncImage
|
||||||
import coil.compose.SubcomposeAsyncImageContent
|
import coil.compose.SubcomposeAsyncImageContent
|
||||||
import com.looker.droidify.R
|
import com.looker.droidify.R
|
||||||
import com.looker.droidify.ui.compose.theme.LocalShapes
|
import com.looker.droidify.ui.compose.theme.LocalShapes
|
||||||
|
|
||||||
@OptIn(ExperimentalCoilApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NetworkImage(
|
fun NetworkImage(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
data: Uri?,
|
data: String?,
|
||||||
contentScale: ContentScale = ContentScale.Crop,
|
contentScale: ContentScale = ContentScale.Crop,
|
||||||
backgroundColor: Color = MaterialTheme.colorScheme.surface,
|
backgroundColor: Color = MaterialTheme.colorScheme.surface,
|
||||||
shape: Shape = RoundedCornerShape(LocalShapes.current.medium)
|
shape: Shape = RoundedCornerShape(LocalShapes.current.medium)
|
||||||
@ -57,32 +50,24 @@ fun NetworkImage(
|
|||||||
@Composable
|
@Composable
|
||||||
fun ZoomableImage(
|
fun ZoomableImage(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
data: Uri?
|
data: String?,
|
||||||
) {
|
) {
|
||||||
val scale = remember { mutableStateOf(1f) }
|
var scale by remember { mutableStateOf(1f) }
|
||||||
val rotationState = remember { mutableStateOf(1f) }
|
var offset by remember { mutableStateOf(Offset.Zero) }
|
||||||
Box(
|
val state = rememberTransformableState { zoomChange, offsetChange, _ ->
|
||||||
modifier = modifier
|
scale *= zoomChange
|
||||||
.fillMaxSize() // Give the size you want...
|
offset += offsetChange * scale
|
||||||
.background(Color.Gray)
|
|
||||||
.pointerInput(Unit) {
|
|
||||||
detectTransformGestures { _, _, zoom, rotation ->
|
|
||||||
scale.value *= zoom
|
|
||||||
rotationState.value += rotation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
NetworkImage(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.Center) // keep the image centralized into the Box
|
|
||||||
.graphicsLayer(
|
|
||||||
// adding some zoom limits (min 50%, max 200%)
|
|
||||||
scaleX = maxOf(.5f, minOf(3f, scale.value)),
|
|
||||||
scaleY = maxOf(.5f, minOf(3f, scale.value)),
|
|
||||||
rotationZ = rotationState.value
|
|
||||||
),
|
|
||||||
data = data,
|
|
||||||
shape = RectangleShape
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
NetworkImage(
|
||||||
|
modifier = modifier
|
||||||
|
.graphicsLayer(
|
||||||
|
scaleX = scale,
|
||||||
|
scaleY = scale,
|
||||||
|
translationX = offset.x,
|
||||||
|
translationY = offset.y
|
||||||
|
)
|
||||||
|
.transformable(state = state),
|
||||||
|
data = data,
|
||||||
|
shape = RectangleShape
|
||||||
|
)
|
||||||
}
|
}
|
@ -187,4 +187,6 @@
|
|||||||
<string name="prefs_new_apps">Number of new apps to show</string>
|
<string name="prefs_new_apps">Number of new apps to show</string>
|
||||||
<string name="new_repository">New repository</string>
|
<string name="new_repository">New repository</string>
|
||||||
<string name="default_tab">Default Tab</string>
|
<string name="default_tab">Default Tab</string>
|
||||||
|
<string name="pending">Pending</string>
|
||||||
|
<string name="installing">Installing</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user