Skip to content

Commit 84fbb47

Browse files
committed
refactor: update feature-auth screen to compose
1 parent 9df76f4 commit 84fbb47

File tree

9 files changed

+302
-18
lines changed

9 files changed

+302
-18
lines changed

.idea/inspectionProfiles/Project_Default.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package co.anitrend.core.android.extensions
2+
3+
import android.graphics.drawable.AdaptiveIconDrawable
4+
import android.os.Build
5+
import androidx.annotation.DrawableRes
6+
import androidx.compose.runtime.Composable
7+
import androidx.compose.ui.graphics.asImageBitmap
8+
import androidx.compose.ui.graphics.painter.BitmapPainter
9+
import androidx.compose.ui.graphics.painter.Painter
10+
import androidx.compose.ui.platform.LocalContext
11+
import androidx.compose.ui.res.painterResource
12+
import androidx.core.content.res.ResourcesCompat
13+
import androidx.core.graphics.drawable.toBitmap
14+
15+
/**
16+
* [Source](https://gist.github.com/tkuenneth/ddf598663f041dc79960cda503d14448?permalink_comment_id=4660486#gistcomment-4660486)
17+
*/
18+
@Composable
19+
fun adaptiveIconPainterResource(@DrawableRes id: Int): Painter {
20+
val res = LocalContext.current.resources
21+
val theme = LocalContext.current.theme
22+
23+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
24+
// Android O supports adaptive icons, try loading this first (even though this is least likely to be the format).
25+
val adaptiveIcon = ResourcesCompat.getDrawable(res, id, theme) as? AdaptiveIconDrawable
26+
if (adaptiveIcon != null) {
27+
BitmapPainter(adaptiveIcon.toBitmap().asImageBitmap())
28+
} else {
29+
// We couldn't load the drawable as an Adaptive Icon, just use painterResource
30+
painterResource(id)
31+
}
32+
} else {
33+
// We're not on Android O or later, just use painterResource
34+
painterResource(id)
35+
}
36+
}

app-navigation/src/main/kotlin/co/anitrend/navigation/model/common/IParam.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package co.anitrend.navigation.model.common
1919

2020
import android.os.Parcelable
21+
import kotlinx.parcelize.Parcelize
2122

