improvements for iOS; bugfixes for loading screen

This commit is contained in:
Myzel394 2022-08-19 14:17:42 +02:00
parent e58462c313
commit 909d4f8d89
20 changed files with 271 additions and 227 deletions

View File

@ -1,5 +1,7 @@
PODS:
- Alamofire (5.6.2)
- apple_maps_flutter (0.0.1):
- Flutter
- camera_avfoundation (0.0.1):
- Flutter
- Flutter (1.0.0)
@ -32,6 +34,7 @@ PODS:
- Flutter
DEPENDENCIES:
- apple_maps_flutter (from `.symlinks/plugins/apple_maps_flutter/ios`)
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
- Flutter (from `Flutter`)
- flutter_osm_plugin (from `.symlinks/plugins/flutter_osm_plugin/ios`)
@ -53,6 +56,8 @@ SPEC REPOS:
- Toast
EXTERNAL SOURCES:
apple_maps_flutter:
:path: ".symlinks/plugins/apple_maps_flutter/ios"
camera_avfoundation:
:path: ".symlinks/plugins/camera_avfoundation/ios"
Flutter:
@ -80,6 +85,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Alamofire: d368e1ff8a298e6dde360e35a3e68e6c610e7204
apple_maps_flutter: c59725efea39e13e703cde52a1d2b14866ad68a8
camera_avfoundation: 07c77549ea54ad95d8581be86617c094a46280d9
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_osm_plugin: f06ae1e854af57270c61ae27bdb8a386cfd4afa5

View File

