Increase use of space in detail view
This commit is contained in:
parent
644e547cb9
commit
c866bde5fa
5 changed files with 118 additions and 120 deletions
|
@ -8,7 +8,7 @@ buildscript {
|
|||
|
||||
dependencies {
|
||||
// keeping this here to allow AS to automatically update
|
||||
classpath("com.android.tools.build:gradle:7.0.2")
|
||||
classpath("com.android.tools.build:gradle:7.0.3")
|
||||
|
||||
with(Deps.Gradle) {
|
||||
classpath(kotlin)
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
package androidx.wear.compose.samples.shared
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.layout.LayoutModifier
|
||||
import androidx.compose.ui.layout.Measurable
|
||||
import androidx.compose.ui.layout.MeasureResult
|
||||
import androidx.compose.ui.layout.MeasureScope
|
||||
import androidx.compose.ui.platform.InspectorInfo
|
||||
import androidx.compose.ui.platform.InspectorValueInfo
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.debugInspectorInfo
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.constrainHeight
|
||||
import androidx.compose.ui.unit.constrainWidth
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.offset
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@Stable
|
||||
fun Modifier.fillMaxRectangle() = composed {
|
||||
val isRound = LocalContext.current.resources.configuration.isScreenRound
|
||||
|
||||
var inset: Dp = 0.dp
|
||||
|
||||
if (isRound) {
|
||||
val screenHeightDp = LocalContext.current.resources.configuration.screenHeightDp
|
||||
val screenWidthDp = LocalContext.current.resources.configuration.smallestScreenWidthDp
|
||||
val maxSquareEdge = (sqrt(((screenHeightDp * screenWidthDp) / 2).toDouble()))
|
||||
inset = Dp(((screenHeightDp - maxSquareEdge) / 2).toFloat())
|
||||
}
|
||||
this.then(RectangleInsetModifier(
|
||||
inset = inset,
|
||||
inspectorInfo = debugInspectorInfo {
|
||||
name = "fillMaxRectangle"
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private class RectangleInsetModifier(
|
||||
val inset: Dp = 0.dp,
|
||||
inspectorInfo: InspectorInfo.() -> Unit
|
||||
) : LayoutModifier, InspectorValueInfo(inspectorInfo) {
|
||||
init {
|
||||
require(
|
||||
(inset.value >= 0f || inset == Dp.Unspecified)
|
||||
) {
|
||||
"Inset must be non-negative"
|
||||
}
|
||||
}
|
||||
|
||||
override fun MeasureScope.measure(
|
||||
measurable: Measurable,
|
||||
constraints: Constraints
|
||||
): MeasureResult {
|
||||
|
||||
val totalOffsetInPx = inset.roundToPx() * 2
|
||||
|
||||
val placeable = measurable.measure(constraints.offset(-totalOffsetInPx, -totalOffsetInPx))
|
||||
|
||||
val width = constraints.constrainWidth(placeable.width + totalOffsetInPx)
|
||||
val height = constraints.constrainHeight(placeable.height + totalOffsetInPx)
|
||||
return layout(width, height) {
|
||||
placeable.place(inset.roundToPx(), inset.roundToPx())
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = inset.hashCode()
|
||||
result = 31 * result + inset.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
val otherModifier = other as? RectangleInsetModifier ?: return false
|
||||
return inset == otherModifier.inset
|
||||
}
|
||||
}
|
|
@ -5,18 +5,14 @@ import androidx.activity.ComponentActivity
|
|||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.navArgument
|
||||
import androidx.wear.compose.material.ExperimentalWearMaterialApi
|
||||
import androidx.wear.compose.navigation.SwipeDismissableNavHost
|
||||
import androidx.wear.compose.navigation.composable
|
||||
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
|
||||
import coil.ImageLoader
|
||||
import coil.compose.LocalImageLoader
|
||||
import com.surrus.common.repository.PeopleInSpaceRepositoryInterface
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
|
||||
sealed class Screen(val route: String) {
|
||||
object PersonList : Screen("personList")
|
||||
object PersonDetails : Screen("personDetails")
|
||||
|
|
|
@ -1,18 +1,38 @@
|
|||
package com.surrus.peopleinspace
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CutCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.wear.compose.material.ExperimentalWearMaterialApi
|
||||
import androidx.wear.compose.material.MaterialTheme
|
||||
import androidx.wear.compose.material.PositionIndicator
|
||||
import androidx.wear.compose.material.Scaffold
|
||||
import androidx.wear.compose.material.Text
|
||||
import androidx.wear.compose.samples.shared.fillMaxRectangle
|
||||
import coil.compose.rememberImagePainter
|
||||
import androidx.wear.compose.material.Vignette
|
||||
import androidx.wear.compose.material.VignettePosition
|
||||
import com.surrus.common.remote.Assignment
|
||||
import org.koin.androidx.compose.getViewModel
|
||||
|
||||
@Composable
|
||||
|
@ -28,41 +48,99 @@ fun PersonDetailsScreen(personName: String) {
|
|||
}
|
||||
}
|
||||
|
||||
PersonDetailsScreen(person)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalWearMaterialApi::class)
|
||||
@Composable
|
||||
private fun PersonDetailsScreen(person: Assignment?) {
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
person?.let { person ->
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.fillMaxRectangle()) {
|
||||
|
||||
MaterialTheme {
|
||||
Scaffold(
|
||||
vignette = {
|
||||
if (person != null) {
|
||||
Vignette(vignettePosition = VignettePosition.Bottom)
|
||||
}
|
||||
},
|
||||
positionIndicator = { PositionIndicator(scrollState = scrollState) }
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxWidth()
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = if (LocalConfiguration.current.isScreenRound) 18.dp else 8.dp)
|
||||
.verticalScroll(scrollState),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Spacer(modifier = Modifier.size(if (LocalConfiguration.current.isScreenRound) 32.dp else 12.dp))
|
||||
|
||||
Text(
|
||||
person.name,
|
||||
style = MaterialTheme.typography.body2,
|
||||
textAlign = TextAlign.Center
|
||||
Image(
|
||||
painter = rememberAstronautPainter(person),
|
||||
modifier = Modifier
|
||||
.size(120.dp)
|
||||
.clip(CutCornerShape(30.dp)),
|
||||
contentDescription = person?.name,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(12.dp))
|
||||
|
||||
val imageUrl = person.personImageUrl ?: ""
|
||||
if (imageUrl.isNotEmpty()) {
|
||||
Image(
|
||||
painter = rememberImagePainter(imageUrl),
|
||||
modifier = Modifier.size(120.dp), contentDescription = person.name
|
||||
Text(
|
||||
person?.name ?: "Astronaut not found.",
|
||||
style = MaterialTheme.typography.title1,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
val personBio = person?.personBio
|
||||
if (personBio != null) {
|
||||
Spacer(modifier = Modifier.size(12.dp))
|
||||
|
||||
Text(
|
||||
personBio,
|
||||
style = MaterialTheme.typography.body2,
|
||||
textAlign = TextAlign.Justify
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.size(24.dp))
|
||||
|
||||
val bio = person.personBio ?: ""
|
||||
Text(bio, style = MaterialTheme.typography.body1, textAlign = TextAlign.Center)
|
||||
Spacer(modifier = Modifier.size(if (LocalConfiguration.current.isScreenRound) 48.dp else 12.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(
|
||||
widthDp = 300,
|
||||
heightDp = 300,
|
||||
apiLevel = 26,
|
||||
uiMode = Configuration.UI_MODE_TYPE_WATCH,
|
||||
backgroundColor = 0x000000,
|
||||
showBackground = true
|
||||
)
|
||||
@Composable
|
||||
fun PersonDetailsScreenPreview() {
|
||||
val person = remember {
|
||||
Assignment(
|
||||
"Apollo 11",
|
||||
"Neil Armstrong",
|
||||
"https://www.biography.com/.image/ar_1:1%2Cc_fill%2Ccs_srgb%2Cfl_progressive%2Cq_auto:good%2Cw_1200/MTc5OTk0MjgyMzk5MTE0MzYy/gettyimages-150832381.jpg",
|
||||
"Mark Thomas Vande Hei (born November 10, 1966) is a retired United States Army officer and NASA astronaut who served as a flight Engineer for Expedition 53 and 54 on the International Space Station."
|
||||
)
|
||||
}
|
||||
Box(modifier = Modifier.background(Color.Black)) {
|
||||
PersonDetailsScreen(person)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(
|
||||
widthDp = 300,
|
||||
heightDp = 300,
|
||||
apiLevel = 26,
|
||||
uiMode = Configuration.UI_MODE_TYPE_WATCH,
|
||||
backgroundColor = 0x000000,
|
||||
showBackground = true
|
||||
)
|
||||
@Composable
|
||||
fun PersonDetailsScreenNotFoundPreview() {
|
||||
Box(modifier = Modifier.background(Color.Black)) {
|
||||
PersonDetailsScreen(null)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ import androidx.wear.compose.material.Text
|
|||
import coil.annotation.ExperimentalCoilApi
|
||||
import coil.compose.rememberImagePainter
|
||||
import com.surrus.common.remote.Assignment
|
||||
import com.surrus.common.repository.PeopleInSpaceRepositoryInterface
|
||||
import org.koin.androidx.compose.getViewModel
|
||||
|
||||
const val PersonListTag = "PersonList"
|
||||
|
@ -117,16 +116,7 @@ fun PersonView(person: Assignment, personSelected: (person: Assignment) -> Unit)
|
|||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
painter = rememberImagePainter(person.personImageUrl) {
|
||||
// Use the generic astronaut SVG for missing or error (404?).
|
||||
fallback(R.drawable.ic_american_astronaut)
|
||||
error(R.drawable.ic_american_astronaut)
|
||||
|
||||
if (LocalInspectionMode.current) {
|
||||
// Show error image instead of blank in @Preview
|
||||
placeholder(R.drawable.ic_american_astronaut)
|
||||
}
|
||||
},
|
||||
painter = rememberAstronautPainter(person),
|
||||
modifier = Modifier
|
||||
.size(50.dp)
|
||||
.clip(MaterialTheme.shapes.medium),
|
||||
|
@ -147,6 +137,20 @@ fun PersonView(person: Assignment, personSelected: (person: Assignment) -> Unit)
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
@Composable
|
||||
fun rememberAstronautPainter(person: Assignment?) =
|
||||
rememberImagePainter(person?.personImageUrl) {
|
||||
// Use the generic astronaut SVG for missing or error (404?).
|
||||
fallback(R.drawable.ic_american_astronaut)
|
||||
error(R.drawable.ic_american_astronaut)
|
||||
|
||||
if (LocalInspectionMode.current) {
|
||||
// Show error image instead of blank in @Preview
|
||||
placeholder(R.drawable.ic_american_astronaut)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(
|
||||
widthDp = 300,
|
||||
heightDp = 80,
|
||||
|
|
Loading…
Reference in a new issue