diff --git a/mobile-app/lib/data/warband_roster.dart b/mobile-app/lib/data/warband_roster.dart index 013d421..b6e25b7 100644 --- a/mobile-app/lib/data/warband_roster.dart +++ b/mobile-app/lib/data/warband_roster.dart @@ -123,8 +123,11 @@ class Hero extends Unit { @JsonKey(defaultValue: 0) final int warbandaddition; + @JsonKey(defaultValue: false, name: 'hiredsword') + final bool hiredSword; + Hero(this.stats, this.skilllists, this.weapons, this.armour, this.rules, - this.warbandaddition, this.header) { + this.warbandaddition, this.header, this.hiredSword) { this.name = this.header['name']; this.type = this.header['type']; this.experience = int.tryParse(this.header['experience']) ?? 0; diff --git a/mobile-app/lib/data/warband_roster.g.dart b/mobile-app/lib/data/warband_roster.g.dart index cee83e3..5ad1616 100644 --- a/mobile-app/lib/data/warband_roster.g.dart +++ b/mobile-app/lib/data/warband_roster.g.dart @@ -26,6 +26,7 @@ Hero _$HeroFromJson(Map json) { Unit._splitListFromJson(json['rules'] as String), json['warbandaddition'] as int ?? 0, Hero._heroHeaderFromJson(json['hero'] as String), + json['hiredsword'] as bool ?? false, ); } diff --git a/mobile-app/lib/main.dart b/mobile-app/lib/main.dart index 6ff7d9e..097d42a 100644 --- a/mobile-app/lib/main.dart +++ b/mobile-app/lib/main.dart @@ -3,6 +3,7 @@ import 'package:preferences/preferences.dart'; import 'package:provider/provider.dart'; import 'package:toolheim/data/github_adapter.dart'; import 'package:toolheim/screens/settings_screen.dart'; +import 'package:toolheim/screens/unit_screen.dart'; import 'package:toolheim/screens/warband_roster_screen.dart'; void main() async { @@ -24,7 +25,8 @@ class Toolheim extends StatelessWidget { initialRoute: '/', routes: { '/': (context) => WarbandRosterScreen(), - '/settings': (context) => SettingsScreen() + '/unit': (context) => UnitScreen(), + '/settings': (context) => SettingsScreen(), }, ), ); diff --git a/mobile-app/lib/screens/settings_screen.dart b/mobile-app/lib/screens/settings_screen.dart index cfb7ea4..a5ec27a 100644 --- a/mobile-app/lib/screens/settings_screen.dart +++ b/mobile-app/lib/screens/settings_screen.dart @@ -22,41 +22,14 @@ class SettingsScreen extends StatelessWidget { PreferenceText( 'Search the given GitHub repository for valid Warband files (ending with .warband.yml). This step can be done at any time.'), FlatButton( - onPressed: () { - github.search(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text('Search Warbands ...'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Checking the GitHub repository for suitable files. This can take a while.'), - SizedBox( - height: 50, - ), - if (github.isSyncInProgress) - CircularProgressIndicator(), - if (github.syncErrors.length > 0) - buildSyncErrors(context), - ]), - actions: [ - if (!github.isSyncInProgress) - FlatButton( - child: Text('Close', - style: TextStyle(color: Colors.blue)), - onPressed: () { - if (github.syncErrors.length > 0) { - Navigator.pop(context); - } else { - Navigator.popAndPushNamed(context, '/'); - } - }, - ) - ]); - }); + onPressed: () async { + showSyncWaitingDialog(context); + await github.search(); + + Navigator.of(context, rootNavigator: true).pop(); + if (github.syncErrors.length > 0) { + showErrorDialog(context, github); + } }, child: Text('Start search', style: TextStyle(color: Colors.blue))), @@ -74,4 +47,48 @@ class SettingsScreen extends StatelessWidget { Text(error, style: TextStyle(color: Colors.red)) ]); } + + void showErrorDialog(context, github) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('Errors'), + content: + Column(mainAxisSize: MainAxisSize.min, children: [ + Text("We've got some errors while searching for warbands"), + SizedBox( + height: 50, + ), + buildSyncErrors(context), + ]), + actions: [ + FlatButton( + child: Text('Close', style: TextStyle(color: Colors.blue)), + onPressed: () { + github.syncErrors.clear(); + Navigator.of(context, rootNavigator: true).pop(); + }, + ) + ]); + }); + } + + void showSyncWaitingDialog(context) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('Search warbands ...'), + content: Column(mainAxisSize: MainAxisSize.min, children: [ + Text( + 'Checking the GitHub repository for suitable files. This can take a while ...'), + SizedBox( + height: 50, + ), + CircularProgressIndicator(), + ]), + ); + }); + } } diff --git a/mobile-app/lib/screens/unit_screen.dart b/mobile-app/lib/screens/unit_screen.dart new file mode 100644 index 0000000..fc74afc --- /dev/null +++ b/mobile-app/lib/screens/unit_screen.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:toolheim/data/github_adapter.dart'; +import 'package:toolheim/data/warband_roster.dart' as roster; +import 'package:toolheim/widgets/stats_widget.dart'; + +class UnitScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + GitHubAdapter github = Provider.of(context); + + final roster.Hero hero = ModalRoute.of(context).settings.arguments; + + return Scaffold( + appBar: AppBar( + actions: [ + CircleAvatar( + child: Text(hero.experience.toString()), + backgroundColor: Colors.green, + foregroundColor: Colors.greenAccent, + ), + ], + title: Column( + children: [ + Text(hero.name), + Text( + hero.type, + textAlign: TextAlign.left, + style: TextStyle(fontSize: 12, fontWeight: FontWeight.normal), + ) + ], + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + )), + body: Column( + children: [StatsWidget(hero.stats)], + )); + } +} diff --git a/mobile-app/lib/screens/warband_roster_screen.dart b/mobile-app/lib/screens/warband_roster_screen.dart index c5ca1a5..e42eff7 100644 --- a/mobile-app/lib/screens/warband_roster_screen.dart +++ b/mobile-app/lib/screens/warband_roster_screen.dart @@ -1,7 +1,9 @@ +import 'package:badges/badges.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:toolheim/data/github_adapter.dart'; +import 'package:toolheim/widgets/stats_widget.dart'; import 'package:toolheim/widgets/warband_drawer_widget.dart'; class WarbandRosterScreen extends StatelessWidget { @@ -47,26 +49,83 @@ class WarbandRosterScreen extends StatelessWidget { child: Column(children: [ for (var hero in github.activeRoster.heros) ListTile( - title: Text(hero.name), - leading: CircleAvatar( - child: Text(hero.experience.toString()), - backgroundColor: Colors.green, - foregroundColor: Colors.greenAccent, + title: Padding( + padding: const EdgeInsets.only(bottom: 7), + child: Row(children: [ + Text(hero.name, + style: TextStyle( + fontWeight: hero.rules.contains('Leader') + ? FontWeight.bold + : FontWeight.normal)), + Text( + '(' + hero.type + ')', + style: TextStyle(fontSize: 10), + ) + ]), ), - subtitle: Text(hero.type), + leading: CircleAvatar( + child: Row(children: [ + Spacer(), + Text(hero.experience.toString(), + style: TextStyle(color: Colors.white)), + Text( + 'xp', + style: TextStyle(fontSize: 8), + ), + Spacer() + ]), + backgroundColor: hero.hiredSword ? Colors.black : Colors.green, + foregroundColor: + hero.hiredSword ? Colors.grey : Colors.greenAccent, + ), + subtitle: StatsWidget(hero.stats), + isThreeLine: true, + onTap: () { + //Navigator.pushNamed(context, '/unit', arguments: hero); + }, ), Divider(), for (var henchmenGroup in github.activeRoster.henchmenGroups) ListTile( - title: Text(henchmenGroup.name), - trailing: Chip(label: Text(henchmenGroup.number.toString() + 'x')), + title: Padding( + padding: const EdgeInsets.only(bottom: 7), + child: Row(children: [ + Text(henchmenGroup.name), + Text( + '(' + henchmenGroup.type + ')', + style: TextStyle(fontSize: 10), + ), + Spacer(), + Badge( + badgeColor: Colors.black12, + shape: BadgeShape.square, + borderRadius: 2, + badgeContent: Text(henchmenGroup.number.toString() + 'x', + style: TextStyle(color: Colors.white)), + ), + ]), + ), leading: CircleAvatar( - child: Text(henchmenGroup.experience.toString()), + child: Row(children: [ + Spacer(), + Text(henchmenGroup.experience.toString(), + style: TextStyle(color: Colors.white)), + Text( + 'xp', + style: TextStyle(fontSize: 8), + ), + Spacer() + ]), backgroundColor: Colors.orange, foregroundColor: Colors.white, ), - subtitle: Text(henchmenGroup.type), - ) + subtitle: StatsWidget(henchmenGroup.stats), + isThreeLine: true, + onTap: () { + //Navigator.pushNamed(context, '/unit', arguments: hero); + }, + ), + Divider() ])), ); } diff --git a/mobile-app/lib/widgets/stats_widget.dart b/mobile-app/lib/widgets/stats_widget.dart new file mode 100644 index 0000000..d5a5b33 --- /dev/null +++ b/mobile-app/lib/widgets/stats_widget.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:toolheim/data/warband_roster.dart'; + +class StatsWidget extends StatelessWidget { + Stats stats; + + @override + Widget build(BuildContext context) { + return GridView.count( + crossAxisCount: 10, + crossAxisSpacing: 0.0, + //padding: const EdgeInsets.all(10), + primary: false, + shrinkWrap: true, + children: [ + statsElement('M', stats.movement, + stats.movement > 3 ? (stats.movement > 5 ? 3 : 2) : 1), + statsElement('WS', stats.weaponSkill, + stats.weaponSkill > 3 ? (stats.weaponSkill > 5 ? 3 : 2) : 1), + statsElement( + 'BS', + stats.ballisticSkill, + stats.ballisticSkill > 3 + ? (stats.ballisticSkill > 5 ? 3 : 2) + : 1), + statsElement('S', stats.strength, + stats.strength > 3 ? (stats.strength > 5 ? 3 : 2) : 1), + statsElement('T', stats.toughtness, + stats.toughtness > 3 ? (stats.toughtness > 5 ? 3 : 2) : 1), + statsElement('W', stats.wounds, + stats.wounds > 1 ? (stats.wounds > 2 ? 3 : 2) : 1), + statsElement('I', stats.initiative, + stats.initiative > 3 ? (stats.initiative > 5 ? 3 : 2) : 1), + statsElement('A', stats.attacks, + stats.attacks > 1 ? (stats.attacks > 2 ? 3 : 2) : 1), + statsElement('Ld', stats.leadership, + stats.leadership > 7 ? (stats.leadership > 9 ? 3 : 2) : 1), + statsElement('Sv', stats.save, + stats.save > 0 ? (stats.leadership > 1 ? 3 : 2) : 0), + ]); + } + + StatsWidget(this.stats); + + Widget statsElement(stat, value, qualityFactor) { + TextStyle styles = TextStyle(fontSize: 14, fontWeight: FontWeight.normal); + String val = value.toString(); + + if (qualityFactor == 0) { + styles = styles.merge(TextStyle(color: Colors.black45)); + val = '-'; + } + + if (qualityFactor > 1) { + styles = styles + .merge(TextStyle(color: Colors.red, fontWeight: FontWeight.bold)); + } + + if (qualityFactor > 2) { + styles = styles.merge(TextStyle(color: Colors.purple)); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + stat, + style: TextStyle(fontSize: 9, color: Colors.grey), + ), + Text(val, style: styles) + ]); + } +}