Skip to content

Commit da5aaf6

Browse files
authored
Merge pull request #240 from fmasa/drop-anonymous-auth
Remove fallback to anonymous auth
2 parents 53af18b + ddfac7a commit da5aaf6

File tree

8 files changed

+91
-86
lines changed

8 files changed

+91
-86
lines changed
Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package cz.muni.fi.rpg.ui.startup
22

33
import androidx.activity.compose.rememberLauncherForActivityResult
4-
import androidx.compose.material.AlertDialog
4+
import androidx.compose.foundation.Image
5+
import androidx.compose.foundation.layout.Arrangement
6+
import androidx.compose.foundation.layout.Box
7+
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.material.Button
59
import androidx.compose.material.Text
6-
import androidx.compose.material.TextButton
710
import androidx.compose.runtime.Composable
811
import androidx.compose.runtime.LaunchedEffect
912
import androidx.compose.runtime.getValue
@@ -13,65 +16,96 @@ import androidx.compose.runtime.remember
1316
import androidx.compose.runtime.rememberCoroutineScope
1417
import androidx.compose.runtime.saveable.rememberSaveable
1518
import androidx.compose.runtime.setValue
19+
import androidx.compose.ui.Alignment
1620
import androidx.compose.ui.platform.LocalContext
21+
import androidx.compose.ui.unit.dp
1722
import com.google.android.gms.auth.api.signin.GoogleSignIn
1823
import cz.frantisekmasa.wfrp_master.common.Str
1924
import cz.frantisekmasa.wfrp_master.common.auth.AuthenticationManager
2025
import cz.frantisekmasa.wfrp_master.common.auth.LocalWebClientId
21-
import cz.frantisekmasa.wfrp_master.common.core.shared.SettingsStorage
22-
import cz.frantisekmasa.wfrp_master.common.core.shared.edit
26+
import cz.frantisekmasa.wfrp_master.common.core.shared.Resources
27+
import cz.frantisekmasa.wfrp_master.common.core.shared.drawableResource
2328
import cz.frantisekmasa.wfrp_master.common.core.ui.flow.collectWithLifecycle
24-
import cz.frantisekmasa.wfrp_master.common.settings.AppSettings
29+
import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.VisualOnlyIconDescription
2530
import cz.frantisekmasa.wfrp_master.common.shell.SplashScreen
2631
import dev.icerock.moko.resources.compose.stringResource
2732
import io.github.aakira.napier.Napier
2833
import kotlinx.coroutines.Dispatchers
2934
import kotlinx.coroutines.launch
3035
import kotlinx.coroutines.tasks.await
3136
import kotlinx.coroutines.withContext
32-
import org.kodein.di.compose.localDI
33-
import org.kodein.di.instance
3437

