Feature/basic app (#1)

Feature/Basic App (#1)

Basic App Structure Consists of Time Progress Dashboard, Time Progress Detail View and Time Progress Creator.
All of these have an AppDrawer with a Link To the Dashboard and all your Track Time Progresses, also an About Button.

Commits:
* Undetailed Commit more work
* Changed isEditing ? in Detail Screen and Extracted FAB row to widget
* Extracted Progress Detail Fab Row and Progress Detail select Date Btn to
widgets
* Create Progress Detail Widgets Folder
* Extracted Edit Dates Row Widget
* Extracted Functions from ui
* Made some fields private
* LoadTimerProgressList if unloaded function
* Created App Yes No Dialog Widget
* Using Yes No Dialog in Detail Screen
* Created TimeProgress Initial Default factory
* Renamed to Time Progress Tracker
* Added About Button in App Drawer
* Code cleanup
* Code clean up and fixed Bug with null as string in Repository

Signed-off-by Andreas Fahrecker <AndreasFahrecker@gmail.com>
This commit is contained in:
Andreas Fahrecker
2020-11-20 01:17:17 +01:00
committed by GitHub
parent 976fbec455
commit f013c0de65
27 changed files with 984 additions and 283 deletions

View File

@ -0,0 +1,110 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'package:redux/redux.dart';
import 'package:time_progress_tracker/actions/actions.dart';
import 'package:time_progress_tracker/app.dart';
import 'package:time_progress_tracker/models/app_state.dart';
import 'package:time_progress_tracker/models/time_progress.dart';
import 'package:time_progress_tracker/screens/progress_dashboard_screen.dart';
import 'package:time_progress_tracker/screens/progress_detail_screen.dart';
class AppDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Drawer(
child: StoreConnector(
converter: _ViewModel.fromStore,
onInit: loadTimeProgressListIfUnloaded,
builder: (context, _ViewModel vm) {
List<Widget> drawerTileList = List<Widget>();
drawerTileList.add(DrawerHeader(
child: Text(TimeProgressTrackerApp.name),
decoration: BoxDecoration(color: Colors.blue),
margin: EdgeInsets.zero,
));
drawerTileList.add(Container(
color: Colors.lightBlue,
margin: EdgeInsets.only(bottom: 8),
child: ListTile(
title: Text(ProgressDashboardScreen.title),
trailing: Icon(Icons.dashboard),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, ProgressDashboardScreen.routeName);
},
),
));
if (vm.timeProgressList.length > 0) {
for (TimeProgress tp in vm.timeProgressList) {
drawerTileList.add(ListTile(
title: Text(tp.name),
trailing: CircularPercentIndicator(
percent: tp.percentDone(),
radius: 40,
progressColor: Colors.green,
backgroundColor: Colors.red,
center: FittedBox(
fit: BoxFit.scaleDown,
child:
Text((tp.percentDone() * 100).floor().toString() + "%"),
),
),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(
context,
ProgressDetailScreen.routeName,
arguments: ProgressDetailScreenArguments(tp.id),
);
},
));
if (vm.timeProgressList.last != tp) {
drawerTileList.add(Divider(
color: Colors.black12,
));
}
}
} else {
drawerTileList.add(ListTile(
title: Text("You don't have any tracked time progress."),
));
}
drawerTileList.add(Divider(
color: Colors.black38,
));
drawerTileList.add(Container(
margin: EdgeInsets.only(bottom: 8),
child: ListTile(
title: Text("About"),
onTap: () {
showAboutDialog(
context: context,
applicationName: TimeProgressTrackerApp.name,
applicationVersion: ' Version 0.0.1',
applicationLegalese: '\u00a9Andreas Fahrecker 2020'
);
},
),
));
return ListView(
children: drawerTileList,
);
},
),
);
}
}
class _ViewModel {
final List<TimeProgress> timeProgressList;
_ViewModel({@required this.timeProgressList});
static _ViewModel fromStore(Store<AppState> store) {
return _ViewModel(
timeProgressList: store.state.timeProgressList,
);
}
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
class AppYesNoDialog extends StatelessWidget {
final String titleText;
final String contentText;
final void Function() onYesPressed;
final void Function() onNoPressed;
AppYesNoDialog({
Key key,
@required this.titleText,
@required this.contentText,
@required this.onYesPressed,
@required this.onNoPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(titleText),
content: Text(contentText),
actions: <Widget>[
FlatButton(
child: Text("Yes"),
onPressed: onYesPressed,
),
FlatButton(
child: Text("No"),
onPressed: onNoPressed,
)
],
);
}
}

View File

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
class ProgressDetailCircularPercent extends StatelessWidget {
final double percentDone;
ProgressDetailCircularPercent({Key key, @required this.percentDone})
: super(key: key);
@override
Widget build(BuildContext context) {
return CircularPercentIndicator(
radius: 100,
lineWidth: 10,
percent: percentDone,
progressColor: Colors.green,
backgroundColor: Colors.red,
center: Text("${(percentDone * 100).floor()} %"),
);
}
}

View File

@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:time_progress_tracker/widgets/progress_detail_widgets/progress_detail_select_date_btn_widget.dart';
class ProgressDetailEditDatesRow extends StatelessWidget {
final DateTime startTime;
final DateTime endTime;
final void Function(DateTime) onStartTimeChanged;
final void Function(DateTime) onEndTimeChanged;
ProgressDetailEditDatesRow({
Key key,
@required this.startTime,
@required this.endTime,
@required this.onStartTimeChanged,
@required this.onEndTimeChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
flex: 5,
child: ProgressDetailSelectDateButton(
leadingString: "Start Date:",
selectedDate: startTime,
onDateSelected: onStartTimeChanged,
),
),
Spacer(
flex: 1,
),
Expanded(
flex: 5,
child: ProgressDetailSelectDateButton(
leadingString: "End Date:",
selectedDate: endTime,
onDateSelected: onEndTimeChanged,
),
)
],
);
}
}

View File

@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
class ProgressDetailFabEditingRow extends StatelessWidget {
final void Function() onSave;
final void Function() onCancelEdit;
ProgressDetailFabEditingRow({
Key key,
@required this.onSave,
@required this.onCancelEdit,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: FloatingActionButton(
heroTag: "saveEditedTimeProgressBTN",
child: Icon(Icons.save),
backgroundColor: Colors.green,
onPressed: this.onSave,
),
),
Expanded(
child: FloatingActionButton(
heroTag: "cancelEditTimeProgressBTN",
child: Icon(Icons.cancel),
backgroundColor: Colors.red,
onPressed: this.onCancelEdit,
))
],
);
}
}

View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
class ProgressDetailFabRow extends StatelessWidget {
final void Function() onEdit;
final void Function() onDelete;
ProgressDetailFabRow(
{Key key, @required this.onEdit, @required this.onDelete})
: super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: FloatingActionButton(
heroTag: "editTimeProgressBTN",
child: Icon(Icons.edit),
onPressed: onEdit,
),
),
Expanded(
child: FloatingActionButton(
heroTag: "deleteTimeProgressBTN",
child: Icon(Icons.delete),
backgroundColor: Colors.red,
onPressed: onDelete,
),
)
],
);
}
}

View File

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:time_progress_tracker/models/time_progress.dart';
class ProgressDetailLinearPercent extends StatelessWidget {
final TimeProgress timeProgress;
ProgressDetailLinearPercent({Key key, @required this.timeProgress})
: super(key: key);
@override
Widget build(BuildContext context) {
return LinearPercentIndicator(
padding: EdgeInsets.symmetric(horizontal: 15),
percent: this.timeProgress.percentDone(),
leading: Text("${this.timeProgress.daysBehind()} Days"),
center: Text("${(this.timeProgress.percentDone() * 100).floor()} %"),
trailing: Text("${this.timeProgress.daysLeft()} Days"),
progressColor: Colors.green,
backgroundColor: Colors.red,
lineHeight: 25,
);
}
}

View File

@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
class ProgressDetailSelectDateButton extends StatelessWidget {
final String leadingString;
final DateTime selectedDate;
final void Function(DateTime) onDateSelected;
ProgressDetailSelectDateButton({
Key key,
@required this.leadingString,
@required this.selectedDate,
@required this.onDateSelected,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FlatButton(
color: Colors.blue,
child: Text(
"$leadingString ${selectedDate.toLocal().toString().split(" ")[0]}"),
onPressed: () async {
DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(selectedDate.year - 5),
lastDate: DateTime(selectedDate.year + 5),
);
onDateSelected(picked);
},
);
}
}