Skip to content

Commit c707e02

Browse files
committed
Add Welcome, Log in and Home screen
1 parent 36afb52 commit c707e02

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1184
-181
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ proguard-project.txt
4444
.idea/inspectionProfiles/profiles_settings.xml
4545
.idea/inspectionProfiles/ktlint.xml
4646
.idea/modules.xml
47+
.idea/inspectionProfiles/Project_Default.xml

.issuetracker

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Integration with Issue Tracker
2+
#
3+
# (note that '\' need to be escaped).
4+
5+
[issuetracker "GitHub Rule"]
6+
regex = "#(\\d+)"
7+
url = "https://github.com/opatry/android-dev-challenge-compose-week3-EMEA/issues/$1"

app/build.gradle

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,23 @@ dependencies {
9090
implementation 'androidx.appcompat:appcompat:1.3.0-beta01'
9191
implementation 'com.google.android.material:material:1.3.0'
9292

93-
implementation "androidx.activity:activity-compose:1.3.0-alpha03"
93+
implementation "androidx.activity:activity-compose:1.3.0-alpha04"
9494

9595
implementation "androidx.compose.ui:ui:$compose_version"
9696
implementation "androidx.compose.material:material:$compose_version"
9797
implementation "androidx.compose.material:material-icons-extended:$compose_version"
9898
implementation "androidx.compose.ui:ui-tooling:$compose_version"
9999
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
100100

101-
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha02"
101+
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha03"
102102
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0'
103103
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0'
104104
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0'
105105

106-
implementation "androidx.navigation:navigation-compose:1.0.0-alpha08"
106+
implementation "androidx.navigation:navigation-compose:1.0.0-alpha09"
107107

108108
implementation "dev.chrisbanes.accompanist:accompanist-coil:0.6.1"
109+
implementation "dev.chrisbanes.accompanist:accompanist-insets:0.6.1"
109110

110111
testImplementation 'junit:junit:4.13.2'
111112

app/src/main/java/net/opatry/speedrun/emea/MainActivity.kt

Lines changed: 61 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -22,122 +22,97 @@
2222
package net.opatry.speedrun.emea
2323

2424
import android.os.Bundle
25+
import android.util.Config
2526
import androidx.activity.compose.setContent
26-
import androidx.annotation.StringRes
2727
import androidx.appcompat.app.AppCompatActivity
28-
import androidx.compose.foundation.layout.Column
29-
import androidx.compose.foundation.layout.padding
30-
import androidx.compose.material.BottomNavigation
31-
import androidx.compose.material.BottomNavigationItem
32-
import androidx.compose.material.Card
33-
import androidx.compose.material.ContentAlpha
34-
import androidx.compose.material.Icon
35-
import androidx.compose.material.LocalContentColor
28+
import androidx.compose.foundation.Canvas
29+
import androidx.compose.foundation.ExperimentalFoundationApi
30+
import androidx.compose.foundation.layout.fillMaxSize
3631
import androidx.compose.material.MaterialTheme
37-
import androidx.compose.material.Scaffold
3832
import androidx.compose.material.Surface
39-
import androidx.compose.material.Text
40-
import androidx.compose.material.icons.Icons
41-
import androidx.compose.material.icons.filled.AccountCircle
42-
import androidx.compose.material.icons.filled.PlayArrow
43-
import androidx.compose.material.icons.filled.Search
44-
import androidx.compose.material.icons.filled.Spa
4533
import androidx.compose.runtime.Composable
4634
import androidx.compose.runtime.mutableStateOf
4735
import androidx.compose.runtime.remember
4836
import androidx.compose.ui.Modifier
49-
import androidx.compose.ui.graphics.vector.ImageVector
50-
import androidx.compose.ui.res.stringResource
51-
import androidx.compose.ui.tooling.preview.Preview
37+
import androidx.compose.ui.geometry.Offset
38+
import androidx.compose.ui.graphics.Color
39+
import androidx.compose.ui.res.booleanResource
5240
import androidx.compose.ui.unit.dp
53-
import net.opatry.speedrun.emea.ui.theme.MyTheme
41+
import androidx.core.view.WindowCompat
42+
import dev.chrisbanes.accompanist.insets.ProvideWindowInsets
43+
import net.opatry.speedrun.emea.ui.home.HomeScreen
44+
import net.opatry.speedrun.emea.ui.welcome.LoginScreen
45+
import net.opatry.speedrun.emea.ui.welcome.WelcomeScreen
46+
import net.opatry.speedrun.emea.ui.theme.MySootheTheme
5447

48+
@ExperimentalFoundationApi
5549
class MainActivity : AppCompatActivity() {
5650
override fun onCreate(savedInstanceState: Bundle?) {
5751
super.onCreate(savedInstanceState)
52+
// This app draws behind the system bars, so we want to handle fitting system windows
53+
WindowCompat.setDecorFitsSystemWindows(window, false)
5854
setContent {
59-
MyTheme {
55+
MySootheTheme {
6056
MySootheApp()
6157
}
6258
}
6359
}
6460
}
6561

66-
private enum class MainTabs(
67-
@StringRes val titleRes: Int,
68-
val icon: ImageVector
69-
) {
70-
Home(R.string.nav_home, Icons.Default.Spa),
71-
// FIXME FAB
72-
Run(R.string.nav_run, Icons.Default.PlayArrow),
73-
Profile(R.string.nav_profile, Icons.Default.AccountCircle)
62+
enum class AppState {
63+
OnBoarding,
64+
Login,
65+
Home
7466
}
7567

68+
@ExperimentalFoundationApi
7669
@Composable
77-
fun MySootheApp(signedIn: Boolean = true) {
78-
if (!signedIn) {
79-
LoginScreen()
80-
} else {
81-
MainScreen()
82-
}
83-
}
84-
85-
@Composable
86-
fun LoginScreen() {
87-
Text("TODO LOGIN")
88-
}
89-
90-
@Composable
91-
fun MainScreen() {
92-
93-
val (selectedTab, setSelectedTab) = remember { mutableStateOf(MainTabs.Home) }
94-
val tabs = MainTabs.values()
95-
96-
Surface(color = MaterialTheme.colors.background) {
97-
Scaffold(
98-
topBar = {},
99-
bottomBar = {
100-
BottomNavigation(
101-
backgroundColor = MaterialTheme.colors.background,
102-
elevation = 8.dp
103-
) {
104-
tabs.forEach { navItem ->
105-
BottomNavigationItem(
106-
icon = { Icon(navItem.icon, null) },
107-
label = { Text(stringResource(navItem.titleRes)) },
108-
selected = selectedTab == navItem,
109-
selectedContentColor = MaterialTheme.colors.onBackground,
110-
unselectedContentColor = MaterialTheme.colors.onBackground.copy(alpha = ContentAlpha.medium),
111-
onClick = { setSelectedTab(navItem) }
112-
)
70+
fun MySootheApp() {
71+
ProvideWindowInsets {
72+
MySootheTheme {
73+
Surface(color = MaterialTheme.colors.background) {
74+
val (appState, setAppState) = remember { mutableStateOf(AppState.OnBoarding) }
75+
when (appState) {
76+
AppState.OnBoarding -> WelcomeScreen {
77+
setAppState(AppState.Login)
11378
}
79+
AppState.Login -> LoginScreen {
80+
setAppState(AppState.Home)
81+
}
82+
AppState.Home -> HomeScreen()
11483
}
115-
}
116-
) {
117-
Card(Modifier.padding(24.dp)) {
118-
Column {
119-
Icon(Icons.Default.Search, null)
120-
Icon(Icons.Default.Spa, null)
121-
Icon(Icons.Default.AccountCircle, null)
122-
Icon(Icons.Default.PlayArrow, null)
84+
val showGrid = true // TODO booleanResource(id = R.bool.is_debug)
85+
if (showGrid) {
86+
GridLayer()
12387
}
12488
}
12589
}
12690
}
12791
}
12892

129-
@Preview("Light Theme", widthDp = 360, heightDp = 640)
13093
@Composable
131-
fun LightPreview() {
132-
MyTheme {
133-
MySootheApp()
134-
}
135-
}
136-
137-
@Preview("Dark Theme", widthDp = 360, heightDp = 640)
138-
@Composable
139-
fun DarkPreview() {
140-
MyTheme(darkTheme = true) {
141-
MySootheApp()
94+
fun GridLayer() {
95+
val offset = 8.dp
96+
Canvas(Modifier.fillMaxSize()) {
97+
var x = 0f
98+
while (x < size.width) {
99+
drawLine(
100+
start = Offset(x, 0f),
101+
end = Offset(x, size.height),
102+
strokeWidth = 1f,
103+
color = Color.Red.copy(alpha = .3f),
104+
)
105+
x += offset.toPx()
106+
}
107+
var y = 0f
108+
while (y < size.height) {
109+
drawLine(
110+
start = Offset(0f, y),
111+
end = Offset(size.width, y),
112+
strokeWidth = 1f,
113+
color = Color.Red.copy(alpha = .3f),
114+
)
115+
y += offset.toPx()
116+
}
142117
}
143-
}
118+
}

app/src/main/java/net/opatry/speedrun/emea/data/MySootheCollections.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,33 @@
2222

2323
package net.opatry.speedrun.emea.data
2424

25+
import net.opatry.speedrun.emea.R
26+
import net.opatry.speedrun.emea.model.MySootheActivity
27+
import net.opatry.speedrun.emea.model.MySootheCollection
28+
29+
val mySootheCollections = listOf(
30+
MySootheCollection(R.string.short_mantras, R.drawable.pexels_damir_mijailovic_3578336),
31+
MySootheCollection(R.string.nature_meditations, R.drawable.pexels_nothing_ahead_3571551),
32+
MySootheCollection(R.string.stress_and_anxiety, R.drawable.pexels_jim_1557238),
33+
MySootheCollection(R.string.self_massage, R.drawable.pexels_scott_webb_1029604),
34+
MySootheCollection(R.string.overwhelmed, R.drawable.pexels_ruvim_3560044),
35+
MySootheCollection(R.string.nightly_wind_down, R.drawable.pexels_jakub_novacek_924824),
36+
)
37+
38+
val mySootheBodyActivities = listOf(
39+
MySootheActivity.BodyActivity(R.string.inversions, R.drawable.pexels_chevanon_photography_317157),
40+
MySootheActivity.BodyActivity(R.string.quick_yoga, R.drawable.pexels_agung_pandit_wiguna_1812964),
41+
MySootheActivity.BodyActivity(R.string.stretching, R.drawable.pexels_cliff_booth_4056723),
42+
MySootheActivity.BodyActivity(R.string.tabata, R.drawable.pexels_elly_fairytale_4662438),
43+
MySootheActivity.BodyActivity(R.string.hiit, R.drawable.pexels_the_lazy_artist_gallery_999309),
44+
MySootheActivity.BodyActivity(R.string.pre_natal_yoga, R.drawable.pexels_freestocksorg_396133),
45+
)
46+
47+
val mySootheMindActivities = listOf(
48+
MySootheActivity.MindActivity(R.string.meditate, R.drawable.pexels_elly_fairytale_3822622),
49+
MySootheActivity.MindActivity(R.string.with_kids, R.drawable.pexels_valeria_ushakova_3094230),
50+
MySootheActivity.MindActivity(R.string.aromatherapy, R.drawable.pexels_karolina_grabowska_4498318),
51+
MySootheActivity.MindActivity(R.string.on_the_go, R.drawable.pexels_suraphat_nueaon_1241348),
52+
MySootheActivity.MindActivity(R.string.with_pets, R.drawable.pexels_cottonbro_4056535),
53+
MySootheActivity.MindActivity(R.string.high_stress, R.drawable.pexels_nathan_cowley_897817),
54+
)

app/src/main/java/net/opatry/speedrun/emea/model/Collection.kt renamed to app/src/main/java/net/opatry/speedrun/emea/model/MySootheModel.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222

2323
package net.opatry.speedrun.emea.model
2424

25-
data class Collection(val name: String, val pictureUrl: String)
25+
import androidx.annotation.DrawableRes
26+
import androidx.annotation.StringRes
2627

27-
sealed class MySootheActivity(val name: String, val pictureUrl: String) {
28-
class BodyActivity(name: String, pictureUrl: String) : MySootheActivity(name, pictureUrl)
29-
class MindActivity(name: String, pictureUrl: String) : MySootheActivity(name, pictureUrl)
28+
data class MySootheCollection(@StringRes val name: Int, @DrawableRes val picture: Int)
29+
30+
sealed class MySootheActivity(@StringRes val name: Int, @DrawableRes val picture: Int) {
31+
class BodyActivity(@StringRes name: Int, @DrawableRes picture: Int) : MySootheActivity(name, picture)
32+
class MindActivity(@StringRes name: Int, @DrawableRes picture: Int) : MySootheActivity(name, picture)
3033
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2021 Olivier Patry
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the Software
9+
* is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20+
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
*/
22+
23+
package net.opatry.speedrun.emea.ui.component
24+
25+
import androidx.compose.foundation.layout.Box
26+
import androidx.compose.foundation.layout.fillMaxSize
27+
import androidx.compose.foundation.layout.fillMaxWidth
28+
import androidx.compose.foundation.layout.size
29+
import androidx.compose.material.Icon
30+
import androidx.compose.material.LocalTextStyle
31+
import androidx.compose.material.MaterialTheme
32+
import androidx.compose.material.Text
33+
import androidx.compose.material.TextField
34+
import androidx.compose.material.TextFieldDefaults
35+
import androidx.compose.material.icons.Icons
36+
import androidx.compose.material.icons.filled.Search
37+
import androidx.compose.runtime.Composable
38+
import androidx.compose.runtime.getValue
39+
import androidx.compose.runtime.mutableStateOf
40+
import androidx.compose.runtime.remember
41+
import androidx.compose.runtime.setValue
42+
import androidx.compose.ui.Alignment
43+
import androidx.compose.ui.Modifier
44+
import androidx.compose.ui.res.stringResource
45+
import androidx.compose.ui.tooling.preview.Preview
46+
import androidx.compose.ui.unit.dp
47+
import net.opatry.speedrun.emea.R
48+
49+
@Composable
50+
fun SearchComponent(modifier: Modifier = Modifier) {
51+
var query by remember { mutableStateOf("") }
52+
TextField(value = query,
53+
onValueChange = { query = it },
54+
modifier.fillMaxWidth(),
55+
maxLines = 1,
56+
colors = TextFieldDefaults.textFieldColors(backgroundColor = MaterialTheme.colors.surface),
57+
leadingIcon = {
58+
Icon(
59+
Icons.Default.Search,
60+
null,
61+
Modifier.size(18.dp)
62+
)
63+
},
64+
placeholder = {
65+
Box(
66+
Modifier.fillMaxSize(),
67+
contentAlignment = Alignment.CenterStart
68+
) {
69+
// TODO replicate text style
70+
Text(stringResource(R.string.search), style = LocalTextStyle.current)
71+
}
72+
})
73+
}
74+
75+
@Preview("Light Theme", widthDp = 360, heightDp = 640)
76+
@Composable
77+
private fun SearchComponentLightPreview() {
78+
SearchComponent()
79+
}
80+
81+
@Preview("Light Theme", widthDp = 360, heightDp = 640)
82+
@Composable
83+
private fun SearchComponentDarkPreview() {
84+
SearchComponent()
85+
}

0 commit comments

Comments
 (0)