Skip to content

Commit 6026327

Browse files
committed
Format code and adjust Google auth/forms flow
Mostly stylistic reformatting and small refactors across multiple files for readability (line-wrapping, consistent indentation, and shorter expression layouts). Key functional changes: requestFormsScope and getGoogleAccessToken in AuthService now use the authorizationClient APIs and include improved error handling/early returns for unsupported desktop/non-Google cases; debug logging messages were wrapped for readability. Minor fixes to GoogleFormsService error message formatting, website prompt/contact-form string formatting and regex declaration, and various UI callback/whitespace cleanups in generate_website_screen and web_generate_website_screen.
1 parent 14942fd commit 6026327

7 files changed

Lines changed: 187 additions & 143 deletions

File tree

lib/core/models/contact_form_config.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,8 @@ class ContactFormConfig {
107107
static const ContactFormConfig disabled = ContactFormConfig();
108108

109109
/// Fields whose label is non-empty — the only ones worth rendering.
110-
List<ContactFormField> get usableFields => fields
111-
.where((f) => f.label.trim().isNotEmpty)
112-
.toList(growable: false);
110+
List<ContactFormField> get usableFields =>
111+
fields.where((f) => f.label.trim().isNotEmpty).toList(growable: false);
113112

114113
Map<String, dynamic> toJson() => {
115114
'enabled': enabled,

lib/core/services/auth_service.dart

Lines changed: 102 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ enum AuthProvider { google, apple }
4040
// 3. Configure OAuth consent screen
4141
//
4242
// Note: For Android, clientId is auto-detected from the signing config
43-
const String _googleClientIdIOS = '1095513138272-41oj756pperrsh5aqumh3nktvankcdel.apps.googleusercontent.com'; // iOS OAuth Client ID
43+
const String _googleClientIdIOS =
44+
'1095513138272-41oj756pperrsh5aqumh3nktvankcdel.apps.googleusercontent.com'; // iOS OAuth Client ID
4445
// Web Client ID (used as serverClientId to mint idTokens the issuer
4546
// accepts). Single-sourced with the web shell in AuthCore.
4647
const String _googleServerClientId = AuthCore.googleWebClientId;
@@ -61,22 +62,22 @@ class AuthUser {
6162
});
6263

6364
Map<String, dynamic> toJson() => {
64-
'id': id,
65-
'email': email,
66-
'displayName': displayName,
67-
'photoUrl': photoUrl,
68-
'provider': provider.name,
69-
};
65+
'id': id,
66+
'email': email,
67+
'displayName': displayName,
68+
'photoUrl': photoUrl,
69+
'provider': provider.name,
70+
};
7071

7172
factory AuthUser.fromJson(Map<String, dynamic> json) => AuthUser(
72-
id: json['id'],
73-
email: json['email'],
74-
displayName: json['displayName'],
75-
photoUrl: json['photoUrl'],
76-
provider: AuthProvider.values.firstWhere(
77-
(e) => e.name == json['provider'],
78-
),
79-
);
73+
id: json['id'],
74+
email: json['email'],
75+
displayName: json['displayName'],
76+
photoUrl: json['photoUrl'],
77+
provider: AuthProvider.values.firstWhere(
78+
(e) => e.name == json['provider'],
79+
),
80+
);
8081
}
8182