3538
@Composable
36-
fun StartupScreen(authenticationManager: AuthenticationManager) {
37-
SplashScreen()
39+
fun StartupScreen(authenticationManager: AuthenticationManager): Unit = Box {
40+
41+
var signInButtonVisible by rememberSaveable { mutableStateOf(false) }
3842

3943
val authenticated by authenticationManager.authenticated.collectWithLifecycle()
4044

4145
Napier.d("Authenticated: $authenticated")
4246

4347
if (authenticated != false) {
48+
SplashScreen()
4449
// We could not determine whether user is logged in yet or there is delay between
4550
// recompositions (user is already authenticated, but startup screen is still visible)
4651
return
4752
}
4853

49-
val coroutineScope = rememberCoroutineScope()
54+
val webClientId = LocalWebClientId.current
55+
val context = LocalContext.current
5056

51-
var showAnonymousAuthenticationDialog by rememberSaveable { mutableStateOf(false) }
57+
val startGoogleSignInFlow = rememberGoogleSignInLauncher(
58+
authenticationManager = authenticationManager,
59+
onFailure = { signInButtonVisible = true },
60+
)
5261

53-
if (showAnonymousAuthenticationDialog) {
54-
val settings: SettingsStorage by localDI().instance()
62+
LaunchedEffect(Unit) {
63+
withContext(Dispatchers.Default) {
64+
// If user signed in via Google before, try to sign in him directly
65+
if (authenticationManager.attemptToRestoreExistingGoogleSignIn(context, webClientId)) {
66+
return@withContext
67+
}
68+
69+
withContext(Dispatchers.Main) { startGoogleSignInFlow() }
70+
}
71+
}
5572

56-
AnonymousAuthenticationExplanationDialog(
57-
onDismissRequest = {
58-
coroutineScope.launch {
59-
settings.edit(AppSettings.GOOGLE_SIGN_IN_DISMISSED, true)
60-
authenticationManager.authenticateAnonymously()
73+
if (signInButtonVisible) {
74+
SplashScreen {
75+
Button(
76+
onClick = startGoogleSignInFlow
77+
) {
78+
Row(
79+
verticalAlignment = Alignment.CenterVertically,
80+
horizontalArrangement = Arrangement.spacedBy(4.dp)
81+
) {
82+
Image(
83+
drawableResource(Resources.Drawable.GoogleLogo),
84+
VisualOnlyIconDescription,
85+
)
86+
Text(stringResource(Str.authentication_button_sign_in))
6187
}
62-
showAnonymousAuthenticationDialog = false
6388
}
64-
)
89+
}
90+
} else {
91+
SplashScreen()
6592
}
93+
}
6694

67-
val context = LocalContext.current
95+
@Composable
96+
private fun rememberGoogleSignInLauncher(
97+
authenticationManager: AuthenticationManager,
98+
onFailure: () -> Unit,
99+
): () -> Unit {
68100
val webClientId = LocalWebClientId.current
69101
val contract = remember(authenticationManager, webClientId) { authenticationManager.googleSignInContract(webClientId) }
70-
val googleSignInLauncher = key(contract, coroutineScope) {
71-
rememberLauncherForActivityResult(contract) { result ->
102+
val coroutineScope = rememberCoroutineScope()
103+
104+
return key(contract, coroutineScope) {
105+
val launcher = rememberLauncherForActivityResult(contract) { result ->
72106
if (result.resultCode == 0) {
73107
Napier.d("Google Sign-In dialog was dismissed")
74-
showAnonymousAuthenticationDialog = true
108+
onFailure()
75109
return@rememberLauncherForActivityResult
76110
}
77111

@@ -82,35 +116,21 @@ fun StartupScreen(authenticationManager: AuthenticationManager) {
82116
.idToken
83117
?.let { idToken -> authenticationManager.signInWithGoogleToken(idToken) }
84118
} catch (e: Throwable) {
85-
showAnonymousAuthenticationDialog = true
119+
onFailure()
86120
}
87121
}
88122
}
89-
}
90123

91-
LaunchedEffect(null) {
92-
withContext(Dispatchers.Default) {
93-
// If user signed in via Google before, try to sign in him directly
94-
if (authenticationManager.attemptToRestoreExistingGoogleSignIn(context, webClientId)) {
95-
return@withContext
124+
return@key remember(launcher, onFailure) {
125+
{
126+
try {
127+
launcher.launch(GoogleSignInCode)
128+
} catch (e: Throwable) {
129+
onFailure()
130+
}
96131
}
97-
98-
withContext(Dispatchers.Main) { googleSignInLauncher.launch(GoogleSignInCode) }
99132
}
100133
}
101134
}
102135

103-
@Composable
104-
private fun AnonymousAuthenticationExplanationDialog(onDismissRequest: () -> Unit) {
105-
AlertDialog(
106-
onDismissRequest = onDismissRequest,
107-
text = { Text(stringResource(Str.authentication_startup_google_sign_in_failed)) },
108-
confirmButton = {
109-
TextButton(onClick = onDismissRequest) {
110-
Text(stringResource(Str.common_ui_button_ok).uppercase())
111-
}
112-
}
113-
)
114-
}
115-
116136
private const val GoogleSignInCode = 100

common/src/androidMain/kotlin/cz/frantisekmasa/wfrp_master/common/auth/AuthenticationManager.kt

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -142,24 +142,6 @@ class AuthenticationManager(private val auth: FirebaseAuth) : UserProvider {
142142
}
143143
}
144144

145-
/**
146-
* @return true if user was successfully authenticated and false otherwise
147-
*/
148-
suspend fun authenticateAnonymously(): Boolean {
149-
check(auth.currentUser == null) { "User is already authenticated" }
150-
151-
return try {
152-
Napier.d("Starting Firebase anonymous sign in")
153-
auth.signInAnonymously().await()
154-
Napier.d("User has signed in successfully")
155-
156-
true
157-
} catch (e: Throwable) {
158-
Napier.e("Anonymous sign-in has failed", e)
159-
false
160-
}
161-
}
162-
163145
private fun googleClient(context: Context, webClientId: String) = GoogleSignIn.getClient(
164146
context,
165147
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package cz.frantisekmasa.wfrp_master.common.shell
22

33
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.layout.Arrangement
45
import androidx.compose.foundation.layout.Box
56
import androidx.compose.foundation.layout.Column
67
import androidx.compose.foundation.layout.fillMaxSize
8+
import androidx.compose.foundation.layout.padding
79
import androidx.compose.foundation.layout.size
810
import androidx.compose.material.MaterialTheme
911
import androidx.compose.material.Text
@@ -13,28 +15,38 @@ import androidx.compose.ui.Modifier
1315
import androidx.compose.ui.unit.dp
1416
import cz.frantisekmasa.wfrp_master.common.core.shared.Resources
1517
import cz.frantisekmasa.wfrp_master.common.core.shared.drawableResource
18+
import cz.frantisekmasa.wfrp_master.common.core.ui.primitives.Spacing
1619
import cz.frantisekmasa.wfrp_master.common.core.ui.theme.Theme
1720
import cz.frantisekmasa.wfrp_master.common.localization.FixedStrings
1821

1922
@Composable
20-
fun SplashScreen() {
23+
fun SplashScreen(content: (@Composable () -> Unit)? = null) {
2124
Box(
2225
modifier = Modifier
2326
.fillMaxSize()
24-
.splashBackground(),
27+
.splashBackground()
28+
.padding(Spacing.bodyPadding),
2529
contentAlignment = Alignment.Center,
2630
) {
27-
Column(horizontalAlignment = Alignment.CenterHorizontally) {
28-
Image(
29-
drawableResource(Resources.Drawable.SplashScreenIcon),
30-
FixedStrings.appName,
31-
Modifier.size(140.dp)
32-
)
33-
Text(
34-
FixedStrings.appName,
35-
style = MaterialTheme.typography.h6,
36-
color = Theme.fixedColors.splashScreenContent,
37-
)
31+
Column(
32+
verticalArrangement = Arrangement.spacedBy(Spacing.small, Alignment.CenterVertically),
33+
horizontalAlignment = Alignment.CenterHorizontally
34+
) {
35+
Column(
36+
horizontalAlignment = Alignment.CenterHorizontally
37+
) {
38+
Image(
39+
drawableResource(Resources.Drawable.SplashScreenIcon),
40+
FixedStrings.appName,
41+
Modifier.size(140.dp)
42+
)
43+
Text(
44+
FixedStrings.appName,
45+
style = MaterialTheme.typography.h6,
46+
color = Theme.fixedColors.splashScreenContent,
47+
)
48+
}
49+
content?.invoke()
3850
}
3951
}
4052
}

common/src/commonMain/resources/MR/base/strings.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
<string name="authentication_messages_reset_password_email_sent">Email with instructions for password reset was sent</string>
4545
<string name="authentication_messages_signed_in_as">You are signed-in as</string>
4646
<string name="authentication_messages_unknown_error">Unknown error occurred</string>
47-
<string name="authentication_startup_google_sign_in_failed">We could not sign you in via Google.\nYour data will be tied to this device, but you can always sign in later in Settings.</string>
4847
<string name="blessings_button_add_non_compendium">…or add non-Compendium blessing</string>
4948
<string name="blessings_label_duration">Duration</string>
5049
<string name="blessings_label_effect">Effect</string>

common/src/commonMain/resources/MR/de/strings.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@
9696
<string name="authentication_messages_email_not_found">Keine E-Mail gefunden</string>
9797
<string name="careers_comma_separated_skills_helper">Kommagetrennte Liste von Fähigkeiten</string>
9898
<string name="blessings_label_name">Name</string>
99-
<string name="authentication_startup_google_sign_in_failed">Wir konnten Sie nicht über Google anmelden.
100-
\nIhre Daten werden an dieses Gerät gebunden, aber Sie können sich später jederzeit in den Einstellungen anmelden.</string>
10199
<string name="character_button_unlink_from_player">Verknüpfung vom Spieler lösen</string>
102100
<string name="authentication_messages_reset_password_email_sent">E-Mail mit Anweisungen zum Zurücksetzen des Kennworts wurde gesendet</string>
103101
<string name="blessings_label_duration">Dauer</string>

common/src/commonMain/resources/MR/es/strings.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,6 @@
245245
<string name="tests_roll">Lanzar</string>
246246
<string name="characteristics_fellowship">Empatía</string>
247247
<string name="compendium_json_import_prompt_warning">El formato de exportación no es definitivo aún</string>
248-
<string name="authentication_startup_google_sign_in_failed">No pudimos ingresarle a través de Google.
249-
\nTus datos se vincularán a este dispositivo, y podrás ingresar más tarde desde los Ajustes.</string>
250248
<string name="weapons_reach_very_long">Muy Larga</string>
251249
<string name="combat_hit_locations_left_leg">Pierna Izquierda</string>
252250
<string name="character_button_unlink_from_player">Desenlazar del Jugador</string>

common/src/commonMain/resources/MR/fr/strings.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,6 @@
434434
<string name="authentication_messages_not_signed_in_description">Vous n\'êtes pas connecté.
435435
\nLa connexion vous permet de conserver l\'accès aux parties entre les appareils.</string>
436436
<string name="authentication_messages_lose_access_to_parties">Vous perdrez l\'accès à ces groupes :</string>
437-
<string name="authentication_startup_google_sign_in_failed">Nous n\'avons pas pu vous connecter via Google.
438-
\nVos données seront liées à cet appareil, mais vous pourrez toujours vous connecter ultérieurement dans les paramètres.</string>
439437
<string name="authentication_messages_unknown_error">Une erreur inconnue s\'est produite</string>
440438
<string name="blessings_label_range">Portée</string>
441439
<string name="calendar_icon_previous_month">Mois précédent</string>

common/src/commonMain/resources/MR/it/strings.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,6 @@
643643
<string name="about_body">Questa applicazione è stata creata da František Maša e dai suoi colleghi studenti, ora è sviluppata
644644
\nnel tempo libero di František Maša.
645645
\nSe ti piace l\'app, per favore dai la tua valutazione di WFRP Master su Google Play.</string>
646-
<string name="authentication_startup_google_sign_in_failed">Non siamo riusciti a farti accedere tramite Google.
647-
\nI tuoi dati saranno associati a questo dispositivo, ma potrai sempre accedere in un secondo momento nelle Impostazioni.</string>
648646
<string name="conditions_prone">Prono</string>
649647
<string name="conditions_blinded">Accecato</string>
650648
<string name="conditions_fatigued">Affaticato</string>

0 commit comments

Comments
 (0)