diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 244c517..d25e8bd 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -1,7 +1,13 @@
PODS:
+ - Alamofire (5.6.2)
- camera_avfoundation (0.0.1):
- Flutter
- Flutter (1.0.0)
+ - flutter_osm_plugin (0.0.1):
+ - Alamofire
+ - Flutter
+ - Polyline
+ - Tangram-es
- flutter_secure_storage (3.3.1):
- Flutter
- fluttertoast (0.0.2):
@@ -9,10 +15,14 @@ PODS:
- Toast
- gallery_saver (0.0.1):
- Flutter
+ - location (0.0.1):
+ - Flutter
- path_provider_ios (0.0.1):
- Flutter
- permission_handler_apple (9.0.4):
- Flutter
+ - Polyline (5.0.2)
+ - Tangram-es (0.17.1)
- Toast (4.0.0)
- uni_links (0.0.1):
- Flutter
@@ -24,9 +34,11 @@ PODS:
DEPENDENCIES:
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
- Flutter (from `Flutter`)
+ - flutter_osm_plugin (from `.symlinks/plugins/flutter_osm_plugin/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- gallery_saver (from `.symlinks/plugins/gallery_saver/ios`)
+ - location (from `.symlinks/plugins/location/ios`)
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- uni_links (from `.symlinks/plugins/uni_links/ios`)
@@ -35,6 +47,9 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
+ - Alamofire
+ - Polyline
+ - Tangram-es
- Toast
EXTERNAL SOURCES:
@@ -42,12 +57,16 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/camera_avfoundation/ios"
Flutter:
:path: Flutter
+ flutter_osm_plugin:
+ :path: ".symlinks/plugins/flutter_osm_plugin/ios"
flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
gallery_saver:
:path: ".symlinks/plugins/gallery_saver/ios"
+ location:
+ :path: ".symlinks/plugins/location/ios"
path_provider_ios:
:path: ".symlinks/plugins/path_provider_ios/ios"
permission_handler_apple:
@@ -60,18 +79,23 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/video_player_avfoundation/ios"
SPEC CHECKSUMS:
+ Alamofire: d368e1ff8a298e6dde360e35a3e68e6c610e7204
camera_avfoundation: 07c77549ea54ad95d8581be86617c094a46280d9
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
+ flutter_osm_plugin: f06ae1e854af57270c61ae27bdb8a386cfd4afa5
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
fluttertoast: 16fbe6039d06a763f3533670197d01fc73459037
gallery_saver: 9fc173c9f4fcc48af53b2a9ebea1b643255be542
+ location: 3a2eed4dd2fab25e7b7baf2a9efefe82b512d740
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
+ Polyline: fce41d72e1146c41c6d081f7656827226f643dff
+ Tangram-es: 628b634f7fc09d2217469b9914de00d9de49ff9d
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff
-PODFILE CHECKSUM: 844e8fbcd0235060f60f771d03577fc655617b90
+PODFILE CHECKSUM: c1e56e861085e01c426a686306e59660903e6fa6
COCOAPODS: 1.11.3
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 9e55a95..b4b9d37 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -75,5 +75,8 @@
NSLocationUsageDescription
Accessing your location allows you to tag your memories
+
+ NSLocationWhenInUseUsageDescription
+ Accessing your location allows you to tag your memories
diff --git a/lib/screens/grant_permission_screen.dart b/lib/screens/grant_permission_screen.dart
index d197703..6e57801 100644
--- a/lib/screens/grant_permission_screen.dart
+++ b/lib/screens/grant_permission_screen.dart
@@ -3,6 +3,7 @@ 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/screens/login_screen.dart';
+import 'package:quid_faciam_hodie/screens/server_loading_screen.dart';
import 'grant_permission_screen/permissions_required_page.dart';
@@ -24,7 +25,14 @@ class GrantPermissionScreen extends StatelessWidget {
child: Center(
child: PermissionsRequiredPage(
onPermissionsGranted: () {
- Navigator.pushReplacementNamed(context, LoginScreen.ID);
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const ServerLoadingScreen(
+ nextScreen: LoginScreen.ID,
+ ),
+ ),
+ );
},
),
),
diff --git a/lib/screens/grant_permission_screen/permissions_required_page.dart b/lib/screens/grant_permission_screen/permissions_required_page.dart
index e19137c..531742c 100644
--- a/lib/screens/grant_permission_screen/permissions_required_page.dart
+++ b/lib/screens/grant_permission_screen/permissions_required_page.dart
@@ -156,7 +156,7 @@ class _PermissionsRequiredPageState extends State {
children: [
Text(
localizations
- .permissionsRequiredPageGrantMicrophonePermission,
+ .permissionsRequiredPageGrantLocationPermission,
),
if (hasGrantedLocationPermission)
Icon(context.platformIcons.checkMark),
diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart
index a0988b1..14c302a 100644
--- a/lib/screens/main_screen.dart
+++ b/lib/screens/main_screen.dart
@@ -219,10 +219,12 @@ class _MainScreenState extends AuthRequiredState with Loadable {
LocationData? locationData;
- if (Platform.isAndroid && (await Permission.location.isGranted)) {
+ if (await Permission.location.isGranted) {
locationData = await Location().getLocation();
- await tagLocationToImage(file, locationData);
+ if (Platform.isAndroid) {
+ await tagLocationToImage(file, locationData);
+ }
}
try {
diff --git a/lib/screens/server_loading_screen.dart b/lib/screens/server_loading_screen.dart
index 45264a6..26c0845 100644
--- a/lib/screens/server_loading_screen.dart
+++ b/lib/screens/server_loading_screen.dart
@@ -48,7 +48,12 @@ class _ServerLoadingScreenState extends State {
final memories = context.read();
final session = Supabase.instance.client.auth.session();
- if (session != null) {
+ if (session == null) {
+ Navigator.pushReplacementNamed(
+ context,
+ WelcomeScreen.ID,
+ );
+ } else {
if (!memories.isInitialized) {
await memories.initialize();
}
@@ -58,7 +63,7 @@ class _ServerLoadingScreenState extends State {
}
if (widget.nextScreen == null) {
- Navigator.pushNamed(
+ Navigator.pushReplacementNamed(
context,
MainScreen.ID,
);
@@ -75,11 +80,6 @@ class _ServerLoadingScreenState extends State {
);
}
}
- } else {
- Navigator.pushReplacementNamed(
- context,
- WelcomeScreen.ID,
- );
}
}
diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart
index d01e5d0..0dd695b 100644
--- a/lib/screens/settings_screen.dart
+++ b/lib/screens/settings_screen.dart
@@ -13,6 +13,7 @@ import 'package:quid_faciam_hodie/screens/welcome_screen.dart';
import 'package:quid_faciam_hodie/utils/auth_required.dart';
import 'package:quid_faciam_hodie/utils/loadable.dart';
import 'package:quid_faciam_hodie/utils/theme.dart';
+import 'package:quid_faciam_hodie/widgets/cupertino_dropdown.dart';
import 'package:settings_ui/settings_ui.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
@@ -81,11 +82,49 @@ class _SettingsScreenState extends AuthRequiredState
);
}
+ Widget getPicker() {
+ final settings = GlobalValuesManager.settings!;
+ final resolutionTextMapping = getResolutionTextMapping(context);
+ final items = ResolutionPreset.values
+ .map(
+ (value) => DropdownMenuItem(
+ value: value,
+ child: Text(resolutionTextMapping[value]!),
+ ),
+ )
+ .toList();
+
+ if (isMaterial(context)) {
+ return DropdownButtonFormField(
+ value: settings.resolution,
+ onChanged: (value) {
+ if (value == null) {
+ return;
+ }
+
+ settings.setResolution(value);
+ },
+ items: items,
+ );
+ } else {
+ return CupertinoDropdownButton(
+ itemExtent: 30,
+ onChanged: (value) {
+ if (value == null) {
+ return;
+ }
+
+ settings.setResolution(value);
+ },
+ value: settings.resolution,
+ items: items,
+ );
+ }
+ }
+
@override
Widget build(BuildContext context) {
- final settings = GlobalValuesManager.settings!;
final localizations = AppLocalizations.of(context)!;
- final resolutionTextMapping = getResolutionTextMapping(context);
return PlatformScaffold(
appBar: PlatformAppBar(
@@ -163,23 +202,7 @@ class _SettingsScreenState extends AuthRequiredState
localizations
.settingsScreenGeneralSectionQualityLabel,
),
- title: DropdownButtonFormField(
- value: settings.resolution,
- onChanged: (value) async {
- if (value == null) {
- return;
- }
-
- settings.setResolution(value);
- },
- items: ResolutionPreset.values
- .map((value) =>
- DropdownMenuItem(
- value: value,
- child: Text(resolutionTextMapping[value]!),
- ))
- .toList(),
- ),
+ title: getPicker(),
)
],
),
diff --git a/lib/screens/timeline_screen/memory_sheet.dart b/lib/screens/timeline_screen/memory_sheet.dart
index da57e1f..e7e6482 100644
--- a/lib/screens/timeline_screen/memory_sheet.dart
+++ b/lib/screens/timeline_screen/memory_sheet.dart
@@ -135,114 +135,114 @@ class _MemorySheetState extends State with Loadable {
background: GestureDetector(
onTap: () => Navigator.pop(context),
),
- persistentHeader: Container(
- padding: const EdgeInsets.all(MEDIUM_SPACE),
- decoration: BoxDecoration(
- color: backgroundColor,
- borderRadius: const BorderRadius.only(
- topLeft: Radius.circular(LARGE_SPACE),
- topRight: Radius.circular(LARGE_SPACE),
- ),
+ persistentHeader: Material(
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(LARGE_SPACE),
+ topRight: Radius.circular(LARGE_SPACE),
),
- child: Column(
- children: [
- if (widget.memory.location != null) ...[
- const Padding(
- padding: EdgeInsets.all(SMALL_SPACE),
- child: SheetIndicator(),
+ color: backgroundColor,
+ child: Padding(
+ padding: const EdgeInsets.all(MEDIUM_SPACE),
+ child: Column(
+ children: [
+ if (widget.memory.location != null) ...[
+ const Padding(
+ padding: EdgeInsets.all(SMALL_SPACE),
+ child: SheetIndicator(),
+ ),
+ const SizedBox(height: MEDIUM_SPACE),
+ ],
+ Text(
+ localizations.memorySheetTitle,
+ style: getTitleTextStyle(context),
),
const SizedBox(height: MEDIUM_SPACE),
- ],
- Text(
- localizations.memorySheetTitle,
- style: getTitleTextStyle(context),
- ),
- const SizedBox(height: MEDIUM_SPACE),
- ListTile(
- leading: PlatformWidget(
- cupertino: (_, __) => Icon(
- CupertinoIcons.down_arrow,
- color: getBodyTextColor(context),
- ),
- material: (_, __) => Icon(
- Icons.download,
- color: getBodyTextColor(context),
- ),
- ),
- title: Text(
- localizations.memorySheetDownloadMemory,
- style: getBodyTextTextStyle(context),
- ),
- enabled: !getIsLoadingSpecificID('download'),
- onTap: getIsLoadingSpecificID('download')
- ? null
- : () => callWithLoading(downloadFile, 'download'),
- trailing: getIsLoadingSpecificID('download')
- ? buildLoadingIndicator()
- : null,
- ),
- ListTile(
- leading: Icon(
- widget.memory.isPublic
- ? Icons.public_off_rounded
- : Icons.public,
- color: getBodyTextColor(context),
- ),
- title: Text(
- widget.memory.isPublic
- ? localizations.memorySheetUpdateMemoryMakePrivate
- : localizations.memorySheetUpdateMemoryMakePublic,
- style: getBodyTextTextStyle(context),
- ),
- enabled: !getIsLoadingSpecificID('public'),
- onTap: getIsLoadingSpecificID('public')
- ? null
- : () => callWithLoading(changeVisibility, 'public'),
- trailing: getIsLoadingSpecificID('public')
- ? buildLoadingIndicator()
- : null,
- ),
- ListTile(
- leading: Icon(
- context.platformIcons.delete,
- color: getBodyTextColor(context),
- ),
- title: Text(
- localizations.memorySheetDeleteMemory,
- style: getBodyTextTextStyle(context),
- ),
- enabled: !getIsLoadingSpecificID('delete'),
- onTap: getIsLoadingSpecificID('delete')
- ? null
- : () => callWithLoading(deleteFile, 'delete'),
- trailing: getIsLoadingSpecificID('delete')
- ? buildLoadingIndicator()
- : null,
- ),
- const SizedBox(height: MEDIUM_SPACE),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(
- context.platformIcons.time,
- size: platformThemeData(
- context,
- material: (data) => data.textTheme.bodyLarge!.fontSize,
- cupertino: (data) => data.textTheme.textStyle.fontSize,
+ ListTile(
+ leading: PlatformWidget(
+ cupertino: (_, __) => Icon(
+ CupertinoIcons.down_arrow,
+ color: getBodyTextColor(context),
+ ),
+ material: (_, __) => Icon(
+ Icons.download,
+ color: getBodyTextColor(context),
),
),
- const SizedBox(width: TINY_SPACE),
- Text(
- localizations.memorySheetCreatedAtDataKey(
- DateFormat.jms().format(
- widget.memory.creationDate,
- ),
- ),
+ title: Text(
+ localizations.memorySheetDownloadMemory,
style: getBodyTextTextStyle(context),
),
- ],
- ),
- ],
+ enabled: !getIsLoadingSpecificID('download'),
+ onTap: getIsLoadingSpecificID('download')
+ ? null
+ : () => callWithLoading(downloadFile, 'download'),
+ trailing: getIsLoadingSpecificID('download')
+ ? buildLoadingIndicator()
+ : null,
+ ),
+ ListTile(
+ leading: Icon(
+ widget.memory.isPublic
+ ? Icons.public_off_rounded
+ : Icons.public,
+ color: getBodyTextColor(context),
+ ),
+ title: Text(
+ widget.memory.isPublic
+ ? localizations.memorySheetUpdateMemoryMakePrivate
+ : localizations.memorySheetUpdateMemoryMakePublic,
+ style: getBodyTextTextStyle(context),
+ ),
+ enabled: !getIsLoadingSpecificID('public'),
+ onTap: getIsLoadingSpecificID('public')
+ ? null
+ : () => callWithLoading(changeVisibility, 'public'),
+ trailing: getIsLoadingSpecificID('public')
+ ? buildLoadingIndicator()
+ : null,
+ ),
+ ListTile(
+ leading: Icon(
+ context.platformIcons.delete,
+ color: getBodyTextColor(context),
+ ),
+ title: Text(
+ localizations.memorySheetDeleteMemory,
+ style: getBodyTextTextStyle(context),
+ ),
+ enabled: !getIsLoadingSpecificID('delete'),
+ onTap: getIsLoadingSpecificID('delete')
+ ? null
+ : () => callWithLoading(deleteFile, 'delete'),
+ trailing: getIsLoadingSpecificID('delete')
+ ? buildLoadingIndicator()
+ : null,
+ ),
+ const SizedBox(height: MEDIUM_SPACE),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Icon(
+ context.platformIcons.time,
+ size: platformThemeData(
+ context,
+ material: (data) => data.textTheme.bodyLarge!.fontSize,
+ cupertino: (data) => data.textTheme.textStyle.fontSize,
+ ),
+ ),
+ const SizedBox(width: TINY_SPACE),
+ Text(
+ localizations.memorySheetCreatedAtDataKey(
+ DateFormat.jms().format(
+ widget.memory.creationDate,
+ ),
+ ),
+ style: getBodyTextTextStyle(context),
+ ),
+ ],
+ ),
+ ],
+ ),
),
),
expandableContent: widget.memory.location == null
diff --git a/lib/widgets/cupertino_dropdown.dart b/lib/widgets/cupertino_dropdown.dart
new file mode 100644
index 0000000..810010f
--- /dev/null
+++ b/lib/widgets/cupertino_dropdown.dart
@@ -0,0 +1,116 @@
+// Adopted from https://github.com/Enough-Software/enough_platform_widgets/blob/main/lib/src/cupertino/cupertino_dropdown_button.dart
+import 'dart:math';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:quid_faciam_hodie/constants/spacing.dart';
+
+class CupertinoDropdownButton extends StatefulWidget {
+ final List>? items;
+ final List Function(BuildContext context)? selectedItemBuilder;
+ final T? value;
+ final void Function(T? value)? onChanged;
+ final double itemExtent;
+ final Widget? hint;
+
+ const CupertinoDropdownButton({
+ Key? key,
+ required this.items,
+ this.selectedItemBuilder,
+ this.value,
+ this.onChanged,
+ this.hint,
+ required this.itemExtent,
+ }) : super(key: key);
+
+ @override
+ _CupertinoDropdownButtonState createState() =>
+ _CupertinoDropdownButtonState();
+}
+
+class _CupertinoDropdownButtonState
+ extends State> {
+ int? _selectedIndex;
+
+ @override
+ Widget build(BuildContext context) {
+ final itms = widget.items;
+ if (itms == null || itms.isEmpty) {
+ return Container();
+ }
+ final builder = widget.selectedItemBuilder;
+ final children = (builder != null)
+ ? builder(context)
+ .map((widget) => Padding(
+ padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE),
+ child: FittedBox(child: widget),
+ ))
+ .toList()
+ : itms
+ .map((itm) => Padding(
+ padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE),
+ child: FittedBox(child: itm.child),
+ ))
+ .toList();
+ final currentValue = widget.value;
+
+ final currentIndex =
+ max(itms.indexWhere((item) => item.value == currentValue), 0);
+ final child = currentValue == null
+ ? widget.hint ?? const Icon(CupertinoIcons.arrow_down)
+ : children[currentIndex];
+ return CupertinoButton(
+ padding: const EdgeInsets.all(MEDIUM_SPACE),
+ child: FittedBox(child: child),
+ onPressed: () async {
+ final scrollController = (currentValue == null)
+ ? null
+ : FixedExtentScrollController(
+ initialItem: currentIndex,
+ );
+ final result = await showCupertinoModalPopup(
+ context: context,
+ builder: (context) => SizedBox(
+ width: MediaQuery.of(context).size.width,
+ height: MediaQuery.of(context).size.height * 0.7,
+ child: SafeArea(
+ child: Container(
+ color: CupertinoTheme.of(context).barBackgroundColor,
+ child: Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CupertinoButton(
+ child: const Icon(Icons.clear),
+ onPressed: () => Navigator.of(context).pop(false)),
+ CupertinoButton(
+ child: const Icon(CupertinoIcons.check_mark),
+ onPressed: () => Navigator.of(context).pop(true)),
+ ],
+ ),
+ Expanded(
+ child: CupertinoPicker(
+ itemExtent: widget.itemExtent,
+ onSelectedItemChanged: (index) =>
+ _selectedIndex = index,
+ scrollController: scrollController,
+ children: children,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ if (result == true && _selectedIndex != null) {
+ final callback = widget.onChanged;
+ if (callback != null) {
+ callback(widget.items![_selectedIndex!].value);
+ }
+ }
+ },
+ );
+ }
+}