8283
class AuthService {
@@ -124,9 +125,11 @@ class AuthService {
124125
Future<bool> hasStoredCredentials() async {
125126
if (_currentUser != null) return true;
126127
try {
127-
final userJson = await SecureStorageService.instance.readJson(
128-
SecureStorageKeys.userCredentials,
129-
).timeout(const Duration(seconds: 2));
128+
final userJson = await SecureStorageService.instance
129+
.readJson(
130+
SecureStorageKeys.userCredentials,
131+
)
132+
.timeout(const Duration(seconds: 2));
130133
return userJson != null;
131134
} catch (e) {
132135
debugPrint('hasStoredCredentials check failed: $e');
@@ -153,14 +156,18 @@ class AuthService {
153156

154157
if (Platform.isAndroid) {
155158
// Android: clientId is auto-detected, only serverClientId needed for idToken
156-
serverClientId = _googleServerClientId.isNotEmpty ? _googleServerClientId : null;
159+
serverClientId =
160+
_googleServerClientId.isNotEmpty ? _googleServerClientId : null;
157161
} else if (Platform.isIOS) {
158162
clientId = _googleClientIdIOS.isNotEmpty ? _googleClientIdIOS : null;
159-
serverClientId = _googleServerClientId.isNotEmpty ? _googleServerClientId : null;
163+
serverClientId =
164+
_googleServerClientId.isNotEmpty ? _googleServerClientId : null;
160165
} else {
161166
// Desktop (Windows/macOS/Linux): use server client ID for browser-based OAuth
162-
clientId = _googleServerClientId.isNotEmpty ? _googleServerClientId : null;
163-
serverClientId = _googleServerClientId.isNotEmpty ? _googleServerClientId : null;
167+
clientId =
168+
_googleServerClientId.isNotEmpty ? _googleServerClientId : null;
169+
serverClientId =
170+
_googleServerClientId.isNotEmpty ? _googleServerClientId : null;
164171
}
165172

166173
await _googleSignIn.initialize(
@@ -188,13 +195,15 @@ class AuthService {
188195
SecureStorageKeys.userCredentials,
189196
);
190197

191-
debugPrint('AuthService: userJson = ${userJson != null ? "found" : "null"}');
198+
debugPrint(
199+
'AuthService: userJson = ${userJson != null ? "found" : "null"}');
192200

193201
if (userJson != null) {
194202
_setCurrentUser(AuthUser.fromJson(userJson));
195203
debugPrint('AuthService: Restored user: ${_currentUser!.email}');
196204
await _deriveEncryptionKey();
197-
debugPrint('AuthService: After _deriveEncryptionKey, key is ${_encryptionKey == null ? "null" : "set"}');
205+
debugPrint(
206+
'AuthService: After _deriveEncryptionKey, key is ${_encryptionKey == null ? "null" : "set"}');
198207
await _initializeFulaClient();
199208
// Re-link cloud mappings and restore tags for reinstall persistence (runs in background)
200209
if (FulaApiService.instance.isConfigured && !skipHeavyOperations) {
@@ -223,13 +232,15 @@ class AuthService {
223232
Future<AuthUser?> signInWithGoogle() async {
224233
try {
225234
if (PlatformCapabilities.isDesktop) {
226-
throw Exception('Google Sign-In is not available on desktop. Please use "Get API Key" to connect your account.');
235+
throw Exception(
236+
'Google Sign-In is not available on desktop. Please use "Get API Key" to connect your account.');
227237
}
228238

229239
await _ensureGoogleInitialized();
230240

231241
if (!_googleSignIn.supportsAuthenticate()) {
232-
debugPrint('Google Sign-In: authenticate not supported on this platform');
242+
debugPrint(
243+
'Google Sign-In: authenticate not supported on this platform');
233244
throw Exception('Google Sign-In not supported on this device');
234245
}
235246

@@ -255,30 +266,43 @@ class AuthService {
255266
debugPrint('Google Sign-In error: $e');
256267
// Check for common Credential Manager errors
257268
final errorStr = e.toString();
258-
if (errorStr.contains('GetCredentialResponse') || errorStr.contains('CredMan')) {
259-
throw Exception('Google Sign-In configuration error. Please check SHA-1 fingerprint and OAuth client IDs in Google Cloud Console.');
269+
if (errorStr.contains('GetCredentialResponse') ||
270+
errorStr.contains('CredMan')) {
271+
throw Exception(
272+
'Google Sign-In configuration error. Please check SHA-1 fingerprint and OAuth client IDs in Google Cloud Console.');
260273
}
261274
rethrow;
262275
}
263276
}
264277

265278
Future<bool> requestFormsScope() async {
266-
if (PlatformCapabilities.isDesktop || _currentUser?.provider != AuthProvider.google) {
279+
if (PlatformCapabilities.isDesktop ||
280+
_currentUser?.provider != AuthProvider.google) {
281+
return false;
282+
}
283+
try {
284+
final authz = await _googleSignIn.authorizationClient.authorizeScopes(
285+
['https://www.googleapis.com/auth/forms.body'],
286+
);
287+
return authz != null;
288+
} catch (e) {
289+
debugPrint('Error requesting forms scope: $e');
267290
return false;
268291
}
269-
final granted = await _googleSignIn.requestScopes(['https://www.googleapis.com/auth/forms.body']);
270-
return granted;
271292
}
272293

273294
Future<String?> getGoogleAccessToken() async {
274295
if (_currentUser?.provider != AuthProvider.google) return null;
275-
276-
// For google_sign_in v7, currentUser getter on the plugin returns the current GoogleSignInAccount
277-
final account = _googleSignIn.currentUser;
278-
if (account == null) return null;
279-
280-
final auth = await account.authentication;
281-
return auth.accessToken;
296+
297+
try {
298+
final authz = await _googleSignIn.authorizationClient.authorizationForScopes(
299+
['https://www.googleapis.com/auth/forms.body'],
300+
);
301+
return authz?.accessToken;
302+
} catch (e) {
303+
debugPrint('Error getting google access token: $e');
304+
return null;
305+
}
282306
}
283307

284308
Future<void> _handleGoogleSignIn(
@@ -344,7 +368,8 @@ class AuthService {
344368
ShelfStorageService.instance.restoreFromCloud();
345369
}
346370
} catch (e) {
347-
debugPrint('Google Sign-In: Fula initialization failed (sign-in still succeeded): $e');
371+
debugPrint(
372+
'Google Sign-In: Fula initialization failed (sign-in still succeeded): $e');
348373
// Sign-in succeeded, but Fula features won't work until RustLib is properly initialized
349374
}
350375
}
@@ -502,7 +527,8 @@ class AuthService {
502527
ShelfStorageService.instance.restoreFromCloud();
503528
}
504529
} catch (e) {
505-
debugPrint('Apple Sign-In: Fula initialization failed (sign-in still succeeded): $e');
530+
debugPrint(
531+
'Apple Sign-In: Fula initialization failed (sign-in still succeeded): $e');
506532
// Sign-in succeeded, but Fula features won't work until RustLib is properly initialized
507533
}
508534
}
@@ -620,7 +646,8 @@ class AuthService {
620646
/// Initialize the fula_client with the derived encryption key
621647
Future<void> _initializeFulaClient() async {
622648
debugPrint('AuthService: _initializeFulaClient called');
623-
debugPrint('AuthService: _encryptionKey is ${_encryptionKey == null ? "null" : "set (${_encryptionKey!.length} bytes)"}');
649+
debugPrint(
650+
'AuthService: _encryptionKey is ${_encryptionKey == null ? "null" : "set (${_encryptionKey!.length} bytes)"}');
624651

625652
if (_encryptionKey == null) {
626653
debugPrint('Cannot initialize FulaApiService: no encryption key');
@@ -701,12 +728,14 @@ class AuthService {
701728

702729
// If no current user, try to restore the session first
703730
if (_currentUser == null) {
704-
debugPrint('AuthService: No current user, attempting to restore session...');
731+
debugPrint(
732+
'AuthService: No current user, attempting to restore session...');
705733
final hasSession = await checkExistingSession();
706734
debugPrint('AuthService: Session restore result: $hasSession');
707735
// checkExistingSession already calls _initializeFulaClient if successful
708736
if (hasSession && FulaApiService.instance.isConfigured) {
709-
debugPrint('AuthService: FulaApiService already initialized via session restore');
737+
debugPrint(
738+
'AuthService: FulaApiService already initialized via session restore');
710739
return;
711740
}
712741
}
@@ -715,7 +744,8 @@ class AuthService {
715744
if (_encryptionKey == null) {
716745
debugPrint('AuthService: No encryption key, calling getEncryptionKey()');
717746
await getEncryptionKey();
718-
debugPrint('AuthService: After getEncryptionKey(), _encryptionKey is ${_encryptionKey == null ? "null" : "set"}');
747+
debugPrint(
748+
'AuthService: After getEncryptionKey(), _encryptionKey is ${_encryptionKey == null ? "null" : "set"}');
719749
}
720750
await _initializeFulaClient();
721751

@@ -741,7 +771,8 @@ class AuthService {
741771
final stored = await SecureStorageService.instance.read(
742772
SecureStorageKeys.encryptionKey,
743773
);
744-
debugPrint('AuthService: Stored encryption key = ${stored != null ? "found" : "null"}');
774+
debugPrint(
775+
'AuthService: Stored encryption key = ${stored != null ? "found" : "null"}');
745776

746777
if (stored != null) {
747778
_encryptionKey = base64Decode(stored);
@@ -754,7 +785,8 @@ class AuthService {
754785
return _encryptionKey;
755786
}
756787

757-
debugPrint('AuthService: Cannot get encryption key - no stored key and no current user');
788+
debugPrint(
789+
'AuthService: Cannot get encryption key - no stored key and no current user');
758790
return null;
759791
}
760792

@@ -838,14 +870,15 @@ class AuthService {
838870
/// material — Mode A `oauthSub`, Mode B `oauthSub` (read from
839871
/// SecureStorage), `effectiveUserId`, and `usersIndexUserKey` are
840872
/// all non-confidential.
841-
Future<({
842-
String mode,
843-
String? provider,
844-
String? oauthSub,
845-
String? effectiveUserId,
846-
String? email,
847-
String? usersIndexUserKey,
848-
})?> getDerivationInputs() async {
873+
Future<
874+
({
875+
String mode,
876+
String? provider,
877+
String? oauthSub,
878+
String? effectiveUserId,
879+
String? email,
880+
String? usersIndexUserKey,
881+
})?> getDerivationInputs() async {
849882
if (_currentUser == null) return null;
850883

851884
final modeVersion = await SecureStorageService.instance.read(
@@ -866,20 +899,19 @@ class AuthService {
866899
);
867900
final jwtSub = AuthCore.extractJwtSub(jwt);
868901
if (jwtSub != null && jwtSub.isNotEmpty) {
869-
usersIndexUserKey =
870-
await fula.deriveUserKeyFromJwtSub(jwtSub: jwtSub);
902+
usersIndexUserKey = await fula.deriveUserKeyFromJwtSub(jwtSub: jwtSub);
871903
}
872904
} catch (e) {
873-
debugPrint('AuthService.getDerivationInputs: JWT-sub deriveUserKey failed: $e');
905+
debugPrint(
906+
'AuthService.getDerivationInputs: JWT-sub deriveUserKey failed: $e');
874907
}
875908

876909
if (mode == 'A') {
877910
final pinned = await SecureStorageService.instance.read(
878911
SecureStorageKeys.derivationEmail,
879912
);
880-
final email = (pinned != null && pinned.isNotEmpty)
881-
? pinned
882-
: _currentUser!.email;
913+
final email =
914+
(pinned != null && pinned.isNotEmpty) ? pinned : _currentUser!.email;
883915

884916
// Email-keyed fallback only makes sense for Mode A: master keys
885917
// Mode A users by email-hash. Mode B/C key by the seed-derived
@@ -888,7 +920,8 @@ class AuthService {
888920
try {
889921
usersIndexUserKey = await fula.deriveUserKeyFromEmail(email: email);
890922
} catch (e) {
891-
debugPrint('AuthService.getDerivationInputs: email deriveUserKey failed: $e');
923+
debugPrint(
924+
'AuthService.getDerivationInputs: email deriveUserKey failed: $e');
892925
usersIndexUserKey = null;
893926
}
894927
}
@@ -1157,7 +1190,8 @@ class AuthService {
11571190
/// persisted to disk — it's used once for KDF + signing, then dropped.
11581191
///
11591192
/// On `GoogleSignInExceptionCode.canceled`, returns `null`.
1160-
Future<({AuthUser user, bool hasModeA})?> signInGoogleModeB({required String password}) async {
1193+
Future<({AuthUser user, bool hasModeA})?> signInGoogleModeB(
1194+
{required String password}) async {
11611195
if (PlatformCapabilities.isDesktop) {
11621196
throw Exception(
11631197
'Google Sign-In is not available on desktop. '
@@ -1195,7 +1229,8 @@ class AuthService {
11951229

11961230
/// Mode B convenience for Apple Sign-In. Returns
11971231
/// `(user: AuthUser, hasModeA: bool)` on success, `null` on user cancel.
1198-
Future<({AuthUser user, bool hasModeA})?> signInAppleModeB({required String password}) async {
1232+
Future<({AuthUser user, bool hasModeA})?> signInAppleModeB(
1233+
{required String password}) async {
11991234
try {
12001235
final credential = await SignInWithApple.getAppleIDCredential(
12011236
scopes: const [
@@ -1286,7 +1321,8 @@ class AuthService {
12861321

12871322
// Clear NFT wallet state and secure storage key
12881323
NftWalletService.instance.clear();
1289-
await SecureStorageService.instance.delete(SecureStorageKeys.nftWalletPrivateKey);
1324+
await SecureStorageService.instance
1325+
.delete(SecureStorageKeys.nftWalletPrivateKey);
12901326

12911327
// Clear NFT collections, received NFTs, and tags (user-specific data)
12921328
await NftService.instance.clearAll();
@@ -1353,7 +1389,8 @@ class AuthService {
13531389
final account = await result.timeout(
13541390
const Duration(seconds: 5),
13551391
onTimeout: () {
1356-
debugPrint('Google lightweight auth timed out in reauthenticate - likely Android 16 Credential Manager issue');
1392+
debugPrint(
1393+
'Google lightweight auth timed out in reauthenticate - likely Android 16 Credential Manager issue');
13571394
return null;
13581395
},
13591396
);

lib/core/services/google_forms_service.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ class GoogleFormsService {
3939
final requests = <Map<String, dynamic>>[];
4040
for (var i = 0; i < fields.length; i++) {
4141
final field = fields[i];
42-
42+
4343
Map<String, dynamic> item = {
4444
'title': field.label,
4545
};
4646

47-
if (field.type == ContactFormFieldType.text ||
48-
field.type == ContactFormFieldType.email ||
47+
if (field.type == ContactFormFieldType.text ||
48+
field.type == ContactFormFieldType.email ||
4949
field.type == ContactFormFieldType.number) {
5050
item['questionItem'] = {
5151
'question': {
@@ -92,7 +92,8 @@ class GoogleFormsService {
9292
);
9393

9494
if (updateRes.statusCode != 200) {
95-
throw Exception('Failed to update Google Form fields: ${updateRes.body}');
95+
throw Exception(
96+
'Failed to update Google Form fields: ${updateRes.body}');
9697
}
9798
}
9899

0 commit comments

Comments
 (0)