mirror of
https://github.com/Myzel394/quid_faciam_hodie.git
synced 2025-06-19 07:35:26 +02:00
created help sheets; improvements & bugfixes
This commit is contained in:
parent
909d4f8d89
commit
6d28ee51dd
4
lib/constants/help_sheet_id.dart
Normal file
4
lib/constants/help_sheet_id.dart
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
enum HelpSheetID {
|
||||||
|
mainScreen,
|
||||||
|
timelineScreen,
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
const CACHE_KEY = '_cache';
|
const CACHE_KEY = '_cache';
|
||||||
const SETTINGS_KEY = 'settings';
|
const SETTINGS_KEY = 'settings';
|
||||||
|
const USER_HELP_SHEETS_KEY = 'user_help_sheets';
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"generalError": "There was an error",
|
"generalError": "There was an error",
|
||||||
"generalCancelButtonLabel": "Cancel",
|
"generalCancelButtonLabel": "Cancel",
|
||||||
"generalContinueButtonLabel": "Continue",
|
"generalContinueButtonLabel": "Continue",
|
||||||
|
"generalUnderstoodButtonLabel": "OK",
|
||||||
|
|
||||||
"welcomeScreenDescription": "Find out what you did all the days and unlock moments you completely forgot!",
|
"welcomeScreenDescription": "Find out what you did all the days and unlock moments you completely forgot!",
|
||||||
"welcomeScreenSubtitle": "What did I do today?",
|
"welcomeScreenSubtitle": "What did I do today?",
|
||||||
@ -46,6 +47,10 @@
|
|||||||
"mainScreenTakeVideoActionSaveVideo": "Taking video, please hold still...",
|
"mainScreenTakeVideoActionSaveVideo": "Taking video, please hold still...",
|
||||||
"mainScreenTakeVideoActionUploadingVideo": "Uploading video...",
|
"mainScreenTakeVideoActionUploadingVideo": "Uploading video...",
|
||||||
|
|
||||||
|
"mainScreenHelpSheetTitle": "Record your best moments in life",
|
||||||
|
"mainScreenHelpSheetTakePhotoExplanation": "Tap on the shutter button once to take a photo.",
|
||||||
|
"mainScreenHelpSheetTakeVideoExplanation": "Hold down the shutter button to start recording a video. Leave the button to stop recording.",
|
||||||
|
|
||||||
"recordingOverlayIsRecording": "Recording",
|
"recordingOverlayIsRecording": "Recording",
|
||||||
|
|
||||||
|
|
||||||
@ -153,6 +158,13 @@
|
|||||||
|
|
||||||
|
|
||||||
"timelineScreenTitle": "Timeline",
|
"timelineScreenTitle": "Timeline",
|
||||||
|
"timelineScreenHelpSheetTitle": "Welcome to your timeline",
|
||||||
|
"timelineHelpContentDescription": "Your memories are displayed in chronological order. You can swipe left or right to navigate through the memories of the given day. You can also swipe up or down to navigate through the days of your memories. The timeline automatically progresses through your memories.",
|
||||||
|
"timelineHelpContentHoldDownExplanation": "Hold down to pause the timeline from progressing to your next memory.",
|
||||||
|
"timelineHelpContentTapTwiceExplanation": "Tap twice to see more details about your memory.",
|
||||||
|
|
||||||
|
|
||||||
|
"helpSheetDontShowAgain": "Don't show this help sheet again",
|
||||||
|
|
||||||
|
|
||||||
"enumMapping_ResolutionPreset_low": "Low",
|
"enumMapping_ResolutionPreset_low": "Low",
|
||||||
|
@ -85,7 +85,9 @@ class _MyAppState extends State<MyApp> {
|
|||||||
TimelineScreen.ID: (context) => const TimelineScreen(),
|
TimelineScreen.ID: (context) => const TimelineScreen(),
|
||||||
GrantPermissionScreen.ID: (context) => const GrantPermissionScreen(),
|
GrantPermissionScreen.ID: (context) => const GrantPermissionScreen(),
|
||||||
CalendarScreen.ID: (context) => const CalendarScreen(),
|
CalendarScreen.ID: (context) => const CalendarScreen(),
|
||||||
ServerLoadingScreen.ID: (context) => const ServerLoadingScreen(),
|
ServerLoadingScreen.ID: (context) => const ServerLoadingScreen(
|
||||||
|
isInitialLoading: true,
|
||||||
|
),
|
||||||
EmptyScreen.ID: (context) => const EmptyScreen(),
|
EmptyScreen.ID: (context) => const EmptyScreen(),
|
||||||
SettingsScreen.ID: (context) => const SettingsScreen(),
|
SettingsScreen.ID: (context) => const SettingsScreen(),
|
||||||
},
|
},
|
||||||
|
@ -14,12 +14,16 @@ class CacheManager {
|
|||||||
final existingEntry = await storage.read(key: cacheKey);
|
final existingEntry = await storage.read(key: cacheKey);
|
||||||
|
|
||||||
if (existingEntry != null) {
|
if (existingEntry != null) {
|
||||||
|
try {
|
||||||
final entry = jsonDecode(existingEntry);
|
final entry = jsonDecode(existingEntry);
|
||||||
final DateTime creationDate = DateTime.parse(entry['creationDate']);
|
final DateTime creationDate = DateTime.parse(entry['creationDate']);
|
||||||
|
|
||||||
// Check if the entry is still valid using CACHE_INVALIDATION_DURATION as the validity duration.
|
// Check if the entry is still valid using CACHE_INVALIDATION_DURATION as the validity duration.
|
||||||
return DateTime.now().difference(creationDate) <
|
return DateTime.now().difference(creationDate) <
|
||||||
CACHE_INVALIDATION_DURATION;
|
CACHE_INVALIDATION_DURATION;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
27
lib/managers/user_help_sheets_manager.dart
Normal file
27
lib/managers/user_help_sheets_manager.dart
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/help_sheet_id.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/storage_keys.dart';
|
||||||
|
|
||||||
|
const storage = FlutterSecureStorage();
|
||||||
|
|
||||||
|
class UserHelpSheetsManager {
|
||||||
|
static String _createKey(final HelpSheetID helpID) =>
|
||||||
|
'$USER_HELP_SHEETS_KEY/$helpID';
|
||||||
|
|
||||||
|
static Future<bool> getIfAlreadyShown(final HelpSheetID helpID) async =>
|
||||||
|
(await storage.read(key: _createKey(helpID))) == 'true';
|
||||||
|
|
||||||
|
static Future<void> setAsShown(final HelpSheetID helpID) async =>
|
||||||
|
storage.write(
|
||||||
|
key: _createKey(helpID),
|
||||||
|
value: 'true',
|
||||||
|
);
|
||||||
|
|
||||||
|
static Future<void> deleteAll() async {
|
||||||
|
const keys = HelpSheetID.values;
|
||||||
|
|
||||||
|
for (final key in keys) {
|
||||||
|
await storage.delete(key: _createKey(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -94,7 +94,14 @@ class _LoginScreenState extends AuthState<LoginScreen> with Loadable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.pushReplacementNamed(context, ServerLoadingScreen.ID);
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => ServerLoadingScreen(
|
||||||
|
nextScreen: MainScreen.ID,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,25 +1,30 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
|
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
import 'package:location/location.dart';
|
import 'package:location/location.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/help_sheet_id.dart';
|
||||||
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
import 'package:quid_faciam_hodie/constants/values.dart';
|
import 'package:quid_faciam_hodie/constants/values.dart';
|
||||||
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
|
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
|
||||||
import 'package:quid_faciam_hodie/managers/file_manager.dart';
|
import 'package:quid_faciam_hodie/managers/file_manager.dart';
|
||||||
import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
|
import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
|
||||||
|
import 'package:quid_faciam_hodie/screens/main_screen/camera_help_content.dart';
|
||||||
import 'package:quid_faciam_hodie/screens/main_screen/settings_button_overlay.dart';
|
import 'package:quid_faciam_hodie/screens/main_screen/settings_button_overlay.dart';
|
||||||
import 'package:quid_faciam_hodie/utils/auth_required.dart';
|
import 'package:quid_faciam_hodie/utils/auth_required.dart';
|
||||||
import 'package:quid_faciam_hodie/utils/loadable.dart';
|
import 'package:quid_faciam_hodie/utils/loadable.dart';
|
||||||
import 'package:quid_faciam_hodie/utils/tag_location_to_image.dart';
|
import 'package:quid_faciam_hodie/utils/tag_location_to_image.dart';
|
||||||
import 'package:quid_faciam_hodie/widgets/animate_in_builder.dart';
|
import 'package:quid_faciam_hodie/widgets/animate_in_builder.dart';
|
||||||
import 'package:quid_faciam_hodie/widgets/fade_and_move_in_animation.dart';
|
import 'package:quid_faciam_hodie/widgets/fade_and_move_in_animation.dart';
|
||||||
|
import 'package:quid_faciam_hodie/widgets/help_sheet.dart';
|
||||||
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
|
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
|
||||||
import 'package:quid_faciam_hodie/widgets/sheet_indicator.dart';
|
import 'package:quid_faciam_hodie/widgets/sheet_indicator.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
@ -330,7 +335,11 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return HelpSheet(
|
||||||
|
title: localizations.mainScreenHelpSheetTitle,
|
||||||
|
helpContent: const CameraHelpContent(),
|
||||||
|
helpID: HelpSheetID.mainScreen,
|
||||||
|
child: Container(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
child: ExpandableBottomSheet(
|
child: ExpandableBottomSheet(
|
||||||
background: SafeArea(
|
background: SafeArea(
|
||||||
@ -400,8 +409,8 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
child: ChangeCameraButton(
|
child: ChangeCameraButton(
|
||||||
disabled: lockCamera || isRecording,
|
disabled: lockCamera || isRecording,
|
||||||
onChangeCamera: () {
|
onChangeCamera: () {
|
||||||
final currentCameraIndex = GlobalValuesManager
|
final currentCameraIndex =
|
||||||
.cameras
|
GlobalValuesManager.cameras
|
||||||
.indexOf(controller!.description);
|
.indexOf(controller!.description);
|
||||||
final availableCameras =
|
final availableCameras =
|
||||||
GlobalValuesManager.cameras.length;
|
GlobalValuesManager.cameras.length;
|
||||||
@ -477,11 +486,13 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
MaterialStateProperty.resolveWith<Color>(
|
MaterialStateProperty.resolveWith<Color>(
|
||||||
(_) => isTorchEnabled ? Colors.white : Colors.black,
|
(_) =>
|
||||||
|
isTorchEnabled ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
foregroundColor:
|
foregroundColor:
|
||||||
MaterialStateProperty.resolveWith<Color>(
|
MaterialStateProperty.resolveWith<Color>(
|
||||||
(_) => isTorchEnabled ? Colors.black : Colors.white,
|
(_) =>
|
||||||
|
isTorchEnabled ? Colors.black : Colors.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -497,8 +508,8 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
},
|
},
|
||||||
child: IconButtonChild(
|
child: IconButtonChild(
|
||||||
icon: const Icon(Icons.flashlight_on_rounded),
|
icon: const Icon(Icons.flashlight_on_rounded),
|
||||||
label:
|
label: Text(
|
||||||
Text(localizations.mainScreenActionsTorchButton),
|
localizations.mainScreenActionsTorchButton),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
@ -537,6 +548,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}(),
|
}(),
|
||||||
),
|
),
|
||||||
|
60
lib/screens/main_screen/camera_help_content.dart
Normal file
60
lib/screens/main_screen/camera_help_content.dart
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
|
import 'package:quid_faciam_hodie/utils/theme.dart';
|
||||||
|
import 'package:quid_faciam_hodie/widgets/help_content_text.dart';
|
||||||
|
|
||||||
|
class CameraHelpContent extends StatelessWidget {
|
||||||
|
const CameraHelpContent({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final localizations = AppLocalizations.of(context)!;
|
||||||
|
final iconColor = getBodyTextColor(context).withOpacity(.2);
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
HelpContentText(
|
||||||
|
icon: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
Icons.circle_rounded,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.circle_rounded,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 13,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
text: localizations.mainScreenHelpSheetTakePhotoExplanation,
|
||||||
|
),
|
||||||
|
const SizedBox(height: MEDIUM_SPACE),
|
||||||
|
HelpContentText(
|
||||||
|
icon: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
Icons.circle_rounded,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
Icon(
|
||||||
|
Icons.circle_rounded,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 19,
|
||||||
|
),
|
||||||
|
Icon(
|
||||||
|
Icons.square_rounded,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 10,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
text: localizations.mainScreenHelpSheetTakeVideoExplanation,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,11 +5,11 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
|
import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
|
||||||
import 'package:quid_faciam_hodie/models/memories.dart';
|
import 'package:quid_faciam_hodie/models/memories.dart';
|
||||||
import 'package:quid_faciam_hodie/screens/grant_permission_screen.dart';
|
|
||||||
import 'package:quid_faciam_hodie/screens/login_screen.dart';
|
import 'package:quid_faciam_hodie/screens/login_screen.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
|
|
||||||
import 'empty_screen.dart';
|
import 'empty_screen.dart';
|
||||||
|
import 'grant_permission_screen.dart';
|
||||||
import 'main_screen.dart';
|
import 'main_screen.dart';
|
||||||
import 'server_loading_screen/dot_animation.dart';
|
import 'server_loading_screen/dot_animation.dart';
|
||||||
import 'welcome_screen.dart';
|
import 'welcome_screen.dart';
|
||||||
@ -18,10 +18,12 @@ class ServerLoadingScreen extends StatefulWidget {
|
|||||||
static const ID = '/';
|
static const ID = '/';
|
||||||
|
|
||||||
final String? nextScreen;
|
final String? nextScreen;
|
||||||
|
final bool isInitialLoading;
|
||||||
|
|
||||||
const ServerLoadingScreen({
|
const ServerLoadingScreen({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.nextScreen,
|
this.nextScreen,
|
||||||
|
this.isInitialLoading = false,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -33,16 +35,28 @@ class _ServerLoadingScreenState extends State<ServerLoadingScreen> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
load();
|
load();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> load() async {
|
Future<void> load() async {
|
||||||
|
if (widget.isInitialLoading) {
|
||||||
|
await Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
WelcomeScreen.ID,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.nextScreen != WelcomeScreen.ID) {
|
||||||
while (!(await GlobalValuesManager.hasGrantedPermissions())) {
|
while (!(await GlobalValuesManager.hasGrantedPermissions())) {
|
||||||
await Navigator.pushNamed(
|
await Navigator.pushNamed(
|
||||||
context,
|
context,
|
||||||
GrantPermissionScreen.ID,
|
GrantPermissionScreen.ID,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await GlobalValuesManager.waitForInitialization();
|
await GlobalValuesManager.waitForInitialization();
|
||||||
|
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/help_sheet_id.dart';
|
||||||
import 'package:quid_faciam_hodie/extensions/date.dart';
|
import 'package:quid_faciam_hodie/extensions/date.dart';
|
||||||
import 'package:quid_faciam_hodie/models/memories.dart';
|
import 'package:quid_faciam_hodie/models/memories.dart';
|
||||||
import 'package:quid_faciam_hodie/models/timeline.dart';
|
import 'package:quid_faciam_hodie/models/timeline.dart';
|
||||||
|
import 'package:quid_faciam_hodie/screens/timeline_screen/timeline_help_content.dart';
|
||||||
import 'package:quid_faciam_hodie/utils/loadable.dart';
|
import 'package:quid_faciam_hodie/utils/loadable.dart';
|
||||||
|
import 'package:quid_faciam_hodie/widgets/help_sheet.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
import 'calendar_screen.dart';
|
import 'calendar_screen.dart';
|
||||||
import 'empty_screen.dart';
|
import 'empty_screen.dart';
|
||||||
@ -111,6 +114,15 @@ class _TimelineScreenState extends State<TimelineScreen> with Loadable {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
child: HelpSheet(
|
||||||
|
title: localizations.timelineScreenHelpSheetTitle,
|
||||||
|
helpContent: const TimelineHelpContent(),
|
||||||
|
helpID: HelpSheetID.timelineScreen,
|
||||||
|
onSheetShown: timeline.pause,
|
||||||
|
onSheetHidden: () {
|
||||||
|
timeline.resume();
|
||||||
|
print("dfsjnifksdf");
|
||||||
|
},
|
||||||
child: PlatformScaffold(
|
child: PlatformScaffold(
|
||||||
appBar: isCupertino(context)
|
appBar: isCupertino(context)
|
||||||
? PlatformAppBar(
|
? PlatformAppBar(
|
||||||
@ -138,6 +150,7 @@ class _TimelineScreenState extends State<TimelineScreen> with Loadable {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
lib/screens/timeline_screen/timeline_help_content.dart
Normal file
41
lib/screens/timeline_screen/timeline_help_content.dart
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
|
import 'package:quid_faciam_hodie/utils/theme.dart';
|
||||||
|
import 'package:quid_faciam_hodie/widgets/help_content_text.dart';
|
||||||
|
|
||||||
|
class TimelineHelpContent extends StatelessWidget {
|
||||||
|
const TimelineHelpContent({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final localizations = AppLocalizations.of(context)!;
|
||||||
|
final textColor = getBodyTextColor(context);
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
localizations.timelineHelpContentDescription,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: getBodyTextTextStyle(context),
|
||||||
|
),
|
||||||
|
const SizedBox(height: LARGE_SPACE),
|
||||||
|
HelpContentText(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.touch_app_rounded,
|
||||||
|
color: textColor,
|
||||||
|
),
|
||||||
|
text: localizations.timelineHelpContentHoldDownExplanation,
|
||||||
|
),
|
||||||
|
const SizedBox(height: MEDIUM_SPACE),
|
||||||
|
HelpContentText(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.align_vertical_bottom_sharp,
|
||||||
|
color: textColor,
|
||||||
|
),
|
||||||
|
text: localizations.timelineHelpContentTapTwiceExplanation,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
|
import 'package:quid_faciam_hodie/managers/user_help_sheets_manager.dart';
|
||||||
|
|
||||||
import 'welcome_screen/pages/get_started_page.dart';
|
import 'welcome_screen/pages/get_started_page.dart';
|
||||||
import 'welcome_screen/pages/guide_page.dart';
|
import 'welcome_screen/pages/guide_page.dart';
|
||||||
@ -19,6 +20,13 @@ class WelcomeScreen extends StatefulWidget {
|
|||||||
class _WelcomeScreenState extends State<WelcomeScreen> {
|
class _WelcomeScreenState extends State<WelcomeScreen> {
|
||||||
final controller = PageController();
|
final controller = PageController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
UserHelpSheetsManager.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
controller.dispose();
|
controller.dispose();
|
||||||
|
@ -24,9 +24,11 @@ mixin Loadable {
|
|||||||
try {
|
try {
|
||||||
await callback();
|
await callback();
|
||||||
} finally {
|
} finally {
|
||||||
|
try {
|
||||||
setState(() {
|
setState(() {
|
||||||
_IDs.remove(id ?? _generalLoadingID);
|
_IDs.remove(id ?? _generalLoadingID);
|
||||||
});
|
});
|
||||||
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
lib/widgets/help_content_text.dart
Normal file
34
lib/widgets/help_content_text.dart
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:quid_faciam_hodie/utils/theme.dart';
|
||||||
|
|
||||||
|
class HelpContentText extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final Widget icon;
|
||||||
|
|
||||||
|
const HelpContentText({
|
||||||
|
Key? key,
|
||||||
|
required this.text,
|
||||||
|
required this.icon,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: icon,
|
||||||
|
),
|
||||||
|
const Spacer(flex: 1),
|
||||||
|
Expanded(
|
||||||
|
flex: 8,
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: getBodyTextTextStyle(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
117
lib/widgets/help_sheet.dart
Normal file
117
lib/widgets/help_sheet.dart
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/help_sheet_id.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
|
import 'package:quid_faciam_hodie/managers/user_help_sheets_manager.dart';
|
||||||
|
import 'package:quid_faciam_hodie/widgets/help_sheet/help_sheet_form.dart';
|
||||||
|
|
||||||
|
class HelpSheet extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
final String title;
|
||||||
|
final Widget helpContent;
|
||||||
|
final HelpSheetID helpID;
|
||||||
|
final bool forceShow;
|
||||||
|
final VoidCallback? onSheetShown;
|
||||||
|
final VoidCallback? onSheetHidden;
|
||||||
|
|
||||||
|
const HelpSheet({
|
||||||
|
Key? key,
|
||||||
|
required this.child,
|
||||||
|
required this.title,
|
||||||
|
required this.helpContent,
|
||||||
|
required this.helpID,
|
||||||
|
this.forceShow = false,
|
||||||
|
this.onSheetShown,
|
||||||
|
this.onSheetHidden,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HelpSheet> createState() => _HelpSheetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HelpSheetState extends State<HelpSheet> {
|
||||||
|
bool isShowingSheet = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
if (widget.forceShow) {
|
||||||
|
showSheet();
|
||||||
|
} else {
|
||||||
|
checkIfSheetShouldBeShown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void showSheet() {
|
||||||
|
if (isShowingSheet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
isShowingSheet = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (widget.onSheetShown != null) {
|
||||||
|
widget.onSheetShown!();
|
||||||
|
}
|
||||||
|
|
||||||
|
final dontShowSheetAgain = await showPlatformModalSheet(
|
||||||
|
material: MaterialModalSheetData(
|
||||||
|
isDismissible: false,
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(LARGE_SPACE),
|
||||||
|
topRight: Radius.circular(LARGE_SPACE),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
context: context,
|
||||||
|
builder: (_) => HelpSheetForm(
|
||||||
|
helpContent: widget.helpContent,
|
||||||
|
title: widget.title,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (widget.onSheetHidden != null) {
|
||||||
|
widget.onSheetHidden!();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
isShowingSheet = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dontShowSheetAgain) {
|
||||||
|
await UserHelpSheetsManager.setAsShown(widget.helpID);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> checkIfSheetShouldBeShown() async {
|
||||||
|
final hasSheetBeShownAlready =
|
||||||
|
await UserHelpSheetsManager.getIfAlreadyShown(widget.helpID);
|
||||||
|
|
||||||
|
if (!hasSheetBeShownAlready) {
|
||||||
|
showSheet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedScale(
|
||||||
|
scale: isShowingSheet ? .99 : 1,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
child: widget.child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
67
lib/widgets/help_sheet/help_sheet_form.dart
Normal file
67
lib/widgets/help_sheet/help_sheet_form.dart
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
|
import 'package:quid_faciam_hodie/utils/theme.dart';
|
||||||
|
import 'package:quid_faciam_hodie/widgets/modal_sheet.dart';
|
||||||
|
|
||||||
|
class HelpSheetForm extends StatefulWidget {
|
||||||
|
final String title;
|
||||||
|
final Widget helpContent;
|
||||||
|
|
||||||
|
const HelpSheetForm({
|
||||||
|
Key? key,
|
||||||
|
required this.helpContent,
|
||||||
|
required this.title,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HelpSheetForm> createState() => _HelpSheetFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HelpSheetFormState extends State<HelpSheetForm> {
|
||||||
|
bool dontShowSheetAgain = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final localizations = AppLocalizations.of(context)!;
|
||||||
|
|
||||||
|
return ModalSheet(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
widget.title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: getTitleTextStyle(context),
|
||||||
|
),
|
||||||
|
const SizedBox(height: MEDIUM_SPACE),
|
||||||
|
widget.helpContent,
|
||||||
|
const SizedBox(height: LARGE_SPACE),
|
||||||
|
PlatformElevatedButton(
|
||||||
|
child: Text(localizations.generalUnderstoodButtonLabel),
|
||||||
|
onPressed: () => Navigator.pop(context, dontShowSheetAgain),
|
||||||
|
),
|
||||||
|
const SizedBox(height: MEDIUM_SPACE),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
PlatformSwitch(
|
||||||
|
value: dontShowSheetAgain,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
dontShowSheetAgain = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(width: SMALL_SPACE),
|
||||||
|
Text(
|
||||||
|
localizations.helpSheetDontShowAgain,
|
||||||
|
style: getBodyTextTextStyle(context),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
|
import 'package:quid_faciam_hodie/utils/theme.dart';
|
||||||
|
|
||||||
class ModalSheet extends StatelessWidget {
|
class ModalSheet extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
@ -12,30 +14,37 @@ class ModalSheet extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Wrap(
|
final innerChild = Padding(
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE),
|
||||||
children: <Widget>[
|
child: child,
|
||||||
Padding(
|
);
|
||||||
padding:
|
|
||||||
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
|
return Column(
|
||||||
child: Material(
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
PlatformWidget(
|
||||||
|
material: (_, __) => Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(LARGE_SPACE),
|
topLeft: Radius.circular(LARGE_SPACE),
|
||||||
topRight: Radius.circular(LARGE_SPACE),
|
topRight: Radius.circular(LARGE_SPACE),
|
||||||
),
|
),
|
||||||
color: platformThemeData(
|
color: getSheetColor(context),
|
||||||
context,
|
|
||||||
material: (data) =>
|
|
||||||
data.bottomSheetTheme.modalBackgroundColor ??
|
|
||||||
data.bottomAppBarColor,
|
|
||||||
cupertino: (data) => data.barBackgroundColor,
|
|
||||||
),
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: MEDIUM_SPACE),
|
||||||
|
child: innerChild,
|
||||||
|
),
|
||||||
|
cupertino: (_, __) => CupertinoPopupSurface(
|
||||||
|
isSurfacePainted: false,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(MEDIUM_SPACE),
|
color: Colors.white,
|
||||||
child: child,
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: LARGE_SPACE),
|
||||||
|
child: innerChild,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user