info: improved loading of location & metadata sections
This commit is contained in:
parent
6feb1efb13
commit
a5115fb83b
6 changed files with 145 additions and 57 deletions
|
@ -1,7 +1,14 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
final Map<String, Color> _stringColors = {};
|
||||||
|
|
||||||
Color stringToColor(String string, {double saturation = .8, double lightness = .6}) {
|
Color stringToColor(String string, {double saturation = .8, double lightness = .6}) {
|
||||||
|
var color = _stringColors[string];
|
||||||
|
if (color == null) {
|
||||||
final hash = string.codeUnits.fold(0, (prev, el) => prev = el + ((prev << 5) - prev));
|
final hash = string.codeUnits.fold(0, (prev, el) => prev = el + ((prev << 5) - prev));
|
||||||
final hue = (hash % 360).toDouble();
|
final hue = (hash % 360).toDouble();
|
||||||
return HSLColor.fromAHSL(1.0, hue, saturation, lightness).toColor();
|
color = HSLColor.fromAHSL(1.0, hue, saturation, lightness).toColor();
|
||||||
|
_stringColors[string] = color;
|
||||||
|
}
|
||||||
|
return color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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/common/aves_filter_chip.dart';
|
import 'package:aves/widgets/common/aves_filter_chip.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/map_initializer.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';
|
||||||
|
@ -168,13 +169,15 @@ class ImageMapState extends State<ImageMap> with AutomaticKeepAliveClientMixin {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SizedBox(
|
|
||||||
height: 200,
|
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: const BorderRadius.all(
|
||||||
Radius.circular(16),
|
Radius.circular(16),
|
||||||
),
|
),
|
||||||
child: GoogleMap(
|
child: Container(
|
||||||
|
color: Colors.white70,
|
||||||
|
height: 200,
|
||||||
|
child: GoogleMapInitializer(
|
||||||
|
builder: (context) => GoogleMap(
|
||||||
initialCameraPosition: CameraPosition(
|
initialCameraPosition: CameraPosition(
|
||||||
target: widget.latLng,
|
target: widget.latLng,
|
||||||
zoom: widget.initialZoom,
|
zoom: widget.initialZoom,
|
||||||
|
@ -197,6 +200,7 @@ class ImageMapState extends State<ImageMap> with AutomaticKeepAliveClientMixin {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Column(children: [
|
Column(children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
|
|
65
lib/widgets/fullscreen/info/map_initializer.dart
Normal file
65
lib/widgets/fullscreen/info/map_initializer.dart
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
// workaround to Google Maps initialization blocking the dart thread
|
||||||
|
// cf https://github.com/flutter/flutter/issues/28493
|
||||||
|
// it loads first Google Maps in an isolate, and then build the desired map
|
||||||
|
|
||||||
|
class GoogleMapInitializer extends StatefulWidget {
|
||||||
|
final WidgetBuilder builder, errorBuilder, placeholderBuilder;
|
||||||
|
|
||||||
|
const GoogleMapInitializer({
|
||||||
|
@required this.builder,
|
||||||
|
this.errorBuilder,
|
||||||
|
this.placeholderBuilder,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_GoogleMapInitializerState createState() => _GoogleMapInitializerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GoogleMapInitializerState extends State<GoogleMapInitializer> {
|
||||||
|
Future<void> initializer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
initializer = compute(_preload, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FutureBuilder(
|
||||||
|
future: initializer,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) {
|
||||||
|
return widget.errorBuilder?.call(context) ?? const Icon(Icons.error_outline);
|
||||||
|
} else if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
return widget.builder(context);
|
||||||
|
} else {
|
||||||
|
return widget.placeholderBuilder?.call(context) ?? const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _preload(_) async {
|
||||||
|
final mapCreatedCompleter = Completer();
|
||||||
|
GoogleMap(
|
||||||
|
compassEnabled: false,
|
||||||
|
mapToolbarEnabled: false,
|
||||||
|
rotateGesturesEnabled: false,
|
||||||
|
scrollGesturesEnabled: false,
|
||||||
|
zoomGesturesEnabled: false,
|
||||||
|
tiltGesturesEnabled: false,
|
||||||
|
buildingsEnabled: false,
|
||||||
|
initialCameraPosition: const CameraPosition(target: LatLng(0, 0), zoom: 20),
|
||||||
|
onMapCreated: (controller) => mapCreatedCompleter.complete(),
|
||||||
|
);
|
||||||
|
return mapCreatedCompleter.future;
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import 'package:aves/model/metadata_service.dart';
|
||||||
import 'package:aves/utils/color_utils.dart';
|
import 'package:aves/utils/color_utils.dart';
|
||||||
import 'package:aves/widgets/common/fx/highlight_decoration.dart';
|
import 'package:aves/widgets/common/fx/highlight_decoration.dart';
|
||||||
import 'package:aves/widgets/fullscreen/info/info_page.dart';
|
import 'package:aves/widgets/fullscreen/info/info_page.dart';
|
||||||
|
import 'package:expansion_tile_card/expansion_tile_card.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:outline_material_icons/outline_material_icons.dart';
|
import 'package:outline_material_icons/outline_material_icons.dart';
|
||||||
|
|
||||||
|
@ -63,37 +64,36 @@ class _MetadataSectionSliverState extends State<MetadataSectionSliver> with Auto
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
|
|
||||||
final directoriesWithoutTitle = _metadata.where((dir) => dir.name.isEmpty);
|
if (_metadata.isEmpty) return const SliverToBoxAdapter(child: SizedBox.shrink());
|
||||||
final directoriesWithTitle = _metadata.where((dir) => dir.name.isNotEmpty);
|
|
||||||
|
final directoriesWithoutTitle = _metadata.where((dir) => dir.name.isEmpty).toList();
|
||||||
|
final directoriesWithTitle = _metadata.where((dir) => dir.name.isNotEmpty).toList();
|
||||||
|
final untitledDirectoryCount = directoriesWithoutTitle.length;
|
||||||
return SliverList(
|
return SliverList(
|
||||||
delegate: SliverChildListDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
[
|
(context, index) {
|
||||||
if (_metadata.isNotEmpty) const SectionRow(OMIcons.info),
|
if (index == 0) {
|
||||||
...directoriesWithoutTitle.map((dir) => InfoRowGroup(dir.tags)),
|
return const SectionRow(OMIcons.info);
|
||||||
Theme(
|
}
|
||||||
data: Theme.of(context).copyWith(cardColor: Colors.grey[900]),
|
if (index < untitledDirectoryCount + 1) {
|
||||||
child: ExpansionPanelList.radio(
|
final dir = directoriesWithoutTitle[index - 1];
|
||||||
key: ValueKey(widget.entry.uri),
|
return InfoRowGroup(dir.tags);
|
||||||
expandedHeaderPadding: EdgeInsets.zero,
|
}
|
||||||
children: directoriesWithTitle.map<ExpansionPanelRadio>((dir) {
|
final dir = directoriesWithTitle[index - 1 - untitledDirectoryCount];
|
||||||
return ExpansionPanelRadio(
|
return ExpansionTileCard(
|
||||||
value: dir.name,
|
|
||||||
canTapOnHeader: true,
|
|
||||||
headerBuilder: (BuildContext context, bool isExpanded) {
|
|
||||||
return ListTile(
|
|
||||||
title: _DirectoryTitle(dir.name),
|
title: _DirectoryTitle(dir.name),
|
||||||
);
|
children: [
|
||||||
},
|
const Divider(thickness: 1.0, height: 1.0),
|
||||||
body: Container(
|
Container(
|
||||||
alignment: Alignment.topLeft,
|
alignment: Alignment.topLeft,
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: InfoRowGroup(dir.tags),
|
child: InfoRowGroup(dir.tags),
|
||||||
),
|
),
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
|
baseColor: Colors.grey[900],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
childCount: 1 + _metadata.length,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,7 @@ class _DirectoryTitle extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
name,
|
name,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
shadows: [
|
shadows: [
|
||||||
Shadow(
|
Shadow(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
|
@ -153,6 +154,9 @@ class _DirectoryTitle extends StatelessWidget {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontFamily: 'Concourse Caps',
|
fontFamily: 'Concourse Caps',
|
||||||
),
|
),
|
||||||
|
softWrap: false,
|
||||||
|
overflow: TextOverflow.fade,
|
||||||
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -101,6 +101,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
expansion_tile_card:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: expansion_tile_card
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
flushbar:
|
flushbar:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -23,6 +23,7 @@ dependencies:
|
||||||
git:
|
git:
|
||||||
url: git://github.com/deckerst/flutter-draggable-scrollbar.git
|
url: git://github.com/deckerst/flutter-draggable-scrollbar.git
|
||||||
event_bus:
|
event_bus:
|
||||||
|
expansion_tile_card:
|
||||||
flushbar:
|
flushbar:
|
||||||
# flushbar-1.9.1 cannot be built with Flutter 1.15.17
|
# flushbar-1.9.1 cannot be built with Flutter 1.15.17
|
||||||
git:
|
git:
|
||||||
|
|
Loading…
Reference in a new issue