@ -52,7 +52,7 @@ class _MyAppState extends State<MyApp> {
}
Future<void> watchAuthenticationStatus() async {
await GlobalValuesManager.watchForInitialization();
await GlobalValuesManager.waitForInitialization();
Supabase.instance.client.auth.onAuthStateChange((event, session) {
switch (event) {

View File

@ -1,33 +1,17 @@
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
import 'package:quid_faciam_hodie/screens/main_screen.dart';
import 'package:quid_faciam_hodie/screens/welcome_screen.dart';
import 'package:supabase/supabase.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
class AuthState<T extends StatefulWidget> extends SupabaseAuthState<T> {
@override
void onUnauthenticated() {
if (mounted) {
Navigator.of(context)
.pushNamedAndRemoveUntil(WelcomeScreen.ID, (route) => false);
}
}
void onUnauthenticated() {}
@override
void onAuthenticated(Session session) {
if (mounted) {
Navigator.of(context)
.pushNamedAndRemoveUntil(MainScreen.ID, (route) => false);
}
}
void onAuthenticated(Session session) {}
@override
void onPasswordRecovery(Session session) {}
@override
void onErrorAuthenticating(String message) {
if (isMaterial(context)) context.showErrorSnackBar(message: message);
}
void onErrorAuthenticating(String message) {}
}

View File

@ -17,7 +17,7 @@ final supabase = Supabase.instance.client;
class FileManager {
static Future<Memory> getMemoryMetadata(final String id) async {
await GlobalValuesManager.watchForInitialization();
await GlobalValuesManager.waitForInitialization();
final response = await supabase
.from('memories')
@ -38,7 +38,7 @@ class FileManager {
final File file, {
LocationData? locationData,
}) async {
await GlobalValuesManager.watchForInitialization();
await GlobalValuesManager.waitForInitialization();
final basename = uuid.v4();
final extension = file.path.split('.').last;
@ -108,7 +108,7 @@ class FileManager {
final bool disableDownloadCache = false,
final bool disableFileCache = false,
}) async {
await GlobalValuesManager.watchForInitialization();
await GlobalValuesManager.waitForInitialization();
final tempDirectory = await getTemporaryDirectory();
final filename = '${tempDirectory.path}/$path';
@ -129,7 +129,7 @@ class FileManager {
}
static Future<void> deleteFile(final String path) async {
await GlobalValuesManager.watchForInitialization();
await GlobalValuesManager.waitForInitialization();
final response =
await supabase.from('memories').delete().eq('location', path).execute();

View File

@ -52,7 +52,7 @@ class GlobalValuesManager {
_initializeSettings();
}
static Future<void> watchForInitialization() async {
static Future<void> waitForInitialization() async {
// Server initialization
if (_serverInitializationFuture == null) {
if (_isServerInitialized) {

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:math';
import 'package:http/http.dart' as http;
import 'package:quid_faciam_hodie/constants/apis.dart';
class PhotoManager {
static const MAX_PHOTOS_PER_PAGE = 80;
@ -10,7 +11,12 @@ class PhotoManager {
static Future<String> getRandomPhoto(final String query) async {
final url =
'https://api.pexels.com/v1/search?query=$query&per_page=$MAX_PHOTOS_PER_PAGE&orientation=portait';
final response = await http.get(Uri.parse(url));
final response = await http.get(
Uri.parse(url),
headers: {
'Authorization': PEXELS_API_KEY,
},
);
final data = jsonDecode(response.body);
final photoIndex = Random().nextInt(data['per_page']);

View File

@ -109,7 +109,7 @@ class Memories extends PropertyChangeNotifier<String> {
}
Future<void> _loadInitialData() async {
await GlobalValuesManager.watchForInitialization();
await GlobalValuesManager.waitForInitialization();
final response = await supabase
.from('memories')

View File

@ -2,8 +2,6 @@ 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/screens/login_screen.dart';
import 'package:quid_faciam_hodie/screens/server_loading_screen.dart';
import 'grant_permission_screen/permissions_required_page.dart';
@ -25,14 +23,7 @@ class GrantPermissionScreen extends StatelessWidget {
child: Center(
child: PermissionsRequiredPage(
onPermissionsGranted: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ServerLoadingScreen(
nextScreen: LoginScreen.ID,
),
),
);
Navigator.pop(context);
},
),
),

View File

@ -118,7 +118,7 @@ class _PermissionsRequiredPageState extends State<PermissionsRequiredPage> {
),
),
),
const SizedBox(height: MEDIUM_SPACE),
const SizedBox(height: SMALL_SPACE),
PlatformTextButton(
onPressed: hasGrantedMicrophonePermission
? null
@ -142,6 +142,7 @@ class _PermissionsRequiredPageState extends State<PermissionsRequiredPage> {
),
),
),
const SizedBox(height: SMALL_SPACE),
PlatformTextButton(
onPressed: hasGrantedLocationPermission
? null

View File

@ -1,7 +1,6 @@
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/foreign_types/memory_location.dart';
@ -10,6 +9,8 @@ import 'package:quid_faciam_hodie/utils/lookup_address.dart';
import 'package:quid_faciam_hodie/utils/theme.dart';
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
import 'package:quid_faciam_hodie/widgets/key_value_info.dart';
import 'package:quid_faciam_hodie/widgets/platform_widgets/memory_cupertino_maps.dart';
import 'package:quid_faciam_hodie/widgets/platform_widgets/memory_material_maps.dart';
import 'package:quid_faciam_hodie/widgets/sheet_indicator.dart';
import 'package:url_launcher/url_launcher.dart';
@ -26,7 +27,6 @@ class MemoryMapScreen extends StatefulWidget {
}
class _MemoryMapScreenState extends State<MemoryMapScreen> with Loadable {
late final MapController controller;
String? address;
@override
@ -34,13 +34,6 @@ class _MemoryMapScreenState extends State<MemoryMapScreen> with Loadable {
super.initState();
callWithLoading(fetchAddress);
controller = MapController(
initPosition: GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
),
);
}
Future<void> fetchAddress() async {
@ -60,34 +53,6 @@ class _MemoryMapScreenState extends State<MemoryMapScreen> with Loadable {
}
}
void drawCircle() => controller.drawCircle(
CircleOSM(
key: 'accuracy',
color: Colors.blue,
centerPoint: GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
),
radius: widget.location.accuracy,
strokeWidth: 4,
),
);
List<StaticPositionGeoPoint> get staticPoints => [
StaticPositionGeoPoint(
'position',
const MarkerIcon(
icon: Icon(Icons.location_on, size: 150, color: Colors.blue),
),
[
GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
)
],
)
];
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
@ -99,16 +64,15 @@ class _MemoryMapScreenState extends State<MemoryMapScreen> with Loadable {
),
body: ExpandableBottomSheet(
enableToggle: true,
background: OSMFlutter(
controller: controller,
initZoom: 13,
stepZoom: 1.0,
trackMyPosition: true,
staticPoints: staticPoints,
onMapIsReady: (_) {
drawCircle();
},
),
background: isMaterial(context)
? MemoryMaterialMaps(
location: widget.location,
initialZoom: 13,
)
: MemoryCupertinoMaps(
location: widget.location,
initialZoom: 13,
),
persistentHeader: Container(
width: double.infinity,
padding: const EdgeInsets.all(SMALL_SPACE),

View File

@ -6,6 +6,7 @@ import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/managers/global_values_manager.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:supabase_flutter/supabase_flutter.dart';
import 'empty_screen.dart';
@ -36,23 +37,32 @@ class _ServerLoadingScreenState extends State<ServerLoadingScreen> {
}
Future<void> load() async {
if (!(await GlobalValuesManager.hasGrantedPermissions())) {
Navigator.pushReplacementNamed(
while (!(await GlobalValuesManager.hasGrantedPermissions())) {
await Navigator.pushNamed(
context,
GrantPermissionScreen.ID,
);
}
await GlobalValuesManager.watchForInitialization();
await GlobalValuesManager.waitForInitialization();
final memories = context.read<Memories>();
final session = Supabase.instance.client.auth.session();
if (session == null && widget.nextScreen == LoginScreen.ID) {
Navigator.pushReplacementNamed(
context,
LoginScreen.ID,
);
return;
}
if (session == null) {
Navigator.pushReplacementNamed(
context,
WelcomeScreen.ID,
);
return;
} else {
if (!memories.isInitialized) {
await memories.initialize();
@ -67,17 +77,20 @@ class _ServerLoadingScreenState extends State<ServerLoadingScreen> {
context,
MainScreen.ID,
);
return;
} else {
if (memories.memories.isEmpty) {
Navigator.pushReplacementNamed(
context,
EmptyScreen.ID,
);
return;
} else {
Navigator.pushReplacementNamed(
context,
widget.nextScreen!,
);
return;
}
}
}

View File

@ -1,130 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/constants/values.dart';
import 'package:quid_faciam_hodie/foreign_types/memory_location.dart';
import 'package:quid_faciam_hodie/screens/memory_map_screen.dart';
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
class MemoryLocationView extends StatefulWidget {
final MemoryLocation location;
const MemoryLocationView({
Key? key,
required this.location,
}) : super(key: key);
@override
State<MemoryLocationView> createState() => _MemoryLocationViewState();
}
class _MemoryLocationViewState extends State<MemoryLocationView> {
late final MapController controller;
@override
void initState() {
super.initState();
controller = MapController(
initPosition: GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
void drawCircle() => controller.drawCircle(
CircleOSM(
key: 'accuracy',
color: Colors.blue,
centerPoint: GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
),
radius: widget.location.accuracy,
strokeWidth: 4,
),
);
List<StaticPositionGeoPoint> get staticPoints {
if (widget.location.accuracy <= ACCURACY_IN_METERS_FOR_PINPOINT) {
return [
StaticPositionGeoPoint(
'position',
const MarkerIcon(
icon: Icon(Icons.location_on, size: 150, color: Colors.blue),
),
[
GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
)
],
)
];
} else {
return [];
}
}
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
return Column(
children: <Widget>[
SizedBox(
width: double.infinity,
height: 400,
child: GestureDetector(
// Avoid panning, map is view-only
onDoubleTap: () {},
child: OSMFlutter(
controller: controller,
initZoom: 14,
minZoomLevel: 14,
maxZoomLevel: 14,
staticPoints: staticPoints,
onMapIsReady: (_) {
drawCircle();
},
),
),
),
const SizedBox(height: MEDIUM_SPACE),
PlatformTextButton(
child: IconButtonChild(
icon: Icon(context.platformIcons.fullscreen),
label: Text(localizations.memorySheetViewMoreDetails),
),
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (_) => MemoryMapScreen(
location: widget.location,
),
),
);
if (!mounted) {
return;
}
Navigator.pop(context);
},
),
const SizedBox(height: MEDIUM_SPACE),
],
);
}
}

View File

@ -10,12 +10,15 @@ import 'package:quid_faciam_hodie/enums.dart';
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
import 'package:quid_faciam_hodie/foreign_types/memory.dart';
import 'package:quid_faciam_hodie/managers/file_manager.dart';
import 'package:quid_faciam_hodie/screens/memory_map_screen.dart';
import 'package:quid_faciam_hodie/utils/loadable.dart';
import 'package:quid_faciam_hodie/utils/theme.dart';
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
import 'package:quid_faciam_hodie/widgets/platform_widgets/memory_cupertino_maps.dart';
import 'package:quid_faciam_hodie/widgets/sheet_indicator.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'memory_location_view.dart';
import '../../widgets/platform_widgets/memory_material_maps.dart';
class MemorySheet extends StatefulWidget {
final Memory memory;
@ -250,8 +253,51 @@ class _MemorySheetState extends State<MemorySheet> with Loadable {
: Container(
width: double.infinity,
color: backgroundColor,
child: MemoryLocationView(
location: widget.memory.location!,
child: Column(
children: <Widget>[
SizedBox(
width: double.infinity,
height: 400,
child: GestureDetector(
// Avoid panning, map is view-only
onDoubleTap: () {},
child: PlatformWidget(
material: (_, __) => MemoryMaterialMaps(
location: widget.memory.location!,
initialZoom: 14,
),
cupertino: (_, __) => MemoryCupertinoMaps(
location: widget.memory.location!,
initialZoom: 14,
),
),
),
),
const SizedBox(height: MEDIUM_SPACE),
PlatformTextButton(
child: IconButtonChild(
icon: Icon(context.platformIcons.fullscreen),
label: Text(localizations.memorySheetViewMoreDetails),
),
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (_) => MemoryMapScreen(
location: widget.memory.location!,
),
),
);
if (!mounted) {
return;
}
Navigator.pop(context);
},
),
const SizedBox(height: MEDIUM_SPACE),
],
),
),
);

View File

@ -2,7 +2,8 @@ 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/screens/grant_permission_screen.dart';
import 'package:quid_faciam_hodie/screens/login_screen.dart';
import 'package:quid_faciam_hodie/screens/server_loading_screen.dart';
import 'package:quid_faciam_hodie/screens/welcome_screen/crabs/logo.dart';
import 'package:quid_faciam_hodie/utils/theme.dart';
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
@ -38,9 +39,13 @@ class GetStartedPage extends StatelessWidget {
label: Text(localizations.welcomeScreenStartButtonTitle),
),
onPressed: () {
Navigator.pushNamed(
Navigator.push(
context,
GrantPermissionScreen.ID,
MaterialPageRoute(
builder: (_) => const ServerLoadingScreen(
nextScreen: LoginScreen.ID,
),
),
);
},
),

View File

@ -1,6 +1,7 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/constants/values.dart';
import 'package:quid_faciam_hodie/managers/photo_manager.dart';
@ -15,7 +16,7 @@ class PhotoSwitching extends StatefulWidget {
}
class _PhotoSwitchingState extends State<PhotoSwitching> with Loadable {
late String photoURL;
String photoURL = '';
@override
void initState() {
@ -41,7 +42,9 @@ class _PhotoSwitchingState extends State<PhotoSwitching> with Loadable {
@override
Widget build(BuildContext context) {
if (isLoading) {
return const Center(child: CircularProgressIndicator());
return Center(
child: PlatformCircularProgressIndicator(),
);
}
return ClipRRect(

View File

@ -0,0 +1,62 @@
import 'package:apple_maps_flutter/apple_maps_flutter.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:quid_faciam_hodie/foreign_types/memory_location.dart';
class MemoryCupertinoMaps extends StatefulWidget {
final MemoryLocation location;
final bool lockZoom;
final double initialZoom;
const MemoryCupertinoMaps({
Key? key,
required this.location,
required this.initialZoom,
this.lockZoom = false,
}) : super(key: key);
@override
State<MemoryCupertinoMaps> createState() => _MemoryCupertinoMapsState();
}
class _MemoryCupertinoMapsState extends State<MemoryCupertinoMaps> {
@override
Widget build(BuildContext context) {
return AppleMap(
minMaxZoomPreference: MinMaxZoomPreference(
widget.lockZoom ? widget.initialZoom : 1,
widget.lockZoom ? widget.initialZoom : 20,
),
circles: {
Circle(
circleId: CircleId('accuracy'),
center: LatLng(
widget.location.latitude,
widget.location.longitude,
),
radius: widget.location.accuracy,
strokeWidth: 1,
fillColor: Colors.blue.withOpacity(.2),
strokeColor: Colors.blue,
),
},
annotations: {
Annotation(
annotationId: AnnotationId('position'),
position: LatLng(
widget.location.latitude,
widget.location.longitude,
),
icon: BitmapDescriptor.defaultAnnotation,
)
},
initialCameraPosition: CameraPosition(
target: LatLng(
widget.location.latitude,
widget.location.longitude,
),
zoom: 14,
),
);
}
}

View File

@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
import 'package:quid_faciam_hodie/foreign_types/memory_location.dart';
class MemoryMaterialMaps extends StatefulWidget {
final MemoryLocation location;
final bool lockZoom;
final double initialZoom;
const MemoryMaterialMaps({
Key? key,
required this.location,
required this.initialZoom,
this.lockZoom = false,
}) : super(key: key);
@override
State<MemoryMaterialMaps> createState() => _MemoryMaterialMapsState();
}
class _MemoryMaterialMapsState extends State<MemoryMaterialMaps> {
late final MapController controller;
@override
void initState() {
super.initState();
controller = MapController(
initPosition: GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
void drawCircle() => controller.drawCircle(
CircleOSM(
key: 'accuracy',
color: Colors.blue,
centerPoint: GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
),
radius: widget.location.accuracy,
strokeWidth: 4,
),
);
List<StaticPositionGeoPoint> get staticPoints => [
StaticPositionGeoPoint(
'position',
const MarkerIcon(
icon: Icon(Icons.location_on, size: 150, color: Colors.blue),
),
[
GeoPoint(
latitude: widget.location.latitude,
longitude: widget.location.longitude,
)
],
)
];
@override
Widget build(BuildContext context) {
return OSMFlutter(
controller: controller,
initZoom: widget.initialZoom,
maxZoomLevel: widget.lockZoom ? widget.initialZoom : 19,
minZoomLevel: widget.lockZoom ? widget.initialZoom : 2,
staticPoints: staticPoints,
onMapIsReady: (_) {
drawCircle();
},
);
}
}

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:quid_faciam_hodie/utils/theme.dart';
class SheetIndicator extends StatelessWidget {
const SheetIndicator({Key? key}) : super(key: key);
@ -9,7 +10,7 @@ class SheetIndicator extends StatelessWidget {
width: 100,
height: 5,
decoration: BoxDecoration(
color: Colors.white24,
color: getBodyTextColor(context).withOpacity(.2),
borderRadius: BorderRadius.circular(10),
),
);

View File

@ -1,6 +1,13 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
apple_maps_flutter:
dependency: "direct main"
description:
name: apple_maps_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
archive:
dependency: transitive
description:

View File

@ -62,6 +62,7 @@ dependencies:
flutter_exif_plugin: ^1.1.0
flutter_osm_plugin: ^0.39.0
url_launcher: ^6.1.5
apple_maps_flutter: ^1.2.0
dev_dependencies:
flutter_test: