Skip to content

Commit

Permalink
Merge pull request #106 from p2panda/delete-sighting
Browse files Browse the repository at this point in the history
Delete sighting
  • Loading branch information
sandreae authored May 31, 2024
2 parents 8f40ae1 + 05d47a4 commit 65b0ceb
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 56 deletions.
15 changes: 10 additions & 5 deletions packages/app/lib/locales/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"createSightingError": "Something went wrong: {error}",
"createSightingScreenTitle": "Add Sighting",
"createSightingSuccess": "Yay, you've successfully added a new sighting to the database",
"deleteSighting": "Delete Sighting",
"editCardCancelButton": "Cancel",
"editCardSaveButton": "Save",
"editSpeciesErrorCantRemove": "Species needs to be defined",
Expand All @@ -27,9 +28,9 @@
"imageDeleteConfirmation": "Image deleted.",
"imageLoadingError": "Could not load image",
"imageMissingError": "No image given",
"localNameCardSaveAction": "Save",
"localNameCardTitle": "Local Name",
"localNamesCardTitle": "Local Names",
"localNameCardSaveAction": "Save",
"locationAdd": "Do you want to add a GPS location?",
"locationAddAction": "Add location to image",
"locationErrorPermissionDenied": "Location permission was denied",
Expand Down Expand Up @@ -57,11 +58,13 @@
"settingsSystemInfoError": "Could not retrieve system informations",
"settingsSystemInfoSDK": "Android SDK Version",
"settingsSystemInformation": "System Information",
"sightingDeleteAlertBody": "Are you sure you want to delete this sighting?",
"sightingDeleteAlertCancel": "Cancel",
"sightingDeleteAlertConfirm": "Delete",
"sightingDeleteAlertTitle": "Delete Sighting",
"sightingDeleteConfirmation": "Sighting deleted.",
"sightingScreenTitle": "Sighting",
"sightingUnspecified": "Unknown species",
"speciesScreenTitle": "Species",
"usedForCardTitle": "Used For",
"usedForTextSave": "Save",
"speciesCardTitle": "Species",
"speciesDescription": "Description",
"speciesScreenTitle": "Species",
Expand All @@ -73,5 +76,7 @@
"taxonomyPhylum": "Phylum",
"taxonomySpecies": "Species",
"taxonomySubfamily": "Subfamily",
"taxonomyTribe": "Tribe"
"taxonomyTribe": "Tribe",
"usedForCardTitle": "Used For",
"usedForTextSave": "Save"
}
67 changes: 38 additions & 29 deletions packages/app/lib/ui/screens/sighting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'package:app/ui/widgets/local_name_field.dart';
import 'package:app/ui/widgets/note_field.dart';
import 'package:app/ui/widgets/refresh_provider.dart';
import 'package:app/ui/widgets/scaffold.dart';
import 'package:app/ui/widgets/sighting_popup_menu.dart';
import 'package:app/ui/widgets/species_field.dart';
import 'package:app/ui/widgets/used_for_field.dart';

Expand All @@ -33,35 +34,43 @@ class SightingScreen extends StatefulWidget {
class _SightingScreenState extends State<SightingScreen> {
@override
Widget build(BuildContext context) {
return MeliScaffold(
title: AppLocalizations.of(context)!.sightingScreenTitle,
backgroundColor: MeliColors.electric,
appBarColor: MeliColors.electric,
body: SingleChildScrollView(
child: Query(
options:
QueryOptions(document: gql(sightingQuery(widget.documentId))),
builder: (result, {VoidCallback? refetch, FetchMore? fetchMore}) {
if (result.hasException) {
return ErrorCard(message: result.exception.toString());
}

if (result.isLoading) {
return const Center(
child: SizedBox(
width: 50,
height: 50,
child:
CircularProgressIndicator(color: MeliColors.black)),
);
}

final sighting = Sighting.fromJson(
result.data?['sighting'] as Map<String, dynamic>);

return SightingProfile(sighting);
}),
));
return Query(
options: QueryOptions(document: gql(sightingQuery(widget.documentId))),
builder: (result, {VoidCallback? refetch, FetchMore? fetchMore}) {
Sighting? sighting;

if (!result.hasException && !result.isLoading) {
sighting = Sighting.fromJson(
result.data?['sighting'] as Map<String, dynamic>);
}

return MeliScaffold(
title: AppLocalizations.of(context)!.sightingScreenTitle,
backgroundColor: MeliColors.electric,
appBarColor: MeliColors.electric,
actionRight: sighting != null
? SightingPopupMenu(viewId: sighting.viewId)
: null,
body: SingleChildScrollView(
child: Builder(builder: (BuildContext context) {
if (result.hasException) {
return ErrorCard(message: result.exception.toString());
}

if (result.isLoading) {
return const Center(
child: SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(
color: MeliColors.black)),
);
}

return SightingProfile(sighting!);
}),
));
});
}
}

