info: navigate by country

This commit is contained in:
Thibault Deckers 2020-03-24 15:25:45 +09:00
parent 2e5a2e7c91
commit 77c9d86ea3
5 changed files with 99 additions and 57 deletions

View file

@ -138,9 +138,9 @@ class _AllCollectionDrawerState extends State<AllCollectionDrawer> {
break; break;
} }
} }
final tags = source.sortedTags;
final countries = source.sortedCountries; final countries = source.sortedCountries;
final tags = source.sortedTags;
final drawerItems = [ final drawerItems = [
header, header,
gifEntry, gifEntry,
@ -175,28 +175,6 @@ class _AllCollectionDrawerState extends State<AllCollectionDrawer> {
], ],
), ),
), ),
if (tags.isNotEmpty)
SafeArea(
top: false,
bottom: false,
child: ExpansionTile(
leading: const Icon(OMIcons.label),
title: Row(
children: [
const Text('Tags'),
const Spacer(),
Text(
'${tags.length}',
style: TextStyle(
color: (_tagsExpanded ? Theme.of(context).accentColor : Colors.white).withOpacity(.6),
),
),
],
),
onExpansionChanged: (expanded) => setState(() => _tagsExpanded = expanded),
children: tags.map(buildTagEntry).toList(),
),
),
if (countries.isNotEmpty) if (countries.isNotEmpty)
SafeArea( SafeArea(
top: false, top: false,
@ -219,6 +197,28 @@ class _AllCollectionDrawerState extends State<AllCollectionDrawer> {
children: countries.map(buildCountryEntry).toList(), children: countries.map(buildCountryEntry).toList(),
), ),
), ),
if (tags.isNotEmpty)
SafeArea(
top: false,
bottom: false,
child: ExpansionTile(
leading: const Icon(OMIcons.label),
title: Row(
children: [
const Text('Tags'),
const Spacer(),
Text(
'${tags.length}',
style: TextStyle(
color: (_tagsExpanded ? Theme.of(context).accentColor : Colors.white).withOpacity(.6),
),
),
],
),
onExpansionChanged: (expanded) => setState(() => _tagsExpanded = expanded),
children: tags.map(buildTagEntry).toList(),
),
),
]; ];
return Drawer( return Drawer(

View file

@ -32,6 +32,8 @@ class InfoPageState extends State<InfoPage> {
ScrollController _scrollController = ScrollController(); ScrollController _scrollController = ScrollController();
bool _scrollStartFromTop = false; bool _scrollStartFromTop = false;
CollectionLens get collection => widget.collection;
ImageEntry get entry => widget.entry; ImageEntry get entry => widget.entry;
@override @override
@ -68,6 +70,7 @@ class InfoPageState extends State<InfoPage> {
final locationAtTop = split && entry.hasGps; final locationAtTop = split && entry.hasGps;
final locationSection = LocationSection( final locationSection = LocationSection(
collection: collection,
entry: entry, entry: entry,
showTitle: !locationAtTop, showTitle: !locationAtTop,
visibleNotifier: widget.visibleNotifier, visibleNotifier: widget.visibleNotifier,
@ -92,7 +95,7 @@ class InfoPageState extends State<InfoPage> {
), ),
); );
final tagSliver = XmpTagSectionSliver( final tagSliver = XmpTagSectionSliver(
collection: widget.collection, collection: collection,
entry: entry, entry: entry,
); );
final metadataSliver = MetadataSectionSliver( final metadataSliver = MetadataSectionSliver(

View file

@ -1,19 +1,25 @@
import 'package:aves/model/collection_filters.dart';
import 'package:aves/model/collection_lens.dart';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/model/settings.dart'; import 'package:aves/model/settings.dart';
import 'package:aves/utils/android_app_service.dart'; import 'package:aves/utils/android_app_service.dart';
import 'package:aves/utils/geo_utils.dart'; import 'package:aves/utils/geo_utils.dart';
import 'package:aves/widgets/album/filtered_collection_page.dart';
import 'package:aves/widgets/fullscreen/info/info_page.dart'; import 'package:aves/widgets/fullscreen/info/info_page.dart';
import 'package:aves/widgets/fullscreen/info/navigation_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:outline_material_icons/outline_material_icons.dart'; import 'package:outline_material_icons/outline_material_icons.dart';
class LocationSection extends StatefulWidget { class LocationSection extends StatefulWidget {
final CollectionLens collection;
final ImageEntry entry; final ImageEntry entry;
final bool showTitle; final bool showTitle;
final ValueNotifier<bool> visibleNotifier; final ValueNotifier<bool> visibleNotifier;
const LocationSection({ const LocationSection({
Key key, Key key,
@required this.collection,
@required this.entry, @required this.entry,
@required this.showTitle, @required this.showTitle,
@required this.visibleNotifier, @required this.visibleNotifier,
@ -26,6 +32,8 @@ class LocationSection extends StatefulWidget {
class _LocationSectionState extends State<LocationSection> { class _LocationSectionState extends State<LocationSection> {
String _loadedUri; String _loadedUri;
CollectionLens get collection => widget.collection;
ImageEntry get entry => widget.entry; ImageEntry get entry => widget.entry;
@override @override
@ -64,12 +72,14 @@ class _LocationSectionState extends State<LocationSection> {
final showMap = (_loadedUri == entry.uri) || (entry.hasGps && widget.visibleNotifier.value); final showMap = (_loadedUri == entry.uri) || (entry.hasGps && widget.visibleNotifier.value);
if (showMap) { if (showMap) {
_loadedUri = entry.uri; _loadedUri = entry.uri;
String location; String location = '';
if (entry.isLocated) { if (entry.isLocated) {
location = entry.addressDetails.addressLine; location = entry.addressDetails.addressLine;
} else if (entry.hasGps) { } else if (entry.hasGps) {
location = toDMS(entry.latLng).join(', '); location = toDMS(entry.latLng).join(', ');
} }
final country = entry.addressDetails?.countryName ?? '';
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -92,6 +102,19 @@ class _LocationSectionState extends State<LocationSection> {
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: InfoRowGroup({'Address': location}), child: InfoRowGroup({'Address': location}),
), ),
if (country.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: NavigationButton.buttonBorderWidth / 2) + const EdgeInsets.only(top: 8),
child: Wrap(
spacing: 8,
children: [
NavigationButton(
label: country,
onPressed: () => _goToCountry(context, country),
),
],
),
),
], ],
); );
} else { } else {
@ -101,6 +124,20 @@ class _LocationSectionState extends State<LocationSection> {
} }
void _handleChange() => setState(() {}); void _handleChange() => setState(() {});
void _goToCountry(BuildContext context, String country) {
if (collection == null) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FilteredCollectionPage(
collection: collection,
filter: CountryFilter(country),
title: country,
),
),
);
}
} }
class ImageMap extends StatefulWidget { class ImageMap extends StatefulWidget {

View file

@ -0,0 +1,29 @@
import 'package:aves/utils/color_utils.dart';
import 'package:flutter/material.dart';
class NavigationButton extends StatelessWidget {
final String label;
final VoidCallback onPressed;
const NavigationButton({
@required this.label,
@required this.onPressed,
});
static const double buttonBorderWidth = 2;
@override
Widget build(BuildContext context) {
return OutlineButton(
onPressed: onPressed,
borderSide: BorderSide(
color: stringToColor(label),
width: buttonBorderWidth,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(42),
),
child: Text(label),
);
}
}

View file

@ -1,9 +1,9 @@
import 'package:aves/model/collection_filters.dart'; import 'package:aves/model/collection_filters.dart';
import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/collection_lens.dart';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/widgets/album/filtered_collection_page.dart'; import 'package:aves/widgets/album/filtered_collection_page.dart';
import 'package:aves/widgets/fullscreen/info/info_page.dart'; import 'package:aves/widgets/fullscreen/info/info_page.dart';
import 'package:aves/widgets/fullscreen/info/navigation_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class XmpTagSectionSliver extends AnimatedWidget { class XmpTagSectionSliver extends AnimatedWidget {
@ -26,12 +26,12 @@ class XmpTagSectionSliver extends AnimatedWidget {
: [ : [
const SectionRow('Tags'), const SectionRow('Tags'),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: TagButton.buttonBorderWidth / 2), padding: const EdgeInsets.symmetric(horizontal: NavigationButton.buttonBorderWidth / 2),
child: Wrap( child: Wrap(
spacing: 8, spacing: 8,
children: tags children: tags
.map((tag) => TagButton( .map((tag) => NavigationButton(
tag: tag, label: tag,
onPressed: () => _goToTag(context, tag), onPressed: () => _goToTag(context, tag),
)) ))
.toList(), .toList(),
@ -56,30 +56,3 @@ class XmpTagSectionSliver extends AnimatedWidget {
); );
} }
} }
class TagButton extends StatelessWidget {
final String tag;
final VoidCallback onPressed;
const TagButton({
@required this.tag,
@required this.onPressed,
});
static const double buttonBorderWidth = 2;
@override
Widget build(BuildContext context) {
return OutlineButton(
onPressed: onPressed,
borderSide: BorderSide(
color: stringToColor(tag),
width: buttonBorderWidth,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(42),
),
child: Text(tag),
);
}
}