From 574c1afc33b28cacaf0cbac390488b9b5bc5c529 Mon Sep 17 00:00:00 2001 From: vjrj Date: Tue, 12 Jun 2018 18:08:49 +0200 Subject: [PATCH] Many work in navegation, map, drawer, about, slider --- images/industry-marker-reg.png | Bin 0 -> 360 bytes images/industry-marker.png | Bin 0 -> 339 bytes lib/activeFires.dart | 108 +++++++++------ lib/basicLocation.dart | 17 ++- lib/basicLocationPersist.dart | 42 +++--- lib/customBottomAppBar.dart | 4 +- lib/customMapPlugin.dart | 58 +++++++++ lib/globals.dart | 5 + lib/homePage.dart | 4 +- lib/leafletMap.dart | 231 ++++++++++++++++++++++++--------- lib/main.dart | 2 +- lib/mainDrawer.dart | 34 +++-- lib/sandbox.dart | 24 +++- lib/slider.dart | 81 +++++++----- pubspec.yaml | 4 + 15 files changed, 446 insertions(+), 168 deletions(-) create mode 100644 images/industry-marker-reg.png create mode 100644 images/industry-marker.png create mode 100644 lib/customMapPlugin.dart diff --git a/images/industry-marker-reg.png b/images/industry-marker-reg.png new file mode 100644 index 0000000000000000000000000000000000000000..a73f6a00698288320bc130e796af772b1f5955a2 GIT binary patch literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^3P7yN!3HFix4(7=Qk(@Ik;M!Q+`=Ht$S`Y;1Oo%3 zl&6bhNJMLLf&}a01d*PmKm#tfgBlVE2Ryi){{w;iQ6V?CIo}K}9%AGHg3nvcjLuxY zna`!iw+5|Nr%@nkJzKfojkH1L=5qZ?*q_=L63{YPLKTqKz<2?bO&i`2}7~N(&@fpO-D~|4JY;1gZ`?b7Hx9>KCIrD3pdqDzE zZ*B)$I%jTy>~zZ;suCYkoM)W=E sCI(Wh%yO*F)+{Ts1n0S(Ji*3r=J19sKVKNu1A~si)78&qol`;+0FRiQ6951J literal 0 HcmV?d00001 diff --git a/images/industry-marker.png b/images/industry-marker.png new file mode 100644 index 0000000000000000000000000000000000000000..2babdab5aff63c3735394aeeab85d2be9e814079 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^3P7yN!3HFix4(90U|^K;ba4!cXiZL#U|pOb($f@Z zz~y#OLn7gT2eVxXk9Xwq z4gCOAyBVb6{@zEoF8>$!@Ds#YzHa}|&-OwyHhvVFvsP^L%l%Pjmi>RhDJ1)Vw-G44 zzD+7YB%-<_@!K@(AdvCv?f*P5^tpM=pzy7)85UU;+7 zxcWfMJoA@4htFL;|L{?snh?+Kb9)*-_g-z0ICrm#{rUZvH>VFAIKXh8(QA?o&+XkZ zg=wyP_!QKn1)1~oz8!tpz<8cj=ZIDdt1dIMN(JY~PF7|)Cgyo;Zi^EREKVqBX9(3j fbXi04CIiEh3G4W$WP}z21B=1a)z4*}Q$iB}iAj=b literal 0 HcmV?d00001 diff --git a/lib/activeFires.dart b/lib/activeFires.dart index 4c3254f..4e2931c 100644 --- a/lib/activeFires.dart +++ b/lib/activeFires.dart @@ -9,10 +9,8 @@ import 'basicLocation.dart'; import 'locationUtils.dart'; import 'globals.dart' as globals; import 'basicLocationPersist.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert' show json; import 'globalFiresBottomStats.dart'; -import 'dart:convert'; +import 'package:flutter_fab_dialer/flutter_fab_dialer.dart'; class ActiveFiresPage extends StatefulWidget { static const String routeName = '/fires'; @@ -26,39 +24,68 @@ class ActiveFiresPage extends StatefulWidget { class _ActiveFiresPageState extends State { final GlobalKey _scaffoldKey = new GlobalKey(); + List _fabMiniMenuItemList(BuildContext context) { + return [ + new FabMiniMenuItem.withText( + new Icon(Icons.location_searching), + fires600, + 8.0, + "Add your current position", + () { + onAddYourLocation(); + }, + "Add your current position", + fires300, + Colors.white, + ), + new FabMiniMenuItem.withText( + new Icon(Icons.edit_location), + fires600, + 8.0, + "Add some other place", + () { + onAddOtherLocation(context); + }, + "Add some other place", + fires300, + Colors.white) + ];} + _ActiveFiresPageState(); Widget _buildRow(BasicLocation loc) { - String desc = loc.description != null - ? loc.description - : 'Position: ${loc.lat}, ${loc.lon}'; return new ListTile( dense: true, leading: const Icon(Icons.location_on), - trailing: const Icon(Icons.notifications_off), - title: new Text(desc), + trailing: new IconButton( + icon: new Icon(loc.isSubscribed + ? Icons.notifications_active + : Icons.notifications_off), + onPressed: () { + loc.subscribed = !loc.isSubscribed; + persistYourLocations(); + setState(() {}); + }), + title: new Text(loc.description), onLongPress: () { showSnackMsg('Slide horizontally to delete this location'); }, onTap: () { - const String km = '100'; - var url = '${globals.firesApiUrl}fires-in/${globals - .firesApiKey}/${loc.lat}/${loc - .lon}/$km'; - http.read(url).then((result) { - int numFires = json.decode(result)['real']; - Navigator.push( - context, - new MaterialPageRoute( - builder: (context) => new LeafletMap( - title: desc, - location: loc, - numFires: numFires, - kmAround: km))); - }); + showLocationMap(loc); }); } + void showLocationMap(BasicLocation loc) { + // , VoidCallback onSubs + Navigator.push( + context, + new MaterialPageRoute( + builder: (context) => new LeafletMap( + title: loc.description, + location: loc, + ))); + } + void showSnackMsg(String msg) { _scaffoldKey.currentState.showSnackBar(new SnackBar( content: new Text(msg), @@ -91,7 +118,7 @@ class _ActiveFiresPageState extends State { void handleUndo(BasicLocation item) { setState(() { globals.yourLocations.add(item); - persist(); + persistYourLocations(); }); } @@ -103,7 +130,7 @@ class _ActiveFiresPageState extends State { onDismissed: (DismissDirection direction) { setState(() { globals.yourLocations.remove(item); - persist(); + persistYourLocations(); }); final String action = 'deleted'; _scaffoldKey.currentState.showSnackBar(new SnackBar( @@ -132,16 +159,11 @@ class _ActiveFiresPageState extends State { child: _buildRow(item))); } - void persist() { - globals.prefs.then((prefs) { - persistYourLocations(prefs); - }); - } - @override Widget build(BuildContext context) { + var hasLocations = globals.yourLocations.length > 0; + final title = hasLocations ? 'Active fires in your places': 'Active fires in the world'; print('Building Active Fires'); - final title = 'Your locations'; return Scaffold( key: _scaffoldKey, // FIXME new? @@ -157,29 +179,32 @@ class _ActiveFiresPageState extends State { ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, bottomNavigationBar: new GlobalFiresBottomStats(), - body: globals.yourLocations.length > 0 - ? _buildSavedLocations() + body: hasLocations + ? new Stack(children: [ + _buildSavedLocations(), + new FabDialer(_fabMiniMenuItemList(context), fires600, new Icon(Icons.add)) + ]) : new Center( child: new CenteredColumn(children: [ new RoundedBtn( icon: Icons.location_searching, - text: 'Add your position', + text: 'Fires near your', onPressed: onAddYourLocation, backColor: fires600), const SizedBox(height: 26.0), new RoundedBtn( icon: Icons.edit_location, - text: 'Add some other place', + text: 'Fires near other place', onPressed: () { onAddOtherLocation(context); }, backColor: fires600), ])), - floatingActionButton: globals.yourLocations.length > 0 + floatingActionButton: hasLocations ? Column(mainAxisAlignment: MainAxisAlignment.end, // crossAxisAlignment: CrossAxisAlignment.center, children: [ - FloatingActionButton.extended( + /* FloatingActionButton.extended( onPressed: onAddYourLocation, heroTag: 'yourposition', label: const Text('Add your position'), @@ -195,7 +220,7 @@ class _ActiveFiresPageState extends State { label: new Text('Add some other place'), icon: const Icon(Icons.edit_location), ), - ) + ), */ ]) : null, ); @@ -219,7 +244,10 @@ class _ActiveFiresPageState extends State { } else this.setState(() { globals.yourLocations.add(newLocation); - persist(); + persistYourLocations(); + new Timer(new Duration(milliseconds: 1000), () { + showLocationMap(newLocation); + }); }); } }); diff --git a/lib/basicLocation.dart b/lib/basicLocation.dart index 040de65..c5f4a43 100644 --- a/lib/basicLocation.dart +++ b/lib/basicLocation.dart @@ -4,10 +4,14 @@ class BasicLocation extends Comparable { final double lat; final double lon; String description; + bool subscribed; static BasicLocation noLocation = new BasicLocation(lat: 0.0, lon: 0.0); - BasicLocation({@required this.lat, @required this.lon, this.description}); + BasicLocation({@required this.lat, @required this.lon, this.description, this.subscribed: false}) { + if (this.description == null) + this.description = 'Position: ${this.lat}, ${this.lon}'; + } int compareTo(BasicLocation other) { return lat == other.lat && lon == other.lon ? 1 : 0; @@ -15,6 +19,17 @@ class BasicLocation extends Comparable { bool operator ==(o) => o is BasicLocation && o.lat == lat && o.lon == lon; + int get hashCode { + int hash = 1; + hash = hash * 17 + lat.hashCode; + hash = hash * 31 + lon.hashCode; + return hash; + } + + bool get isSubscribed { + return subscribed == null ? false : subscribed; + } + BasicLocation.fromJson(Map json) : lat = json['lat'], lon = json['lon'], diff --git a/lib/basicLocationPersist.dart b/lib/basicLocationPersist.dart index a721b87..a6ea7cf 100644 --- a/lib/basicLocationPersist.dart +++ b/lib/basicLocationPersist.dart @@ -1,24 +1,36 @@ import 'dart:convert'; import 'basicLocation.dart'; import 'globals.dart' as globals; + +import 'package:shared_preferences/shared_preferences.dart'; final String locationKey = 'yourlocations'; -void loadYourLocations(prefs) { - List yourLocations = prefs.getStringList(locationKey); - if (yourLocations == null) { - yourLocations = []; - persistYourLocations(prefs); - } - yourLocations.forEach((locationString) { - Map locationMap = json.decode(locationString); - globals.yourLocations.add(BasicLocation.fromJson(locationMap)); +void loadYourLocations() { + globals.prefs.then((prefs) { + loadYourLocationsWithPrefs(prefs); }); } -persistYourLocations(prefs) { - List yourLocationsAsString = []; - globals.yourLocations.forEach((location) { - yourLocationsAsString.add(json.encode(location.toJson())); +persistYourLocations() { + globals.prefs.then((prefs) { + List yourLocationsAsString = []; + globals.yourLocations.forEach((location) { + yourLocationsAsString.add(json.encode(location.toJson())); + }); + prefs.setStringList(locationKey, yourLocationsAsString); }); - prefs.setStringList(locationKey, yourLocationsAsString); -} \ No newline at end of file +} + +void loadYourLocationsWithPrefs(SharedPreferences prefs) { + globals.prefs.then((prefs) { + List yourLocations = prefs.getStringList(locationKey); + if (yourLocations == null) { + yourLocations = []; + persistYourLocations(); + } + yourLocations.forEach((locationString) { + Map locationMap = json.decode(locationString); + globals.yourLocations.add(BasicLocation.fromJson(locationMap)); + }); + }); +} diff --git a/lib/customBottomAppBar.dart b/lib/customBottomAppBar.dart index d26a356..162a433 100644 --- a/lib/customBottomAppBar.dart +++ b/lib/customBottomAppBar.dart @@ -4,11 +4,13 @@ class CustomBottomAppBar extends StatelessWidget { const CustomBottomAppBar( {this.fabLocation, this.showNotch, + this.height = 56.0, this.color = Colors.black45, this.mainAxisAlignment = MainAxisAlignment.center, this.actions}); final Color color; + final double height; final MainAxisAlignment mainAxisAlignment; final FloatingActionButtonLocation fabLocation; final bool showNotch; @@ -22,7 +24,7 @@ class CustomBottomAppBar extends StatelessWidget { @override Widget build(BuildContext context) { - final List rowContents = [new SizedBox(height: 56.0)]; + final List rowContents = [new SizedBox(height: height)]; if (kCenterLocations.contains(fabLocation)) { /* rowContents.add( diff --git a/lib/customMapPlugin.dart b/lib/customMapPlugin.dart new file mode 100644 index 0000000..fd29515 --- /dev/null +++ b/lib/customMapPlugin.dart @@ -0,0 +1,58 @@ +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_map/plugin_api.dart'; +import 'package:flutter/material.dart'; +import 'package:comunes_flutter/comunes_flutter.dart'; + +class ZoomMapPluginOptions extends LayerOptions { + final String text; + + ZoomMapPluginOptions({this.text = ""}); +} + +// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/plugin_api.dart +class ZoomMapPlugin extends MapPlugin { + IconButton zoomButton(MapState mapState, IconData zoomIcon, int inc) { + return new IconButton( + icon: Icon(zoomIcon), + onPressed: () { + var currentZoom = mapState.zoom; + var currentCenter = mapState.center; + mapState.move(currentCenter, currentZoom + inc); + }); + } + + @override + Widget createLayer(LayerOptions options, MapState mapState) { + if (options is ZoomMapPluginOptions) { + /* print('point ${mapState + .getPixelBounds(mapState.zoom) + .bottomLeft}'); */ + return LayoutBuilder( + builder: (context, constraints) => + Stack(fit: StackFit.expand, children: [ + Positioned( + top: constraints.maxHeight - 100, + right: 10.0, + // left: 10.0, + child: new CenteredRow( + children: [ + new Column( + children: [ + zoomButton(mapState, Icons.zoom_in, 1), + zoomButton(mapState, Icons.zoom_out, -1) + ], + ) + ], + ), + ) + ])); + } + throw ("Unknown options type for ZoomMapPlugin" + "plugin: $options"); + } + + @override + bool supportsLayer(LayerOptions options) { + return options is ZoomMapPluginOptions; + } +} diff --git a/lib/globals.dart b/lib/globals.dart index f234e36..c573976 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -3,11 +3,16 @@ import 'package:get_it/get_it.dart'; import 'dart:async'; import 'package:shared_preferences/shared_preferences.dart'; import 'basicLocation.dart'; +import 'package:flutter/material.dart'; String gmapKey; String firesApiKey; String firesApiUrl; String appName = 'All Against The Fire!'; +String appVersion = '0.0.1'; +String appLicense = "(c) 2017-2018 Comunes Association under the GNU Affero GPL v3"; +Widget appMediumIcon = Image.asset('images/logo-200.png', width: 60.0, height: 60.0); +Widget appIcon = Image.asset('images/logo-200.png', width: 24.0, height: 24.0); Future prefs = SharedPreferences.getInstance(); final List yourLocations = []; final GetIt getIt = new GetIt(); diff --git a/lib/homePage.dart b/lib/homePage.dart index c14208d..c9d26f7 100644 --- a/lib/homePage.dart +++ b/lib/homePage.dart @@ -36,8 +36,8 @@ class HomePage extends StatelessWidget { ]), new Expanded( child: new FractionallySizedBox( - alignment: FractionalOffset.bottomCenter, - heightFactor: 0.9, + alignment: FractionalOffset.center, + heightFactor: 0.8, child: new Image.asset('images/logo-200.png', fit: BoxFit.fitHeight))), new Expanded( diff --git a/lib/leafletMap.dart b/lib/leafletMap.dart index 5a74756..7fd42ee 100644 --- a/lib/leafletMap.dart +++ b/lib/leafletMap.dart @@ -7,21 +7,24 @@ import 'package:comunes_flutter/comunes_flutter.dart'; import 'colors.dart'; import 'customBottomAppBar.dart'; import 'dart:core'; +import 'globals.dart' as globals; +import 'package:http/http.dart' as http; +import 'dart:convert' show json; +import 'slider.dart'; +import 'customMapPlugin.dart'; +import 'package:just_debounce_it/just_debounce_it.dart'; + +enum MarkType { position, fire, industry, falsePos } class LeafletMap extends StatefulWidget { final BasicLocation location; final String title; - final int numFires; - final String kmAround; - LeafletMap({@required this.title, @required this.location, - @required this.numFires, @required this.kmAround - }); + LeafletMap({@required this.title, @required this.location}); @override - _LeafletMapState createState() => _LeafletMapState(title: title, location: location, - numFires: numFires, kmAround: kmAround - ); + _LeafletMapState createState() => + _LeafletMapState(title: title, location: location); } class _LeafletMapState extends State { @@ -29,26 +32,94 @@ class _LeafletMapState extends State { final BasicLocation location; final String title; - final int numFires; - final String kmAround; + int numFires; + int kmAround = 100; + List fires = []; + List falsePos = []; + List industries = []; + + @override + void initState() { + super.initState(); + updateFireStats(); + } + + void updateFireStats() { + var url = '${globals.firesApiUrl}fires-in-full/${globals + .firesApiKey}/${location.lat}/${location.lon}/$kmAround'; + http.read(url).then((result) { + setState(() { + var resultDecoded = json.decode(result); + print(resultDecoded); + numFires = resultDecoded['real']; + fires = resultDecoded['fires']; + falsePos = resultDecoded['falsePos']; + industries = resultDecoded['industries']; + + var firesCount = fires.length; + var industriesCount = industries.length; + var falsePosCount = falsePos.length; + + print( + 'fire: $firesCount falsePos: $falsePosCount industries: $industriesCount'); + }); + }); + } + + _LeafletMapState({@required this.title, @required this.location}); - _LeafletMapState({@required this.title, @required this.location, - @required this.numFires, @required this.kmAround - }); @override Widget build(BuildContext context) { + MapOptions mapOptions = new MapOptions( + center: new LatLng(this.location.lat, this.location.lon), + plugins: [new ZoomMapPlugin()], + // this works ? + // interactive: false, + zoom: 13.0, + // THIS does not works as expected + // maxZoom: 6.0, + onPositionChanged: (positionCallback) { + // decouple + // print('${positionCallback.center}, ${positionCallback.zoom}'); + }); + var mapController = new MapController(); + // mapController.fitBounds(bounds); + // mapController.center + var fmap = new FlutterMap( + options: mapOptions, + mapController: mapController, + layers: [ + new TileLayerOptions( + maxZoom: 6.0, + subdomains: ['a', 'b', 'c'], + urlTemplate: 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', + additionalOptions: { + // 'opacity': '0.1', + 'attribution': + '© OpenStreetMap contributors' + }, + ), + new ZoomMapPluginOptions(), + new MarkerLayerOptions( + markers: buildMarkers( + this.location, this.fires, this.industries, this.falsePos), + ), + ], + ); + return new Scaffold( - key: _scaffoldKey, + key: _scaffoldKey, // drawer: new MainDrawer(context), appBar: new AppBar( title: new Text(title), ), floatingActionButton: FloatingActionButton.extended( - onPressed: () { - - }, + onPressed: () {}, icon: const Icon(Icons.notifications_none, color: fires600), - label: new Text('Subscribe', style: const TextStyle(color: fires600),), + label: new Text( + 'Subscribe', + style: const TextStyle(color: fires600), + ), backgroundColor: Colors.white, ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, @@ -56,54 +127,90 @@ class _LeafletMapState extends State { fabLocation: FloatingActionButtonLocation.centerFloat, showNotch: false, color: fires100, + // height: 170.0, mainAxisAlignment: MainAxisAlignment.center, actions: listWithoutNulls([ - numFires > 0 ? - new Text('${numFires.toString()} fires at $kmAround км around this area'): - new Text('There is no fires at $kmAround км around this area'), + numFires == null + ? null + : numFires > 0 + ? new Text('${numFires.toString()} fires at ${kmAround + .toString()} км around this area') + : new Text( + 'There is no fires at ${kmAround.toString()} км around this area'), SizedBox(width: 10.0) ])), - body: new FlutterMap( - options: new MapOptions( - center: new LatLng(this.location.lat, this.location.lon), - zoom: 13.0, - // THIS does not works as expected - // maxZoom: 6.0, - onPositionChanged: (positionCallback) { - print('$positionCallback'); - } - ), - layers: [ - new TileLayerOptions( - maxZoom: 6.0, - urlTemplate: 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', - additionalOptions: { - // 'opacity': '0.1', - 'attribution': '© OpenStreetMap contributors' - }, - ), /* - new TileLayerOptions( - urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - additionalOptions: { - // 'opacity': '0.1', - 'attribution': '&copy OpenStreetMap contributors' - }, + body: LayoutBuilder( + builder: (context, constraints) => + Stack(fit: StackFit.expand, children: [ + // Material(color: Colors.yellowAccent), + fmap, + Positioned( + top: constraints.maxHeight - 160, + right: 10.0, + left: 10.0, + child: new CenteredRow( + // Fit sample: + // https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/map_controller.dart + children: [ + new FireDistanceSlider( + initialValue: kmAround, + onSlide: (distance) { + setState(() { + kmAround = distance; + Debounce.seconds(1, updateFireStats); + }); + }) + ], + ), + ) + ]), + )); + } - ), */ - new MarkerLayerOptions( - markers: [ - new Marker( - width: 80.0, - height: 80.0, - point: new LatLng(this.location.lat, this.location.lon), - builder: (ctx) => - new Container( - child: new Image.asset('images/fire-marker-l.png'), - ), - ), - ], - ), - ], - )); + List buildMarkers(BasicLocation yourLocation, List fires, + List falsePos, List industries) { + List markers = []; + markers.add(buildMarker(yourLocation, MarkType.position)); + falsePos.forEach((fire) { + var coords = fire['geo']['coordinates']; + var loc = BasicLocation(lon: coords[0], lat: coords[1]); + markers.add(buildMarker(loc, MarkType.falsePos)); + }); + industries.forEach((fire) { + // print(fire['geo']['coordinates']); + var coords = fire['geo']['coordinates']; + var loc = BasicLocation(lon: coords[0], lat: coords[1]); + markers.add(buildMarker(loc, MarkType.industry)); + }); + fires.forEach((fire) { + var loc = new BasicLocation(lat: fire['lat'], lon: fire['lon']); + markers.add(buildMarker(loc, MarkType.fire)); + }); + return markers; + } + + Marker buildMarker(location, MarkType type) { + return new Marker( + width: 80.0, + height: 80.0, + point: new LatLng(location.lat, location.lon), + builder: (ctx) => new Container( + child: buildImageMark(type), + ), + ); + } + + Widget buildImageMark(MarkType type) { + switch (type) { + case MarkType.position: + return new Icon(Icons.location_on, color: fires600, size: 50.0); + case MarkType.fire: + return new Image.asset('images/fire-marker-l.png'); + case MarkType.industry: + return new Image.asset('images/industry-marker-reg.png'); + case MarkType.falsePos: + default: + return new Image.asset('images/industry-marker.png'); + } } } diff --git a/lib/main.dart b/lib/main.dart index 618db07..edab90a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,7 +16,7 @@ void main() { globals.firesApiKey = secrets['firesApiKey']; globals.firesApiUrl = secrets['firesApiUrl']; globals.prefs.then((prefs) { - loadYourLocations(prefs); + loadYourLocationsWithPrefs(prefs); // Run baby run! runApp(new FiresApp()); diff --git a/lib/mainDrawer.dart b/lib/mainDrawer.dart index 486213b..466f16a 100644 --- a/lib/mainDrawer.dart +++ b/lib/mainDrawer.dart @@ -41,7 +41,7 @@ Widget mainDrawer(BuildContext context) { ), ), ), - new ListTile( + /* new ListTile( // https://docs.flutter.io/flutter/material/CircleAvatar-class.html leading: new CircleAvatar( backgroundColor: Colors.brown.shade800, @@ -49,14 +49,10 @@ Widget mainDrawer(BuildContext context) { ), title: new Text('Your profile'), onTap: () { - // Update the state of the app - // ... - // Then close the drawer - // Navigator.pop(context); Navigator.pushNamed(context, IntroPage.routeName); }, ), - new Divider(), + new Divider(), */ new ListTile( leading: const Icon(Icons.whatshot), title: new Text('Active fires'), @@ -65,14 +61,22 @@ Widget mainDrawer(BuildContext context) { }, ), new ListTile( - leading: const Icon(Icons.location_on), - title: new Text('My subscribed areas'), + leading: const Icon(Icons.notifications_active), + title: new Text('Notify a fire'), + onTap: () { + // Then close the drawer + Navigator.pushNamed(context, Sandbox.routeName); + }, + ), + new Divider(), + new ListTile( + leading: const Icon(Icons.favorite), + title: new Text('Support this initiative'), onTap: () { // Then close the drawer Navigator.pushNamed(context, '/subscriptions'); }, ), - new Divider(), new ListTile( leading: const Icon(Icons.bug_report), title: new Text('Sandbox'), @@ -92,8 +96,16 @@ Widget mainDrawer(BuildContext context) { }, ), new AboutListTile( - // FIXME - ) + icon: globals.appIcon, + applicationName: globals.appName, + applicationVersion: globals.appVersion, + applicationIcon: globals.appMediumIcon, + applicationLegalese: globals.appLicense, + aboutBoxChildren: [ + // new Text('What?') + ] + // FIXME + ) ], ); } diff --git a/lib/sandbox.dart b/lib/sandbox.dart index fe25e6c..192593a 100644 --- a/lib/sandbox.dart +++ b/lib/sandbox.dart @@ -13,13 +13,25 @@ class Sandbox extends StatelessWidget { @override Widget build(BuildContext context) { - //showDialog(context: context, child: builder(context)); + //showDialog(context: context, child: builder(context)); return Scaffold( - body: new CenteredColumn( - children: [ - new FireDistanceSlider() - - ], + body: LayoutBuilder( + builder: (context, constraints) => + Stack(fit: StackFit.expand, children: [ + // Material(color: Colors.yellowAccent), + Positioned( + top: 0.0, + child: Icon(Icons.star, size: 40.0), + ), + Positioned( + top: constraints.maxHeight - 80, + right: 10.0, + left: 10.0, + child: new CenteredRow( + children: [new FireDistanceSlider()], + ), + ) + ]), ), ); } diff --git a/lib/slider.dart b/lib/slider.dart index 05ee9f3..d58d32b 100644 --- a/lib/slider.dart +++ b/lib/slider.dart @@ -1,45 +1,68 @@ import 'package:flutter/material.dart'; import 'colors.dart'; import 'package:comunes_flutter/comunes_flutter.dart'; +import 'package:padder/padding.dart'; + +typedef void SlideCallback(int distance); class FireDistanceSlider extends StatefulWidget { + final int initialValue; + final SlideCallback onSlide; + + FireDistanceSlider({this.initialValue, this.onSlide}); + @override - _FireDistanceSliderState createState() => new _FireDistanceSliderState(); + _FireDistanceSliderState createState() => new _FireDistanceSliderState( + initialValue: initialValue, onSlide: onSlide); } class _FireDistanceSliderState extends State { - int _discreteValue = 10; + int _sliderValue; + final SlideCallback onSlide; + + _FireDistanceSliderState({int initialValue = 10, this.onSlide}) { + this._sliderValue = initialValue; + } + + sizeText(_sliderValue) => + new Text('Subscribe to $_sliderValue км around this area'); + + warningText(_sliderValue) => _sliderValue >= 50 + ? new Text('Warning: this is a very large area', + style: new TextStyle(color: fires900)) + : new Text(''); @override Widget build(BuildContext context) { + var slider = new Slider( + value: _sliderValue + 0.0, + activeColor: fires900, + inactiveColor: Colors.black45, + + min: 1.0, + max: 100.0, + divisions: 99, + label: '${_sliderValue.round()}', + onChanged: (double value) { + _sliderValue = value.round(); + if (onSlide != null) { + onSlide(_sliderValue); + } + setState(() {}); + }, + ); return new Column( - children: [ - new Column( - mainAxisSize: MainAxisSize.min, - children: - listWithoutNulls([ - new Slider( - value: _discreteValue + 0.0, - activeColor: fires900, - min: 1.0, - max: 100.0, - divisions: 99, - label: '${_discreteValue.round()}', - onChanged: (double value) { - setState(() { - _discreteValue = value.round(); - }); - }, - ), - new Text('Subscribe to $_discreteValue км around this area'), - _discreteValue >= 50 ? - new Text( - 'Warning: this is a very large area', - style: new TextStyle(color: Colors.orange) - ): new Text('') - ]), - ), - ], + mainAxisSize: MainAxisSize.min, + children: listWithoutNulls([ + slider, + new Card( + color: const Color(0x60FFFFFF), + child: PaddingAll(10.0, + child: new Column(children: [ + sizeText(_sliderValue), + warningText(_sliderValue) + ]))) + ]), ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 1c47178..ff89a1d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,8 @@ dependencies: http: "^0.11.3+16" simple_moment: "^0.0.3" geocoder: "^0.0.1" + just_debounce_it: "^1.0.4" + flutter_fab_dialer: "^0.0.5" dev_dependencies: flutter_test: @@ -52,6 +54,8 @@ flutter: - images/fire-marker-m.png - images/fire-marker-s.png - images/fire-marker.png + - images/industry-marker-reg.png + - images/industry-marker.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.io/assets-and-images/#resolution-aware.