Skip to content

Commit

Permalink
Jetlagged Home Screen - use Flows (#1435)
Browse files Browse the repository at this point in the history
Using FlowRow + FlowColumn combined with WindowSize classes to adapt
better to different device sizes.


![image](https://github.com/user-attachments/assets/2acc2f43-5cd5-435b-ac86-8e9aa78f4683)
  • Loading branch information
riggaroo authored Jul 25, 2024
2 parents 324bc6f + f54357a commit 2900c01
Show file tree
Hide file tree
Showing 26 changed files with 1,400 additions and 170 deletions.
7 changes: 6 additions & 1 deletion JetLagged/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ android {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
compose = true
// Disable unused AGP features
Expand Down Expand Up @@ -108,6 +110,8 @@ dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewModelCompose)
implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.constraintlayout.compose)
implementation(libs.google.android.material)
Expand All @@ -119,6 +123,7 @@ dependencies {
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.animation)
implementation(libs.androidx.compose.material.iconsExtended)
implementation(libs.androidx.compose.materialWindow)
implementation(libs.androidx.compose.ui.googlefonts)
implementation(libs.androidx.compose.ui.tooling.preview)
debugImplementation(libs.androidx.compose.ui.tooling)
Expand Down
2 changes: 2 additions & 0 deletions JetLagged/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:resizeableActivity="true"
android:theme="@style/Theme.JetLagged">

<profileable android:shell="true" tools:targetApi="q" />
Expand All @@ -31,6 +32,7 @@
android:name=".MainActivity"
android:theme="@style/Theme.JetLagged"
android:exported="true"
android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout|uiMode"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
281 changes: 281 additions & 0 deletions JetLagged/app/src/main/java/com/example/jetlagged/HomeScreenCards.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.jetlagged

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.SingleBed
import androidx.compose.material.icons.filled.Watch
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.Center
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Alignment.Companion.CenterStart
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.jetlagged.backgrounds.BubbleBackground
import com.example.jetlagged.backgrounds.FadingCircleBackground
import com.example.jetlagged.data.WellnessData
import com.example.jetlagged.ui.theme.HeadingStyle
import com.example.jetlagged.ui.theme.LightBlue
import com.example.jetlagged.ui.theme.Lilac
import com.example.jetlagged.ui.theme.MintGreen
import com.example.jetlagged.ui.theme.SmallHeadingStyle

@Composable
fun BasicInformationalCard(
modifier: Modifier = Modifier,
borderColor: Color,
content: @Composable () -> Unit
) {
val shape = RoundedCornerShape(24.dp)
Card(
shape = shape,
colors = CardDefaults.cardColors(containerColor = Color.White),
modifier = modifier
.padding(8.dp),
border = BorderStroke(2.dp, borderColor)
) {
Box {
content()
}
}
}

@Composable
fun TwoLineInfoCard(
borderColor: Color,
firstLineText: String,
secondLineText: String,
icon: ImageVector,
modifier: Modifier = Modifier
) {
BasicInformationalCard(
borderColor = borderColor,
modifier = modifier.size(200.dp)
) {
BubbleBackground(
modifier = Modifier.fillMaxSize(),
numberBubbles = 3, bubbleColor = borderColor.copy(0.25f)
)
BoxWithConstraints(
modifier = Modifier
.padding(16.dp)
.fillMaxSize(),
) {
if (maxWidth > 400.dp) {
Row(
modifier = Modifier
.wrapContentSize()
.align(CenterStart)
) {
Icon(
icon, contentDescription = null,
modifier = Modifier
.size(50.dp)
.align(CenterVertically)
)
Spacer(modifier = Modifier.width(16.dp))
Column(
modifier = Modifier
.align(CenterVertically)
.wrapContentSize()
) {
Text(
firstLineText,
style = SmallHeadingStyle
)
Text(
secondLineText,
style = HeadingStyle,
)
}
}
} else {
Column(
modifier = Modifier
.wrapContentSize()
.align(Center)
) {
Icon(
icon, contentDescription = null,
modifier = Modifier
.size(50.dp)
.align(CenterHorizontally)
)
Spacer(modifier = Modifier.height(16.dp))
Column(modifier = Modifier.align(CenterHorizontally)) {
Text(
firstLineText,
style = SmallHeadingStyle,
modifier = Modifier.align(CenterHorizontally)
)
Text(
secondLineText,
style = HeadingStyle,
modifier = Modifier.align(CenterHorizontally)
)
}
}
}
}
}
}

@Preview
@Preview(widthDp = 500, name = "larger screen")
@Composable
fun AverageTimeInBedCard(modifier: Modifier = Modifier) {
TwoLineInfoCard(
borderColor = Lilac,
firstLineText = stringResource(R.string.ave_time_in_bed_heading),
secondLineText = "8h42min",
icon = Icons.Default.Watch,
modifier = modifier
.wrapContentWidth()
.heightIn(min = 156.dp)
)
}

@Preview
@Preview(widthDp = 500, name = "larger screen")
@Composable
fun AverageTimeAsleepCard(modifier: Modifier = Modifier) {
TwoLineInfoCard(
borderColor = MintGreen,
firstLineText = stringResource(R.string.ave_time_sleep_heading),
secondLineText = "7h42min",
icon = Icons.Default.SingleBed,
modifier = modifier
.wrapContentWidth()
.heightIn(min = 156.dp)
)
}

@OptIn(ExperimentalLayoutApi::class)
@Preview
@Composable
fun WellnessCard(
modifier: Modifier = Modifier,
wellnessData: WellnessData = WellnessData(0, 0, 0)
) {
BasicInformationalCard(
borderColor = LightBlue,
modifier = modifier
.widthIn(max = 400.dp)
.heightIn(min = 200.dp)
) {
FadingCircleBackground(36.dp, LightBlue.copy(0.25f))
Column(
horizontalAlignment = CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
) {
HomeScreenCardHeading(text = stringResource(R.string.wellness_heading))
FlowRow(
horizontalArrangement = Arrangement.Center,
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxHeight()
) {
WellnessBubble(
titleText = stringResource(R.string.snoring_heading),
countText = wellnessData.snoring.toString(),
metric = "min"
)
WellnessBubble(
titleText = stringResource(R.string.coughing_heading),
countText = wellnessData.coughing.toString(),
metric = "times"
)
WellnessBubble(
titleText = stringResource(R.string.respiration_heading),
countText = wellnessData.respiration.toString(),
metric = "rpm"
)
}
}
}
}

@Composable
fun WellnessBubble(
titleText: String,
countText: String,
metric: String,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.padding(4.dp)
.sizeIn(maxHeight = 100.dp)
.aspectRatio(1f)
.drawBehind {
drawCircle(LightBlue)
},
verticalArrangement = Arrangement.Center,
horizontalAlignment = CenterHorizontally
) {
Text(titleText, fontSize = 12.sp)
Text(countText, fontSize = 36.sp)
Text(metric, fontSize = 12.sp)
}
}

