diff --git a/packages/firebase_ui_auth/example/lib/main.dart b/packages/firebase_ui_auth/example/lib/main.dart index 6c4e8828..154ec69a 100644 --- a/packages/firebase_ui_auth/example/lib/main.dart +++ b/packages/firebase_ui_auth/example/lib/main.dart @@ -267,6 +267,7 @@ class FirebaseAuthUIExample extends StatelessWidget { showMFATile: kIsWeb || platform == TargetPlatform.iOS || platform == TargetPlatform.android, + showUnlinkConfirmationDialog: true, ); }, }, diff --git a/packages/firebase_ui_auth/lib/src/navigation/authentication.dart b/packages/firebase_ui_auth/lib/src/navigation/authentication.dart index d72979c2..8303b7b9 100644 --- a/packages/firebase_ui_auth/lib/src/navigation/authentication.dart +++ b/packages/firebase_ui_auth/lib/src/navigation/authentication.dart @@ -28,7 +28,7 @@ Future showReauthenticateDialog({ final reauthenticated = await showGeneralDialog( context: context, barrierDismissible: true, - barrierLabel: l.cancelLabel, + barrierLabel: l.cancelButtonLabel, pageBuilder: (_, __, ___) => FirebaseUIActions.inherit( from: context, child: ReauthenticateDialog( diff --git a/packages/firebase_ui_auth/lib/src/screens/profile_screen.dart b/packages/firebase_ui_auth/lib/src/screens/profile_screen.dart index a5ff468d..9848c252 100644 --- a/packages/firebase_ui_auth/lib/src/screens/profile_screen.dart +++ b/packages/firebase_ui_auth/lib/src/screens/profile_screen.dart @@ -176,11 +176,13 @@ class _LinkedProvidersRow extends StatefulWidget { final FirebaseAuth? auth; final List providers; final VoidCallback onProviderUnlinked; + final bool showUnlinkConfirmationDialog; const _LinkedProvidersRow({ this.auth, required this.providers, required this.onProviderUnlinked, + required this.showUnlinkConfirmationDialog, }); @override @@ -201,13 +203,41 @@ class _LinkedProvidersRowState extends State<_LinkedProvidersRow> { }); } + void Function() pop(bool value) { + return () { + Navigator.of(context).pop(value); + }; + } + Future _unlinkProvider(BuildContext context, String providerId) async { setState(() { unlinkingProvider = providerId; error = null; }); + bool? confirmed = !widget.showUnlinkConfirmationDialog; + + if (!confirmed) { + final l = FirebaseUILocalizations.labelsOf(context); + + confirmed = await showAdaptiveDialog( + context: context, + builder: (context) { + return UniversalAlert( + onConfirm: pop(true), + onCancel: pop(false), + title: l.ulinkProviderAlertTitle, + confirmButtonText: l.confirmUnlinkButtonLabel, + cancelButtonText: l.cancelButtonLabel, + message: l.unlinkProviderAlertMessage, + ); + }, + ); + } + try { + if (!(confirmed ?? false)) return; + final user = widget.auth!.currentUser!; await user.unlink(providerId); await user.reload(); @@ -712,6 +742,10 @@ class ProfileScreen extends MultiProviderScreen { /// are ignored. final Widget? avatar; + /// Indicates wether a confirmation dialog should be shown when the user + /// tries to unlink a provider. + final bool showUnlinkConfirmationDialog; + const ProfileScreen({ super.key, super.auth, @@ -726,6 +760,7 @@ class ProfileScreen extends MultiProviderScreen { this.cupertinoNavigationBar, this.actionCodeSettings, this.showMFATile = false, + this.showUnlinkConfirmationDialog = false, }); Future _reauthenticate(BuildContext context) { @@ -819,6 +854,7 @@ class ProfileScreen extends MultiProviderScreen { auth: auth, providers: linkedProviders, onProviderUnlinked: providersScopeKey.rebuild, + showUnlinkConfirmationDialog: showUnlinkConfirmationDialog, ), ); }, diff --git a/packages/firebase_ui_auth/lib/src/widgets/different_method_sign_in_dialog.dart b/packages/firebase_ui_auth/lib/src/widgets/different_method_sign_in_dialog.dart index 4f581ed9..5effa3d7 100644 --- a/packages/firebase_ui_auth/lib/src/widgets/different_method_sign_in_dialog.dart +++ b/packages/firebase_ui_auth/lib/src/widgets/different_method_sign_in_dialog.dart @@ -60,7 +60,7 @@ class DifferentMethodSignInDialog extends StatelessWidget { onSignedIn: onSignedIn, ), UniversalButton( - text: l.cancelLabel, + text: l.cancelButtonLabel, onPressed: () => Navigator.of(context).pop(), ), ], diff --git a/packages/firebase_ui_localizations/README.md b/packages/firebase_ui_localizations/README.md index 294c9d89..fdfe9392 100644 --- a/packages/firebase_ui_localizations/README.md +++ b/packages/firebase_ui_localizations/README.md @@ -62,6 +62,8 @@ and make sure that your custom delegate extends `LocalizationsDelegate.arb` @@ -69,3 +71,21 @@ If you want to add a new language, make sure to add a relevant `.arb` file into - run `dart run firebase_ui_localizations:gen_l10n` - commit the `.arb` and generated `.dart` file - submit a PR + +### Adding a new label to existing languages + +If you want to add new labels to existing languages, + +- Execute `dart run firebase_ui_localizations:add_label`: + +```bash +dart run firebase_ui_localizations:add_label +Label name?: someNewLabel +Label description?: This will go to the doc comment of the label +English translation?: Some new label +Done! +``` + +- Execute `dart run firebase_ui_localizations:gen_l10n` +- Commit the changes +- Submit a PR diff --git a/packages/firebase_ui_localizations/bin/add_label.dart b/packages/firebase_ui_localizations/bin/add_label.dart index 613adbd9..c9d74fca 100644 --- a/packages/firebase_ui_localizations/bin/add_label.dart +++ b/packages/firebase_ui_localizations/bin/add_label.dart @@ -20,12 +20,22 @@ String prompt(String tag) { Future main(List args) async { final name = prompt('Label name'); - final description = prompt('Label description'); - final englishTranslation = prompt('English translation'); final cwd = Directory.current.path; final l10nSrc = Directory(path.join(cwd, 'lib', 'l10n')); + final enArb = File(path.join(l10nSrc.path, 'firebase_ui_en.arb')); + final enContent = + jsonDecode(await enArb.readAsString()) as Map; + + if (enContent.containsKey(name)) { + stderr.writeln('Label "$name" already exists'); + exit(1); + } + + final description = prompt('Label description'); + final englishTranslation = prompt('English translation'); + final files = l10nSrc.listSync().whereType().toList(); final futures = files.map((e) async { final newContent = await addLabel(e, name, description, englishTranslation); @@ -48,6 +58,7 @@ Future> addLabel( String englishTranslation, ) async { final content = jsonDecode(await file.readAsString()) as Map; + return { ...content, "@@last_modified": DateTime.now().toIso8601String(), diff --git a/packages/firebase_ui_localizations/bin/gen_l10n.dart b/packages/firebase_ui_localizations/bin/gen_l10n.dart index 9aedc53f..dd811f8e 100644 --- a/packages/firebase_ui_localizations/bin/gen_l10n.dart +++ b/packages/firebase_ui_localizations/bin/gen_l10n.dart @@ -74,6 +74,12 @@ void main() async { }).expand((element) => element); await Future.wait([...genOps.cast()]); + + await generateDefaultLocalizations( + labelsByLocale['en']['default'].cast(), + licenseHeader, + ); + await generateLanguagesList(labelsByLocale, licenseHeader); Process.runSync('dart', ['format', outDir.path]); } @@ -226,3 +232,130 @@ Future getLicenseHeader() async { return '// $e'; }).join('\n'); } + +Future generateDefaultLocalizations( + Map arb, + String licenseHeader, +) async { + final labels = arb.entries.where(isLabelEntry).map((e) { + final meta = arb['@${e.key}'] ?? {}; + + return Label( + key: e.key, + translation: e.value, + description: meta['description'], + ); + }).toList() + ..sort((a, b) => a.key.compareTo(b.key)); + + final content = await getDefaultLocalizationsContent(labels, licenseHeader); + final outFile = File(path.join(outDir.path, 'default_localizations.dart')); + + if (!outFile.existsSync()) { + outFile.createSync(recursive: true); + } + + final out = outFile.openWrite(); + out.write(content); + await out.flush(); + await out.close(); +} + +Future getDefaultLocalizationsContent( + List