diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..66f0daa Binary files /dev/null and b/assets/logo.png differ diff --git a/lib/views/organizations/item.dart b/lib/views/organizations/item.dart index e267cbd..6f9e668 100644 --- a/lib/views/organizations/item.dart +++ b/lib/views/organizations/item.dart @@ -2,35 +2,51 @@ import 'package:flutter/material.dart'; import 'package:strollplanner_tracker/models/org.dart'; import 'package:strollplanner_tracker/views/routes/list.dart'; -class OrganizationItem extends StatelessWidget { +class OrganizationItemTile extends StatelessWidget { final Organization org; - OrganizationItem(this.org); + OrganizationItemTile(this.org); @override Widget build(BuildContext context) { - return Stack(children: [ - Container( + return Container( + padding: EdgeInsets.all(10), decoration: BoxDecoration( + color: Colors.white, borderRadius: BorderRadius.circular(10), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), spreadRadius: 5, - blurRadius: 7, - offset: - Offset(0, 3), // changes position of shadow + blurRadius: 10, + offset: Offset(0, 3), // changes position of shadow ), ], ), - child: ListTile( - leading: Image.network(org.logoUrl), - title: Text(org.name), - contentPadding: EdgeInsets.all(10), - tileColor: Colors.white, - trailing: Icon(Icons.keyboard_arrow_right_outlined, size: 40, color: Colors.black87), - ), - ), + child: Row( + children: [ + Image.network(org.logoUrl, height: 100, width: 100), + Expanded( + child: Container( + padding: EdgeInsets.all(10), + child: Text(org.name, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)))), + Icon(Icons.keyboard_arrow_right_outlined, + size: 40, color: Colors.black87), + ], + )); + } +} + +class OrganizationItem extends StatelessWidget { + final Organization org; + + OrganizationItem(this.org); + + @override + Widget build(BuildContext context) { + return Stack(children: [ + OrganizationItemTile(org), Positioned.fill( child: Material( color: Colors.transparent, @@ -48,4 +64,4 @@ class OrganizationItem extends StatelessWidget { ) ]); } -} \ No newline at end of file +} diff --git a/lib/views/organizations/list.dart b/lib/views/organizations/list.dart index 55d0104..9482f8b 100644 --- a/lib/views/organizations/list.dart +++ b/lib/views/organizations/list.dart @@ -21,50 +21,32 @@ class _OrganizationsPageState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(999), - border: Border.all( - color: Colors.white, - width: 1, - ), - ), - child: Image.asset( - "assets/icon.png", - fit: BoxFit.cover, - height: 35.0, - )), - SizedBox(width: 20), - Text("StrollPlanner") - ], + print(organizations?.length); + return SafeArea( + child: Column( + children: [ + Container( + width: MediaQuery.of(context).size.width * 0.70, + child: Image.asset( + "assets/logo.png", + fit: BoxFit.cover, ), - actions: [ - FlatButton( - textColor: Colors.white, - onPressed: () { - AuthService.of(context, listen: false).logout(); - }, - child: Text("Logout"), - shape: CircleBorder(side: BorderSide(color: Colors.transparent)), - ), - ], + padding: EdgeInsets.all(30), ), - body: organizations == null - ? Center(child: CircularProgressIndicator()) - : RefreshIndicator( - child: ListView.separated( - itemCount: organizations.length, - itemBuilder: (_, index) => - OrganizationItem(organizations[index]), - separatorBuilder: (_, index) => SizedBox(height: 20), - ), - onRefresh: fetchOrganizations, - )); + Expanded( + child: organizations == null + ? Center(child: CircularProgressIndicator()) + : RefreshIndicator( + child: ListView.separated( + itemCount: organizations.length, + itemBuilder: (_, index) => + OrganizationItem(organizations[index]), + separatorBuilder: (_, index) => SizedBox(height: 20), + ), + onRefresh: fetchOrganizations, + )) + ], + )); } Future fetchOrganizations() async { diff --git a/lib/views/root.dart b/lib/views/root.dart index 1cea3f4..f8e5707 100644 --- a/lib/views/root.dart +++ b/lib/views/root.dart @@ -58,13 +58,12 @@ class RootPage extends StatelessWidget { return MaterialApp( title: 'StrollPlanner', theme: ThemeData( - primarySwatch: createMaterialColor(Color(0xFF005DCC)), - // This makes the visual density adapt to the platform that you run - // the app on. For desktop platforms, the controls will be smaller and - // closer together (more dense) than on mobile platforms. - visualDensity: VisualDensity.adaptivePlatformDensity, - backgroundColor: Color(0xf4f4f4ff) - ), + primarySwatch: createMaterialColor(Color(0xFF005DCC)), + // This makes the visual density adapt to the platform that you run + // the app on. For desktop platforms, the controls will be smaller and + // closer together (more dense) than on mobile platforms. + visualDensity: VisualDensity.adaptivePlatformDensity, + backgroundColor: Colors.white), home: Material( child: UpdatePage.build( AuthWidget(TrackSessionRedirector(OrganizationsPage())))), diff --git a/lib/views/routes/item.dart b/lib/views/routes/item.dart index 19874fb..7d26946 100644 --- a/lib/views/routes/item.dart +++ b/lib/views/routes/item.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart' hide Route; import 'package:strollplanner_tracker/config.dart'; +import 'package:strollplanner_tracker/views/routes/route_status.dart'; import 'package:strollplanner_tracker/views/track.dart'; import 'package:strollplanner_tracker/models/route.dart'; @@ -17,6 +18,71 @@ String formatDistance(double d) { return "${d.toStringAsFixed(precision)} m"; } +class RouteItemTile extends StatelessWidget { + final String orgId; + final Route route; + + const RouteItemTile({Key key, this.orgId, this.route}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + ShaderMask( + blendMode: BlendMode.dstOut, + shaderCallback: (Rect bounds) { + return LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + stops: [0.4, 1.0], + colors: [Colors.transparent, Colors.white]) + .createShader(bounds); + }, + child: Image.network( + "${AppConfig.of(context).apiBaseUrl}/orgs/$orgId/routes/${route.id}/static/simplified/300/300", + width: 150, + height: 150, + ), + ), + Positioned.fill( + left: 100, + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Text(route.title, + maxLines: 3, + overflow: TextOverflow.ellipsis, + textDirection: TextDirection.rtl, + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 20)), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + RouteStatus(route: this.route), + SizedBox(width: 10), + Text(formatDistance(route.totalLength)) + ], + ) + ], + ), + )) + ], + ) + ], + ); + } +} + class RouteItem extends StatelessWidget { final String orgId; final Route route; @@ -39,63 +105,7 @@ class RouteItem extends StatelessWidget { color: Colors.white, ), child: Stack(children: [ - Container( - child: Column(children: [ - Container( - child: Text(route.title, - style: Theme.of(context).textTheme.headline6), - padding: EdgeInsets.all(10)), - Row( - children: [ - Image.network( - "${AppConfig.of(context).apiBaseUrl}/orgs/$orgId/routes/${route.id}/static/simplified/300/300", - width: 150, - ), - Container( - child: Column( - children: [ - Text(formatDistance(route.totalLength)), - SizedBox(height: 20), - route.published - ? route.canceled - ? Chip( - label: Text( - "Canceled", - style: Theme.of(context) - .textTheme - .bodyText1 - .copyWith(color: Colors.white), - ), - backgroundColor: Colors.red, - ) - : Chip( - label: Text( - "Published", - style: Theme.of(context) - .textTheme - .bodyText1 - .copyWith(color: Colors.white), - ), - backgroundColor: Colors.green, - ) - : Chip( - label: Text( - "Not Published", - style: Theme.of(context) - .textTheme - .bodyText1 - .copyWith(color: Colors.white), - ), - backgroundColor: Colors.grey[500], - ), - ], - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - ), - padding: EdgeInsets.all(10)) - ], - ) - ], crossAxisAlignment: CrossAxisAlignment.stretch)), + RouteItemTile(orgId: orgId, route: route), Positioned.fill( child: Material( color: Colors.transparent, diff --git a/lib/views/routes/route_status.dart b/lib/views/routes/route_status.dart new file mode 100644 index 0000000..6541d37 --- /dev/null +++ b/lib/views/routes/route_status.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart' hide Route; +import 'package:strollplanner_tracker/models/route.dart'; + +class RouteStatus extends StatelessWidget { + final Route route; + + const RouteStatus({Key key, this.route}) : super(key: key); + + @override + Widget build(BuildContext context) { + if (route.published) { + if (route.canceled) { + return Icon(Icons.close_rounded, color: Colors.red); + } + + return Container(); + } + + return Icon(Icons.hourglass_bottom_outlined, color: Colors.grey[500]); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 1c085de..774a1d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,6 +60,7 @@ flutter: assets: - assets/icon.png + - assets/logo.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware.