Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UsedForField widget on sighting #48

Merged
merged 63 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
438ab97
Add UsedFor model with queries
sandreae Oct 17, 2023
6b5ff61
Basic flow for creating UsedFor
sandreae Oct 17, 2023
0fb93aa
Paginated UsedFor list with onsubmit refresh
sandreae Oct 17, 2023
b2c7f81
Add delete button, don't autofocus
sandreae Oct 17, 2023
9b7f641
Implement deletion for UsedFor items
sandreae Oct 17, 2023
e6be447
Make PaginationList a bit more customizable
sandreae Oct 18, 2023
3870707
Fetch next page of UsedFor on scroll end
sandreae Oct 18, 2023
997ee1c
Set DEFAULT_PAGE_SIZE back to 10
sandreae Oct 18, 2023
2062221
Move list UsedFor list building to own method
sandreae Oct 18, 2023
537be74
Split UsedForField into multiple widgets
sandreae Oct 18, 2023
e909d88
Style used for tags
sandreae Oct 18, 2023
8ebd9d5
Make DocumentId optional in UsedForPaginator
sandreae Oct 18, 2023
0a8d21f
Pass loadMore button into listBuilder
sandreae Oct 18, 2023
e0c8e26
Create separate widgets for each paginated list case
sandreae Oct 18, 2023
8b92be1
Basic layout of sub-widgets
sandreae Oct 18, 2023
520a356
Don't check for duplicate uses
sandreae Oct 18, 2023
aa9c879
Make the layout somehow work
sandreae Oct 18, 2023
21382b2
Create UsedFor when clicking on UsedFor tag
sandreae Oct 18, 2023
8cf755d
Deduplicate UsedFor with same value for tags
sandreae Oct 18, 2023
608ef67
Give paginators distinct names
sandreae Oct 19, 2023
2417408
Refactor used for field build method
sandreae Oct 19, 2023
2cd9ddd
Style changes for uses tag and current lists
sandreae Oct 19, 2023
cc93fd8
Refactor layouts of paginated use lists
sandreae Oct 19, 2023
27f9ec2
Make more button grey
sandreae Oct 19, 2023
d90995d
Improvements to UsedForField layout
sandreae Oct 19, 2023
9ae27c1
Keep fetching UsedFor tags until we have minimum 20
sandreae Oct 19, 2023
d9f9fc0
Remove "more" tag button
sandreae Oct 19, 2023
44a7ef1
Styling of current uses list
sandreae Oct 19, 2023
6f0e45d
Don't refresh tags paginator
sandreae Oct 19, 2023
5c0759a
Refactor and center list items
sandreae Oct 19, 2023
f045f04
Fixes after rebase
sandreae Oct 19, 2023
6919e98
Translations
sandreae Oct 19, 2023
a439e4c
Fix after rebase
sandreae May 6, 2024
9cb1ecd
Method for updating UsedFor documents not required
sandreae May 6, 2024
87bc812
Update updateUsedFor method on sighting screen
sandreae May 6, 2024
87af257
Refactor methods for creating UsedFor documents on UsedForField
sandreae May 6, 2024
5fc0861
Don't use autocomplete widget for new tag text field
sandreae May 6, 2024
fe01ce2
Remove unused parameter
sandreae May 6, 2024
c4a7eee
Formatting and linting
sandreae May 6, 2024
490d57b
Rename and refactor some methods
sandreae May 7, 2024
17b8ceb
Remove unused query
sandreae May 7, 2024
5c41ca0
Move create use logic into UsedForField
sandreae May 7, 2024
bd752d7
Roll-back changes in Autocomplete widget
sandreae May 7, 2024
33643d6
Roll-back changes in Autocomplete widget
sandreae May 7, 2024
42a549e
Revert name changes
sandreae May 7, 2024
8946fff
Rename infinite scroll widgets
sandreae May 7, 2024
9b3f555
Small refactor and better comments in UsedForField
sandreae May 7, 2024
28aa960
Remove unused methods in infinite scroll lists
sandreae May 7, 2024
43702f0
Format and lint
sandreae May 7, 2024
ad8262b
Introduce UsedForTextField and add Create Tag button
sandreae May 8, 2024
5ce4b45
Refactor: new widget UsedForTagSelector
sandreae May 8, 2024
e4e5d6d
Refactor: new widget UsedForList
sandreae May 8, 2024
b5db4c8
Add headings to fields in used for edit view
sandreae May 8, 2024
440b8d5
Make tag selector items larger
sandreae May 8, 2024
06d5378
Change used for save text
sandreae May 8, 2024
a5fcb30
Better messages when uses lists are empty
sandreae May 8, 2024
79715f9
Add scrollbar to uses list and tag selector
sandreae May 8, 2024
9726e0f
Style of uses list items
sandreae May 8, 2024
e6e9d65
Pass ScrollController into RawScrollbar
sandreae May 8, 2024
ad53437
Pass ScrollController into RawScrollbar in all widgets
sandreae May 8, 2024
cb05af4
Format and linting
sandreae May 8, 2024
a043888
Fix analysis error
sandreae May 8, 2024
74a1fa0
Add missing license headers, minor import order clean up
adzialocha May 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/app/lib/locales/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
"settingsSystemInformation": "System Information",
"sightingScreenTitle": "Sighting",
"sightingUnspecified": "Unknown species",
"speciesScreenTitle": "Species",
"usedForCardTitle": "Used For",
"usedForTextSave": "Save",
"speciesCardTitle": "Species",
"speciesDescription": "Description",
"speciesScreenTitle": "Species",
Expand Down
40 changes: 32 additions & 8 deletions packages/app/lib/locales/app_pt.arb
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"allSpeciesScreenTitle": "Todas as Espécies",
"createSightingError": "Algo deu errado: {error}",
"createSightingScreenTitle": "Adicionar Avistamento",
"createSightingSuccess": "Eba, você adicionou com sucesso um novo avistamento ao banco de dados",
"createSightingSuccess": "Uau, você adicionou com sucesso um novo avistamento ao banco de dados",
"editSpeciesErrorCantRemove": "A espécie precisa ser definida",
"editSpeciesErrorConfirm": "Ok",
"editSpeciesErrorInvalidRankCase": "O rank \"{rank}\" não pode ser alterado!",
"editSpeciesErrorMessage": "{error}",
"editSpeciesErrorNullCase": "O rank \"{rank}\" precisa ser especificado!",
"editSpeciesErrorTitle": "Não foi possível salvar a espécie",
"imageDeleteAlertBody": "Tem certeza de que deseja excluir esta imagem?",
"imageDeleteAlertCancel": "Não",
"imageDeleteAlertConfirm": "Sim",
Expand All @@ -14,7 +21,7 @@
"locationAddAction": "Adicionar localização à imagem",
"locationErrorPermissionDenied": "Permissão de localização negada",
"locationErrorServiceDisabled": "O serviço de localização está desativado",
"locationErrorTimeout": "Não foi possível recuperar a localização",
"locationErrorTimeout": "Localização não pôde ser recuperada",
"locationErrorUnknown": "Ocorreu um erro desconhecido",
"locationHeader": "Localização",
"locationLoading": "Recuperando localização...",
Expand All @@ -25,13 +32,30 @@
"paginationListError": "Ocorreu um erro ao solicitar os dados: {errorMessage}",
"paginationListLoadMore": "Carregar Mais",
"paginationListNoResults": "Nenhuma entrada fornecida ainda",
"sightingUnspecified": "Espécie desconhecida",
"settings": "Configurações",
"settingsLanguages": "Idiomas",
"settingsLanguageChangeSuccess": "Idioma alterado para \"{language}\"",
"settingsLanguageChangeError": "Erro: não foi possível alterar o idioma",
"settingsSystemInformation": "Informações do Sistema",
"settingsEnglish": "Inglês",
"settingsLanguageChangeError": "Erro: não foi possível alterar o idioma",
"settingsLanguageChangeSuccess": "Idioma alterado para \"{language}\"",
"settingsLanguages": "Idiomas",
"settingsPortuguese": "Português",
"speciesScreenTitle": "Espécies"
"settingsSystemInfoAndroid": "Versão do Android",
"settingsSystemInfoDevice": "Dispositivo",
"settingsSystemInfoError": "Não foi possível recuperar informações do sistema",
"settingsSystemInfoSDK": "Versão do Android SDK",
"settingsSystemInformation": "Informações do Sistema",
"sightingScreenTitle": "Avistamento",
"sightingUnspecified": "Espécie desconhecida",
"speciesScreenTitle": "Espécies",
"usedForCardTitle": "Usado Para",
"speciesCardTitle": "Espécie",
"speciesDescription": "Descrição",
"taxonomyClass": "Classe",
"taxonomyFamily": "Família",
"taxonomyGenus": "Gênero",
"taxonomyKingdom": "Reino",
"taxonomyOrder": "Ordem",
"taxonomyPhylum": "Filo",
"taxonomySpecies": "Espécie",
"taxonomySubfamily": "Subfamília",
"taxonomyTribe": "Tribo"
}
2 changes: 2 additions & 0 deletions packages/app/lib/models/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ abstract class Paginator<T> {
/// Paginator instance.
VoidCallback? refresh;

VoidCallback? fetchMore;

/// Should return GraphQL query for the next page.
DocumentNode nextPageQuery(String? cursor);

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

import 'package:gql/src/ast/ast.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:p2panda/p2panda.dart';

import 'package:app/io/p2panda/publish.dart';
import 'package:app/models/base.dart';
import 'package:app/models/schema_ids.dart';

class UsedFor {
final DocumentId id;
DocumentViewId viewId;
DocumentId sighting;
String usedFor;

UsedFor(
{required this.id,
required this.viewId,
required this.sighting,
required this.usedFor});

factory UsedFor.fromJson(Map<String, dynamic> result) {
return UsedFor(
id: result['meta']['documentId'] as DocumentId,
viewId: result['meta']['viewId'] as DocumentViewId,
sighting:
result['fields']['sighting']['meta']['documentId'] as DocumentId,
usedFor: result['fields']['used_for'] as String);
}

static Future<UsedFor> create(
{required DocumentId sighting, required String usedFor}) async {
DocumentViewId viewId =
await createUsedFor(sighting: sighting, usedFor: usedFor);
return UsedFor(
id: viewId,
viewId: viewId,
sighting: sighting,
usedFor: usedFor,
);
}

Future<DocumentViewId> delete() async {
viewId = await deleteUsedFor(viewId);
return viewId;
}
}

String get usedForFields {
return '''
$metaFields
fields {
used_for
sighting {
meta {
documentId
}
}
}
''';
}

String usedForQuery(DocumentId id) {
const schemaId = SchemaIds.bee_attributes_used_for;

return '''
query usedForQuery {
document: $schemaId(id: "$id") {
$usedForFields
}
}
''';
}

class UsedForPaginator extends Paginator<UsedFor> {
final DocumentId? sighting;

UsedForPaginator({this.sighting});

@override
DocumentNode nextPageQuery(String? cursor) {
return gql(allUsesQuery(sighting, cursor));
}

@override
PaginatedCollection<UsedFor> parseJSON(Map<String, dynamic> json) {
final list = json[DEFAULT_RESULTS_KEY]['documents'] as List;
final documents = list
.map((sighting) => UsedFor.fromJson(sighting as Map<String, dynamic>))
.toList();

final endCursor = json[DEFAULT_RESULTS_KEY]['endCursor'] as String?;
final hasNextPage = json[DEFAULT_RESULTS_KEY]['hasNextPage'] as bool;

return PaginatedCollection(
documents: documents, hasNextPage: hasNextPage, endCursor: endCursor);
}
}

String allUsesQuery(DocumentId? sighting, String? cursor) {
final after = (cursor != null) ? '''after: "$cursor",''' : '';
final filter = (sighting != null)
? '''filter: { sighting: { eq: "$sighting" } },'''
: '';
const schemaId = SchemaIds.bee_attributes_used_for;

return '''
query AllUses {
$DEFAULT_RESULTS_KEY: all_$schemaId(
$filter
first: $DEFAULT_PAGE_SIZE,
$after
orderBy: "used_for",
orderDirection: ASC
) {
$paginationFields
documents {
$usedForFields
}
}
}
''';
}

Future<DocumentViewId> createUsedFor(
{required DocumentId sighting, required String usedFor}) async {
List<(String, OperationValue)> fields = [
("sighting", OperationValue.relation(sighting)),
("used_for", OperationValue.string(usedFor)),
];
return await create(SchemaIds.bee_attributes_used_for, fields);
}

Future<DocumentViewId> deleteUsedFor(DocumentViewId viewId) async {
return await delete(SchemaIds.bee_attributes_used_for, viewId);
}
11 changes: 6 additions & 5 deletions packages/app/lib/ui/screens/all_sightings.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

import 'package:app/ui/widgets/pagination_cards_list.dart';
import 'package:flutter/material.dart';

import 'package:app/models/base.dart';
import 'package:app/models/sightings.dart';
import 'package:app/router.dart';
import 'package:app/ui/colors.dart';
import 'package:app/ui/widgets/fab.dart';
import 'package:app/ui/widgets/pagination_list.dart';
import 'package:app/ui/widgets/scaffold.dart';
import 'package:app/ui/widgets/sighting_card.dart';

Expand Down Expand Up @@ -98,12 +98,12 @@ class _SightingsListState extends State<SightingsList> {
decoration: const MagnoliaWavesBackground(),
child: Container(
width: double.infinity,
padding: const EdgeInsets.only(top: 30.0, bottom: 20.0),
padding: EdgeInsets.only(top: 30.0, bottom: 20.0),
child: PaginationList<Sighting>(
builder: (Sighting sighting) {
return Container(
padding: const EdgeInsets.only(bottom: 20.0),
child: _item(sighting));
padding: EdgeInsets.only(bottom: 20.0),
child: this._item(sighting));
},
paginator: widget.paginator)),
);
Expand Down Expand Up @@ -163,7 +163,8 @@ class _BouncyBeeState extends State<BouncyBee>
},
child: SlideTransition(
position: _flyingBeeAnimation,
child: const Center(child: Text("🐝", style: TextStyle(fontSize: 50.0))),
child:
const Center(child: Text("🐝", style: TextStyle(fontSize: 50.0))),
),
);
}
Expand Down
11 changes: 6 additions & 5 deletions packages/app/lib/ui/screens/all_species.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

import 'package:app/ui/widgets/pagination_cards_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import 'package:app/models/base.dart';
import 'package:app/models/species.dart';
import 'package:app/router.dart';
import 'package:app/ui/colors.dart';
import 'package:app/ui/widgets/pagination_list.dart';
import 'package:app/ui/widgets/scaffold.dart';
import 'package:app/ui/widgets/species_card.dart';

Expand All @@ -31,7 +31,8 @@ class AllSpeciesScreen extends StatelessWidget {
},
child: LayoutBuilder(builder: (context, constraints) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 0.0),
padding:
const EdgeInsets.symmetric(horizontal: 20.0, vertical: 0.0),
constraints: BoxConstraints(minHeight: constraints.maxHeight),
decoration: const PeachWavesBackground(),
child: SingleChildScrollView(
Expand Down Expand Up @@ -68,12 +69,12 @@ class _SpeciesListState extends State<SpeciesList> {
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.only(top: 30.0, bottom: 20.0),
padding: EdgeInsets.only(top: 30.0, bottom: 20.0),
child: PaginationList<Species>(
builder: (Species species) {
return Container(
padding: const EdgeInsets.only(bottom: 20.0),
child: _item(species));
padding: EdgeInsets.only(bottom: 20.0),
child: this._item(species));
},
paginator: widget.paginator));
}
Expand Down
9 changes: 6 additions & 3 deletions packages/app/lib/ui/screens/sighting.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

import 'package:app/ui/widgets/used_for_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
Expand Down Expand Up @@ -130,9 +131,8 @@ class _SightingProfileState extends State<SightingProfile> {

@override
Widget build(BuildContext context) {
final imagePaths = sighting.images
.map((image) => '$BLOBS_BASE_PATH/${image.id}')
.toList();
final imagePaths =
sighting.images.map((image) => '$BLOBS_BASE_PATH/${image.id}').toList();

return Container(
padding: const EdgeInsets.only(
Expand All @@ -150,6 +150,9 @@ class _SightingProfileState extends State<SightingProfile> {
onUpdate: _updateSpecies,
),
NoteField(sighting.comment, onUpdate: _updateComment),
UsedForField(
sighting: sighting.id,
),
// @TODO: Remove this as soon as there are more elements
const SizedBox(height: 550.0),
]),
Expand Down
Loading