Merge pull request #113 from ente-io/register_for_url
Support for handling otpauth scheme
This commit is contained in:
@@ -28,6 +28,13 @@
|
||||
<data android:scheme="ente-auth"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="otpauth" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<!-- Don't delete the meta-data below.
|
||||
|
||||
@@ -99,6 +99,8 @@ PODS:
|
||||
- FMDB (>= 2.7.5)
|
||||
- SwiftyGif (5.4.4)
|
||||
- Toast (4.0.0)
|
||||
- uni_links (0.0.1):
|
||||
- Flutter
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
|
||||
@@ -125,6 +127,7 @@ DEPENDENCIES:
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
@@ -185,6 +188,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
|
||||
sqflite:
|
||||
:path: ".symlinks/plugins/sqflite/ios"
|
||||
uni_links:
|
||||
:path: ".symlinks/plugins/uni_links/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
|
||||
@@ -221,6 +226,7 @@ SPEC CHECKSUMS:
|
||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
||||
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||
url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2
|
||||
|
||||
PODFILE CHECKSUM: b4e3a7eabb03395b66e81fc061789f61526ee6bb
|
||||
|
||||
@@ -1,68 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>auth</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLocalizations</key>
|
||||
<array>
|
||||
<string>en</string>
|
||||
<string>es</string>
|
||||
</array>
|
||||
<key>CFBundleName</key>
|
||||
<string>auth</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app needs camera access to scan QR codes</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>Please allow auth to lock itself with FaceID or TouchID</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Please allow auth to pick a file to import data from</string>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>auth</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLocalizations</key>
|
||||
<array>
|
||||
<string>en</string>
|
||||
<string>es</string>
|
||||
</array>
|
||||
<key>CFBundleName</key>
|
||||
<string>auth</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>otpauth</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app needs camera access to scan QR codes</string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>Please allow auth to lock itself with FaceID or TouchID</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Please allow auth to pick a file to import data from</string>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:bip39/bip39.dart' as bip39;
|
||||
import 'package:ente_auth/core/constants.dart';
|
||||
import 'package:ente_auth/core/errors.dart';
|
||||
import 'package:ente_auth/core/event_bus.dart';
|
||||
// ignore: import_of_legacy_library_into_null_safe
|
||||
import 'package:ente_auth/events/signed_in_event.dart';
|
||||
import 'package:ente_auth/events/signed_out_event.dart';
|
||||
import 'package:ente_auth/models/key_attributes.dart';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// ignore_for_file: import_of_legacy_library_into_null_safe
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:ente_auth/app/view/app.dart';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import "package:ente_auth/l10n/l10n.dart";
|
||||
import 'package:ente_auth/models/code.dart';
|
||||
// ignore: import_of_legacy_library_into_null_safe
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/totp_util.dart';
|
||||
import "package:flutter/material.dart";
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:ente_auth/utils/email_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
PopupMenuButton<dynamic> reportBugPopupMenu(BuildContext context) {
|
||||
return PopupMenuButton(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:ente_auth/ente_theme_data.dart';
|
||||
import 'package:ente_auth/ui/components/captioned_text_widget.dart';
|
||||
import 'package:ente_auth/ui/components/menu_item_widget.dart';
|
||||
// ignore: import_of_legacy_library_into_null_safe
|
||||
import 'package:ente_auth/ui/settings/common_settings.dart';
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
71
lib/ui/home/coach_mark_widget.dart
Normal file
71
lib/ui/home/coach_mark_widget.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:ente_auth/core/event_bus.dart';
|
||||
import 'package:ente_auth/events/codes_updated_event.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/services/preference_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CoachMarkWidget extends StatelessWidget {
|
||||
const CoachMarkWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
await PreferenceService.instance.setHasShownCoachMark(true);
|
||||
Bus.instance.fire(CodesUpdatedEvent());
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).colorScheme.background.withOpacity(0.1),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.swipe_left,
|
||||
size: 42,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
l10n.swipeHint,
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 36,
|
||||
),
|
||||
SizedBox(
|
||||
width: 160,
|
||||
child: OutlinedButton(
|
||||
onPressed: () async {
|
||||
await PreferenceService.instance
|
||||
.setHasShownCoachMark(true);
|
||||
Bus.instance.fire(CodesUpdatedEvent());
|
||||
},
|
||||
child: Text(l10n.ok),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
61
lib/ui/home/home_empty_state.dart
Normal file
61
lib/ui/home/home_empty_state.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HomeEmptyStateWidget extends StatelessWidget {
|
||||
final VoidCallback? onScanTap;
|
||||
final VoidCallback? onManuallySetupTap;
|
||||
|
||||
const HomeEmptyStateWidget({
|
||||
Key? key,
|
||||
required this.onScanTap,
|
||||
required this.onManuallySetupTap,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.tightFor(height: 800, width: 450),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/wallet-front-gradient.png",
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
Text(
|
||||
l10n.setupFirstAccount,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
const SizedBox(height: 64),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onScanTap,
|
||||
child: Text(l10n.importScanQrCode),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onManuallySetupTap,
|
||||
child: Text(l10n.importEnterSetupKey),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
29
lib/ui/home/speed_dial_label_widget.dart
Normal file
29
lib/ui/home/speed_dial_label_widget.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'package:ente_auth/ente_theme_data.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SpeedDialLabelWidget extends StatelessWidget {
|
||||
final String label;
|
||||
|
||||
const SpeedDialLabelWidget(
|
||||
this.label, {
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.all(4),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: Theme.of(context).colorScheme.fabBackgroundColor,
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.fabForegroundColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
// ignore_for_file: import_of_legacy_library_into_null_safe
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:ente_auth/core/configuration.dart';
|
||||
import 'package:ente_auth/core/event_bus.dart';
|
||||
import 'package:ente_auth/ente_theme_data.dart';
|
||||
import 'package:ente_auth/events/codes_updated_event.dart';
|
||||
@@ -17,12 +15,19 @@ import 'package:ente_auth/store/code_store.dart';
|
||||
import 'package:ente_auth/ui/account/logout_dialog.dart';
|
||||
import 'package:ente_auth/ui/code_widget.dart';
|
||||
import 'package:ente_auth/ui/common/loading_widget.dart';
|
||||
import 'package:ente_auth/ui/home/coach_mark_widget.dart';
|
||||
import 'package:ente_auth/ui/home/home_empty_state.dart';
|
||||
import 'package:ente_auth/ui/home/speed_dial_label_widget.dart';
|
||||
import 'package:ente_auth/ui/scanner_page.dart';
|
||||
import 'package:ente_auth/ui/settings_page.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/totp_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:move_to_background/move_to_background.dart';
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({Key? key}) : super(key: key);
|
||||
@@ -58,16 +63,15 @@ class _HomePageState extends State<HomePage> {
|
||||
Bus.instance.on<TriggerLogoutEvent>().listen((event) async {
|
||||
await autoLogoutAlert(context);
|
||||
});
|
||||
_initDeepLinks();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _loadCodes() {
|
||||
CodeStore.instance.getAllCodes().then((codes) {
|
||||
_codes = codes;
|
||||
_filteredCodes = codes;
|
||||
|
||||
_hasLoaded = true;
|
||||
setState(() {});
|
||||
_applyFiltering();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -207,7 +211,10 @@ class _HomePageState extends State<HomePage> {
|
||||
final l10n = context.l10n;
|
||||
if (_hasLoaded) {
|
||||
if (_filteredCodes.isEmpty && _searchText.isEmpty) {
|
||||
return _getEmptyState();
|
||||
return HomeEmptyStateWidget(
|
||||
onScanTap: _redirectToManualEntryPage,
|
||||
onManuallySetupTap: _redirectToManualEntryPage,
|
||||
);
|
||||
} else {
|
||||
final list = ListView.builder(
|
||||
itemBuilder: ((context, index) {
|
||||
@@ -219,7 +226,7 @@ class _HomePageState extends State<HomePage> {
|
||||
return Stack(
|
||||
children: [
|
||||
list,
|
||||
_getCoachMarkWidget(),
|
||||
const CoachMarkWidget(),
|
||||
],
|
||||
);
|
||||
} else if (_showSearchBox) {
|
||||
@@ -260,6 +267,57 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _initDeepLinks() async {
|
||||
// Platform messages may fail, so we use a try/catch PlatformException.
|
||||
try {
|
||||
final String? initialLink = await getInitialLink();
|
||||
// Parse the link and warn the user, if it is not correct,
|
||||
// but keep in mind it could be `null`.
|
||||
if (initialLink != null) {
|
||||
_handleDeeplink(context, initialLink);
|
||||
return true;
|
||||
} else {
|
||||
_logger.info("No initial link received.");
|
||||
}
|
||||
} on PlatformException {
|
||||
// Handle exception by warning the user their action did not succeed
|
||||
// return?
|
||||
_logger.severe("PlatformException thrown while getting initial link");
|
||||
}
|
||||
|
||||
// Attach a listener to the stream
|
||||
linkStream.listen(
|
||||
(String? link) {
|
||||
_handleDeeplink(context, link);
|
||||
},
|
||||
onError: (err) {
|
||||
_logger.severe(err);
|
||||
},
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
void _handleDeeplink(BuildContext context, String? link) {
|
||||
if (!Configuration.instance.hasConfiguredAccount() || link == null) {
|
||||
return;
|
||||
}
|
||||
if (mounted && link.toLowerCase().startsWith("otpauth://")) {
|
||||
try {
|
||||
final newCode = Code.fromRawData(link);
|
||||
getNextTotp(newCode);
|
||||
CodeStore.instance.addCode(newCode);
|
||||
_showSearchBox = true;
|
||||
_textController.text = newCode.account;
|
||||
_searchText = newCode.account;
|
||||
_applyFiltering();
|
||||
setState(() {});
|
||||
} catch (e, s) {
|
||||
showGenericErrorDialog(context: context);
|
||||
_logger.severe("error while handling deeplink", e, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _getFab() {
|
||||
return SpeedDial(
|
||||
icon: Icons.add,
|
||||
@@ -292,137 +350,4 @@ class _HomePageState extends State<HomePage> {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getEmptyState() {
|
||||
final l10n = context.l10n;
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.tightFor(height: 800, width: 450),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/wallet-front-gradient.png",
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
Text(
|
||||
l10n.setupFirstAccount,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
const SizedBox(height: 64),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: _redirectToScannerPage,
|
||||
child: Text(l10n.importScanQrCode),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: _redirectToManualEntryPage,
|
||||
child: Text(l10n.importEnterSetupKey),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getCoachMarkWidget() {
|
||||
final l10n = context.l10n;
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
await PreferenceService.instance.setHasShownCoachMark(true);
|
||||
setState(() {});
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).colorScheme.background.withOpacity(0.1),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.swipe_left,
|
||||
size: 42,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
l10n.swipeHint,
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 36,
|
||||
),
|
||||
SizedBox(
|
||||
width: 160,
|
||||
child: OutlinedButton(
|
||||
onPressed: () async {
|
||||
await PreferenceService.instance
|
||||
.setHasShownCoachMark(true);
|
||||
setState(() {});
|
||||
},
|
||||
child: Text(l10n.ok),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SpeedDialLabelWidget extends StatelessWidget {
|
||||
final String label;
|
||||
|
||||
const SpeedDialLabelWidget(
|
||||
this.label, {
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.all(4),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: Theme.of(context).colorScheme.fabBackgroundColor,
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.fabForegroundColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import 'package:ente_auth/core/constants.dart';
|
||||
import 'package:ente_auth/core/logging/super_logging.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
|
||||
24
pubspec.lock
24
pubspec.lock
@@ -1387,6 +1387,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
uni_links:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: uni_links
|
||||
sha256: "051098acfc9e26a9fde03b487bef5d3d228ca8f67693480c6f33fd4fbb8e2b6e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
uni_links_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uni_links_platform_interface
|
||||
sha256: "929cf1a71b59e3b7c2d8a2605a9cf7e0b125b13bc858e55083d88c62722d4507"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
uni_links_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uni_links_web
|
||||
sha256: "7539db908e25f67de2438e33cc1020b30ab94e66720b5677ba6763b25f6394df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
universal_io:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -64,6 +64,7 @@ dependencies:
|
||||
sqflite: ^2.1.0
|
||||
step_progress_indicator: ^1.0.2
|
||||
styled_text: ^7.0.0
|
||||
uni_links: ^0.5.1
|
||||
url_launcher: ^6.1.5
|
||||
uuid: ^3.0.4
|
||||
|
||||
|
||||
Reference in New Issue
Block a user