2223
/**
2324
* Parameter contract
@@ -31,4 +32,7 @@ interface IParam : Parcelable {
3132
@Suppress("PropertyName")
3233
val KEY: String
3334
}
34-
}
35+
36+
@Parcelize
37+
data class None(override val idKey: String = "") : IParam
38+
}

feature-auth/src/main/AndroidManifest.xml

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
</intent>
2525
<intent>
2626
<action android:name="android.intent.action.VIEW" />
27-
<!--suppress AndroidElementNotAllowed -->
2827
<category android:name="android.intent.category.BROWSABLE" />
2928
<data android:scheme="https" />
3029
</intent>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package co.anitrend.auth.component.compose
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.Spacer
7+
import androidx.compose.foundation.layout.fillMaxSize
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.foundation.rememberScrollState
10+
import androidx.compose.foundation.verticalScroll
11+
import androidx.compose.material.icons.Icons
12+
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
13+
import androidx.compose.material.icons.rounded.AccountCircle
14+
import androidx.compose.material.icons.twotone.Info
15+
import androidx.compose.material.icons.twotone.NoAccounts
16+
import androidx.compose.material3.BottomAppBar
17+
import androidx.compose.material3.FilledTonalButton
18+
import androidx.compose.material3.Icon
19+
import androidx.compose.material3.IconButton
20+
import androidx.compose.material3.Scaffold
21+
import androidx.compose.material3.Snackbar
22+
import androidx.compose.material3.SnackbarHost
23+
import androidx.compose.material3.SnackbarHostState
24+
import androidx.compose.material3.SuggestionChip
25+
import androidx.compose.material3.Text
26+
import androidx.compose.runtime.Composable
27+
import androidx.compose.runtime.LaunchedEffect
28+
import androidx.compose.runtime.livedata.observeAsState
29+
import androidx.compose.runtime.remember
30+
import androidx.compose.runtime.rememberCoroutineScope
31+
import androidx.compose.ui.Alignment
32+
import androidx.compose.ui.Modifier
33+
import androidx.compose.ui.res.colorResource
34+
import androidx.compose.ui.res.stringResource
35+
import androidx.compose.ui.text.style.TextAlign
36+
import androidx.compose.ui.unit.dp
37+
import co.anitrend.auth.component.viewmodel.state.AuthState
38+
import co.anitrend.core.android.ui.AniTrendPreview
39+
import co.anitrend.core.android.ui.theme.AniTrendTheme3
40+
import co.anitrend.core.android.ui.typography.AniTrendTypography
41+
import kotlinx.coroutines.launch
42+
43+
@Composable
44+
private fun AuthBrandNameComponent(modifier: Modifier = Modifier) {
45+
Row(modifier = modifier) {
46+
Text(
47+
text = stringResource(co.anitrend.auth.R.string.auth_label_segment_first),
48+
style = AniTrendTypography.displayMedium,
49+
)
50+
Text(
51+
text = stringResource(co.anitrend.auth.R.string.auth_label_segment_second),
52+
style = AniTrendTypography.displayMedium.copy(
53+
color = colorResource(co.anitrend.arch.theme.R.color.colorStateBlue)
54+
),
55+
56+
)
57+
}
58+
}
59+
60+
@Composable
61+
private fun AuthHeaderSection(modifier: Modifier = Modifier) {
62+
Column(
63+
modifier = modifier.padding(top = 16.dp),
64+
horizontalAlignment = Alignment.CenterHorizontally
65+
) {
66+
AuthBrandNameComponent()
67+
Spacer(modifier = Modifier.padding(top = 8.dp))
68+
Text(text = stringResource(co.anitrend.auth.R.string.label_allow_authorization))
69+
}
70+
}
71+
72+
@Composable
73+
private fun AuthAuthorizationSection(
74+
onAuthorizeClick: () -> Unit,
75+
onAuthorizationHelpClick: () -> Unit,
76+
modifier: Modifier = Modifier
77+
) {
78+
Column(
79+
modifier = modifier.padding(top = 16.dp),
80+
horizontalAlignment = Alignment.CenterHorizontally
81+
) {
82+
FilledTonalButton(
83+
onClick = onAuthorizeClick,
84+
) {
85+
Icon(imageVector = Icons.Rounded.AccountCircle, contentDescription = null)
86+
Spacer(modifier = Modifier.padding(start = 6.dp))
87+
Text(text = stringResource(co.anitrend.auth.R.string.auth_label_authorize))
88+
}
89+
Spacer(modifier = Modifier.padding(top = 8.dp))
90+
SuggestionChip(
91+
onClick = onAuthorizationHelpClick,
92+
label = {
93+
Text(text = stringResource(co.anitrend.auth.R.string.auth_label_having_trouble_logging_in))
94+
},
95+
icon = { Icon(imageVector = Icons.TwoTone.Info, contentDescription = null) }
96+
)
97+
}
98+
}
99+
100+
@Composable
101+
private fun AuthAnonymousSection(modifier: Modifier = Modifier) {
102+
Column(
103+
modifier = modifier.padding(top = 16.dp),
104+
horizontalAlignment = Alignment.CenterHorizontally
105+
) {
106+
Text(
107+
text = stringResource(co.anitrend.auth.R.string.auth_label_alternative_account),
108+
textAlign = TextAlign.Center,
109+
style = AniTrendTypography.labelMedium,
110+
)
111+
Spacer(modifier = Modifier.padding(top = 8.dp))
112+
SuggestionChip(
113+
onClick = {},
114+
label = {
115+
Text(text = stringResource(co.anitrend.auth.R.string.auth_label_action_start_anonymous_account))
116+
},
117+
icon = { Icon(imageVector = Icons.TwoTone.NoAccounts, contentDescription = null) }
118+
)
119+
}
120+
}
121+
122+
@Composable
123+
private fun AuthContent(
124+
onAuthorizeClick: () -> Unit,
125+
onAuthorizationHelpClick: () -> Unit,
126+
modifier: Modifier = Modifier,
127+
) {
128+
Column(
129+
verticalArrangement = Arrangement.Center,
130+
horizontalAlignment = Alignment.CenterHorizontally,
131+
modifier = modifier.then(Modifier.padding(start = 48.dp, end = 48.dp)),
132+
) {
133+
AuthHeaderSection()
134+
Spacer(modifier = Modifier.padding(top = 24.dp))
135+
AuthAuthorizationSection(onAuthorizeClick, onAuthorizationHelpClick)
136+
Spacer(modifier = Modifier.padding(top = 24.dp))
137+
AuthAnonymousSection()
138+
}
139+
}
140+
141+
@Composable
142+
private fun AuthBottomAppBar(onBackPress: () -> Unit) {
143+
BottomAppBar(
144+
actions = {
145+
IconButton(onClick = onBackPress) {
146+
Icon(
147+
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
148+
contentDescription = "Back"
149+
)
150+
}
151+
}
152+
)
153+
}
154+
155+
@Composable
156+
fun AuthScreenContent(
157+
authState: AuthState,
158+
onAuthorizeClick: () -> Unit,
159+
onAuthorizationHelpClick: () -> Unit,
160+
onBackPress: () -> Unit
161+
) {
162+
val snackbarHostState = remember { SnackbarHostState() }
163+
val state = authState.model.observeAsState()
164+
165+
Scaffold(
166+
bottomBar = {
167+
AuthBottomAppBar(onBackPress = onBackPress)
168+
},
169+
snackbarHost = {
170+
SnackbarHost(hostState = snackbarHostState)
171+
},
172+
modifier = Modifier
173+
) { innerPadding ->
174+
AuthContent(
175+
onAuthorizeClick,
176+
onAuthorizationHelpClick,
177+
modifier = Modifier.padding(innerPadding)
178+
.fillMaxSize()
179+
.verticalScroll(rememberScrollState())
180+
)
181+
}
182+
}
183+
184+
185+
@AniTrendPreview.Mobile
186+
@AniTrendPreview.Light
187+
@AniTrendPreview.Dark
188+
@Composable
189+
private fun MediaDetailComponentPreview() {
190+
AniTrendTheme3 {
191+
AuthContent(
192+
onAuthorizeClick = {},
193+
onAuthorizationHelpClick = {}
194+
)
195+
}
196+
}

feature-auth/src/main/kotlin/co/anitrend/auth/component/content/AuthContent.kt

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class AuthContent(
131131
viewModelState().model.observeOnce(viewLifecycleOwner) { user ->
132132
runCatching {
133133
presenter.runSignInWorker(user.id)
134+
closeScreen()
134135
}.onFailure {
135136
Snackbar.make(
136137
requireView(),

0 commit comments

Comments
 (0)