diff --git a/src/main/kotlin/com/looker/droidify/entity/Enums.kt b/src/main/kotlin/com/looker/droidify/entity/Enums.kt
index 76b7ea61..44af78f5 100644
--- a/src/main/kotlin/com/looker/droidify/entity/Enums.kt
+++ b/src/main/kotlin/com/looker/droidify/entity/Enums.kt
@@ -12,4 +12,11 @@ enum class UpdateCategory(val id: Int) {
ALL(0),
UPDATED(1),
NEW(2)
+}
+
+enum class InstallState {
+ INSTALL,
+ INSTALLING,
+ INSTALLED,
+ PENDING
}
\ No newline at end of file
diff --git a/src/main/kotlin/com/looker/droidify/ui/compose/components/ProductCard.kt b/src/main/kotlin/com/looker/droidify/ui/compose/components/ProductCard.kt
index f22b2113..2c5e957c 100644
--- a/src/main/kotlin/com/looker/droidify/ui/compose/components/ProductCard.kt
+++ b/src/main/kotlin/com/looker/droidify/ui/compose/components/ProductCard.kt
@@ -36,7 +36,7 @@ fun ProductCard(
item.metadataIcon,
repo?.address,
repo?.authentication
- )
+ ).toString()
)
}
diff --git a/src/main/kotlin/com/looker/droidify/ui/compose/components/ProductsListItem.kt b/src/main/kotlin/com/looker/droidify/ui/compose/components/ProductsListItem.kt
index 6e78ed66..8ab827e9 100644
--- a/src/main/kotlin/com/looker/droidify/ui/compose/components/ProductsListItem.kt
+++ b/src/main/kotlin/com/looker/droidify/ui/compose/components/ProductsListItem.kt
@@ -40,7 +40,7 @@ fun ProductsListItem(
item.metadataIcon,
repo?.address,
repo?.authentication
- )
+ ).toString()
)
}
diff --git a/src/main/kotlin/com/looker/droidify/ui/compose/components/ScreenshotList.kt b/src/main/kotlin/com/looker/droidify/ui/compose/components/ScreenshotList.kt
index 4f01c1c9..87d98ddb 100644
--- a/src/main/kotlin/com/looker/droidify/ui/compose/components/ScreenshotList.kt
+++ b/src/main/kotlin/com/looker/droidify/ui/compose/components/ScreenshotList.kt
@@ -36,7 +36,7 @@ fun ScreenshotList(
.wrapContentWidth()
.requiredHeight(120.dp)
.clickable { onScreenShotClick(it) },
- data = it.path.toUri(),
+ data = it.path,
shape = RoundedCornerShape(LocalShapes.current.large)
)
}
diff --git a/src/main/kotlin/com/looker/droidify/ui/compose/pages/app_detail/AppDetail.kt b/src/main/kotlin/com/looker/droidify/ui/compose/pages/app_detail/AppDetail.kt
new file mode 100644
index 00000000..5c1003ae
--- /dev/null
+++ b/src/main/kotlin/com/looker/droidify/ui/compose/pages/app_detail/AppDetail.kt
@@ -0,0 +1,2 @@
+package com.looker.droidify.ui.compose.pages.app_detail
+
diff --git a/src/main/kotlin/com/looker/droidify/ui/compose/pages/app_detail/components/Header.kt b/src/main/kotlin/com/looker/droidify/ui/compose/pages/app_detail/components/Header.kt
new file mode 100644
index 00000000..7578bfa3
--- /dev/null
+++ b/src/main/kotlin/com/looker/droidify/ui/compose/pages/app_detail/components/Header.kt
@@ -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)
+ }
+ )
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/looker/droidify/ui/compose/utils/Image.kt b/src/main/kotlin/com/looker/droidify/ui/compose/utils/Image.kt
index 2c40c5a2..b3d4081c 100644
--- a/src/main/kotlin/com/looker/droidify/ui/compose/utils/Image.kt
+++ b/src/main/kotlin/com/looker/droidify/ui/compose/utils/Image.kt
@@ -1,37 +1,30 @@
package com.looker.droidify.ui.compose.utils
-import android.net.Uri
import androidx.compose.foundation.background
-import androidx.compose.foundation.gestures.detectTransformGestures
-import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.gestures.rememberTransformableState
+import androidx.compose.foundation.gestures.transformable
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
+import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
-import coil.annotation.ExperimentalCoilApi
import coil.compose.SubcomposeAsyncImage
import coil.compose.SubcomposeAsyncImageContent
import com.looker.droidify.R
import com.looker.droidify.ui.compose.theme.LocalShapes
-@OptIn(ExperimentalCoilApi::class)
@Composable
fun NetworkImage(
modifier: Modifier = Modifier,
- data: Uri?,
+ data: String?,
contentScale: ContentScale = ContentScale.Crop,
backgroundColor: Color = MaterialTheme.colorScheme.surface,
shape: Shape = RoundedCornerShape(LocalShapes.current.medium)
@@ -57,32 +50,24 @@ fun NetworkImage(
@Composable
fun ZoomableImage(
modifier: Modifier = Modifier,
- data: Uri?
+ data: String?,
) {
- val scale = remember { mutableStateOf(1f) }
- val rotationState = remember { mutableStateOf(1f) }
- Box(
- modifier = modifier
- .fillMaxSize() // Give the size you want...
- .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
- )
+ var scale by remember { mutableStateOf(1f) }
+ var offset by remember { mutableStateOf(Offset.Zero) }
+ val state = rememberTransformableState { zoomChange, offsetChange, _ ->
+ scale *= zoomChange
+ offset += offsetChange * scale
}
+ NetworkImage(
+ modifier = modifier
+ .graphicsLayer(
+ scaleX = scale,
+ scaleY = scale,
+ translationX = offset.x,
+ translationY = offset.y
+ )
+ .transformable(state = state),
+ data = data,
+ shape = RectangleShape
+ )
}
\ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index ba2ad79d..54484d9e 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -187,4 +187,6 @@
Number of new apps to show
New repository
Default Tab
+ Pending
+ Installing