Expand Down
10 changes: 6 additions & 4 deletions packages/app/lib/ui/screens/species.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,13 @@ class _SpeciesProfileState extends State<SpeciesProfile> {
onTap: (DocumentId sightingId) {
router.pushNamed(RoutePaths.sighting.name,
pathParameters: {'documentId': sightingId}).then((value) {
final refreshProvider = RefreshProvider.of(context);
// Force loading the species again after we've returned from
// an updated sighting, to make sure that aggregated data over
// all sightings is up-to-date
if (RefreshProvider.of(context)
.isDirty(RefreshKeys.UpdatedSighting) &&
// an updated or deleted sighting, to make sure that
// aggregated data over all sightings is up-to-date
if ((refreshProvider.isDirty(RefreshKeys.UpdatedSighting) ||
refreshProvider
.isDirty(RefreshKeys.DeletedSighting)) &&
widget.refetch != null) {
widget.refetch!();
}
Expand Down
7 changes: 2 additions & 5 deletions packages/app/lib/ui/widgets/refresh_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@

import 'package:flutter/widgets.dart';

/// Actions which might affect other views.
enum RefreshKeys {
/// New sighting got created which might affect other views.
CreatedSighting,

/// Sighting got updated with data which might affect other views.
UpdatedSighting,

/// Species got updated with data which might affect other views.
DeletedSighting,
UpdatedSpecies,
}

Expand Down
30 changes: 20 additions & 10 deletions packages/app/lib/ui/widgets/scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:app/ui/colors.dart';
class MeliScaffold extends StatefulWidget {
final String? title;
final Widget? body;
final Widget? actionRight;
final Color backgroundColor;
final Color appBarColor;
final List<Widget> floatingActionButtons;
Expand All @@ -16,6 +17,7 @@ class MeliScaffold extends StatefulWidget {
{super.key,
this.body,
this.title,
this.actionRight,
this.floatingActionButtons = const [],
this.fabAlignment = MainAxisAlignment.spaceBetween,
this.appBarColor = MeliColors.flurry,
Expand All @@ -35,16 +37,24 @@ class _MeliScaffoldState extends State<MeliScaffold> {
shadowColor: Colors.black54,
forceMaterialTransparency: false,
backgroundColor: widget.appBarColor,
title: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
IconButton(
icon: const Icon(Icons.arrow_back_rounded),
onPressed: () {
Navigator.of(context).pop();
}),
const SizedBox(width: 7.0),
Text(widget.title!),
const SizedBox(width: 35.0),
]),
title: Stack(
children: [
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
IconButton(
icon: const Icon(Icons.arrow_back_rounded),
onPressed: () {
Navigator.of(context).pop();
}),
const SizedBox(width: 7.0),
Text(widget.title!),
const SizedBox(width: 35.0),
]),
if (widget.actionRight != null)
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [widget.actionRight!]),
],
),
);
}

Expand Down
61 changes: 61 additions & 0 deletions packages/app/lib/ui/widgets/sighting_popup_menu.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import 'package:app/io/p2panda/publish.dart';
import 'package:app/models/sightings.dart';
import 'package:app/router.dart';
import 'package:app/ui/widgets/confirm_dialog.dart';
import 'package:app/ui/widgets/refresh_provider.dart';

class SightingPopupMenu extends StatelessWidget {
final DocumentViewId viewId;

const SightingPopupMenu({super.key, required this.viewId});

void _onDelete(BuildContext context) {
final messenger = ScaffoldMessenger.of(context);
final t = AppLocalizations.of(context)!;
final refreshProvider = RefreshProvider.of(context);

showDialog<String>(
context: context,
builder: (BuildContext context) => ConfirmDialog(
title: t.sightingDeleteAlertTitle,
message: t.sightingDeleteAlertBody,
labelAbort: t.sightingDeleteAlertCancel,
labelConfirm: t.sightingDeleteAlertConfirm,
onConfirm: () async {
// @TODO: also delete all uses documents and hive location documents.
await deleteSighting(viewId);

// Set flag for other widgets to tell them that they might need to
// re-render their data. This will make sure that our updates are
// reflected in the UI
refreshProvider.setDirty(RefreshKeys.DeletedSighting);

// First pop closes this dialog, second goes back to the view we came
// from
router.pop();
router.pop();

messenger.showSnackBar(
SnackBar(content: Text(t.sightingDeleteConfirmation)));
},
),
);
}

@override
Widget build(BuildContext context) {
return PopupMenuButton(
itemBuilder: (BuildContext context) => [
PopupMenuItem<void>(
child: Text(AppLocalizations.of(context)!.deleteSighting),
onTap: () {
_onDelete(context);
}),
]);
}
}
8 changes: 5 additions & 3 deletions packages/app/lib/ui/widgets/sightings_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ class _SightingsListState extends State<SightingsList> {
return SightingCard(
onTap: () => router.pushNamed(RoutePaths.sighting.name,
pathParameters: {'documentId': sighting.id}).then((value) {
// Refresh list when we've returned from updating a sighting
if (RefreshProvider.of(context)
.isDirty(RefreshKeys.UpdatedSighting) &&
final refreshProvider = RefreshProvider.of(context);
// Refresh list when we've returned from updating or deleting a
// sighting
if ((refreshProvider.isDirty(RefreshKeys.UpdatedSighting) ||
refreshProvider.isDirty(RefreshKeys.DeletedSighting)) &&
widget.paginator.refresh != null) {
widget.paginator.refresh!();
}
Expand Down

0 comments on commit 65b0ceb

Please sign in to comment.