@Composable
fun HomeScreenCardHeading(text: String) {
Text(
text,
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
textAlign = TextAlign.Center,
style = HeadingStyle
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -54,7 +56,8 @@ import androidx.compose.ui.util.lerp
import kotlinx.coroutines.launch

@Composable
fun HomeScreenDrawer() {
fun HomeScreenDrawer(windowSizeClass: WindowSizeClass) {

Surface(
modifier = Modifier.fillMaxSize()
) {
Expand Down Expand Up @@ -105,6 +108,7 @@ fun HomeScreenDrawer() {
})
val decay = rememberSplineBasedDecay<Float>()
ScreenContents(
windowWidthSizeClass = windowSizeClass.widthSizeClass,
selectedScreen = screenState,
onDrawerClicked = ::toggleDrawerState,
modifier = Modifier
Expand Down Expand Up @@ -166,6 +170,7 @@ fun HomeScreenDrawer() {

@Composable
private fun ScreenContents(
windowWidthSizeClass: WindowWidthSizeClass,
selectedScreen: Screen,
onDrawerClicked: () -> Unit,
modifier: Modifier = Modifier
Expand All @@ -174,6 +179,7 @@ private fun ScreenContents(
when (selectedScreen) {
Screen.Home ->
JetLaggedScreen(
windowSizeClass = windowWidthSizeClass,
modifier = Modifier,
onDrawerClicked = onDrawerClicked
)
Expand Down
Loading

0 comments on commit 2900c01

Please sign in to comment.