Feature/code cleanup (#9)
* Implemented hasSettingsLoaded reducer * Added Padding to Progress List View * Created Settings and Time Progress List Store Connector * Rewritten Home Active Tab * Fixed missing onTap in Progress List Tile * Started using new Store Connectors in Inactive and Settings Tab * Created Time Progress Store Connector * Rewritten ProgressDetailScreen with new Store Connectors * Rewritten DatePickerBtn with TextButton * Deleted unused widget * Changed Foreground Color behaviour in ColorPicker BTN * Created Select Duration Button * Rewritten Duration Setting Widget * Updated Version Number Signed-off-by: Andreas Fahrecker <AndreasFahrecker@gmail.com>
This commit is contained in:
parent
fc35476503
commit
40bdcc44f9
17
lib/helper_functions.dart
Normal file
17
lib/helper_functions.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
|
|
||||||
|
TimeProgress selectProgressById(List<TimeProgress> tpList, String id) =>
|
||||||
|
tpList.firstWhere((tp) => tp.id == id, orElse: null);
|
||||||
|
|
||||||
|
List<TimeProgress> selectActiveProgresses(List<TimeProgress> tpList) =>
|
||||||
|
tpList.where((tp) => tp.hasStarted() && !tp.hasEnded()).toList();
|
||||||
|
|
||||||
|
List<TimeProgress> selectInactiveProgresses(List<TimeProgress> tpList) =>
|
||||||
|
tpList.where((tp) => !tp.hasStarted() || tp.hasEnded()).toList();
|
||||||
|
|
||||||
|
bool useBrightBackground(Color bC) {
|
||||||
|
double yiq = ((bC.red * 299) + (bC.green * 587) + (bC.blue * 114)) / 1000;
|
||||||
|
return yiq >= 186 || (bC.red == 0 && bC.green == 0 && bC.blue == 0);
|
||||||
|
}
|
@ -7,7 +7,10 @@ import 'package:time_progress_tracker/reducers/time_progress_list_reducer.dart';
|
|||||||
|
|
||||||
AppState appStateReducer(AppState state, dynamic action) {
|
AppState appStateReducer(AppState state, dynamic action) {
|
||||||
return AppState(
|
return AppState(
|
||||||
hasProgressesLoaded: hasLoadedReducer(state.hasProgressesLoaded, action),
|
hasSettingsLoaded:
|
||||||
|
hasSettingsLoadedReducer(state.hasSettingsLoaded, action),
|
||||||
|
hasProgressesLoaded:
|
||||||
|
hasProgressesLoadedReducer(state.hasProgressesLoaded, action),
|
||||||
timeProgressList: timeProgressListReducer(state.timeProgressList, action),
|
timeProgressList: timeProgressListReducer(state.timeProgressList, action),
|
||||||
appSettings: appSettingsReducers(state.appSettings, action),
|
appSettings: appSettingsReducers(state.appSettings, action),
|
||||||
);
|
);
|
||||||
|
@ -1,15 +1,28 @@
|
|||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
import 'package:time_progress_tracker/actions/actions.dart';
|
import 'package:time_progress_tracker/actions/actions.dart';
|
||||||
|
|
||||||
final hasLoadedReducer = combineReducers<bool>([
|
final hasProgressesLoadedReducer = combineReducers<bool>([
|
||||||
TypedReducer<bool, TimeProgressListLoadedAction>(_setLoaded),
|
TypedReducer<bool, TimeProgressListLoadedAction>(_setProgressesLoaded),
|
||||||
TypedReducer<bool, TimeProgressListNotLoadedAction>(_setUnloaded)
|
TypedReducer<bool, TimeProgressListNotLoadedAction>(_setProgressesUnloaded)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
bool _setLoaded(bool hasLoaded, TimeProgressListLoadedAction action) {
|
bool _setProgressesLoaded(bool hasLoaded, TimeProgressListLoadedAction action) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _setUnloaded(bool hasLoaded, TimeProgressListNotLoadedAction action) {
|
bool _setProgressesUnloaded(bool hasLoaded, TimeProgressListNotLoadedAction action) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final hasSettingsLoadedReducer = combineReducers<bool>([
|
||||||
|
TypedReducer<bool, AppSettingsLoadedActions>(_setSettingsLoaded),
|
||||||
|
TypedReducer<bool, AppSettingsNotLoadedAction>(_setSettingsUnloaded)
|
||||||
|
]);
|
||||||
|
|
||||||
|
bool _setSettingsLoaded(bool hasLoaded, AppSettingsLoadedActions action) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _setSettingsUnloaded(bool hasLoaded, AppSettingsNotLoadedAction action) {
|
||||||
|
return false;
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:time_progress_tracker/screens/progress_creation_screen.dart';
|
import 'package:time_progress_tracker/widgets/buttons/create_progress_button.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/home_bottom_navbar.dart';
|
import 'package:time_progress_tracker/widgets/home/home_bottom_navbar.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/tabs/home_active_progresses_tab.dart';
|
import 'package:time_progress_tracker/widgets/home/tabs/home_active_progresses_tab.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/tabs/home_inactive_progresses_tab.dart';
|
import 'package:time_progress_tracker/widgets/home/tabs/home_inactive_progresses_tab.dart';
|
||||||
@ -37,15 +37,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
),
|
),
|
||||||
body: _children[_currentIndex],
|
body: _children[_currentIndex],
|
||||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||||
floatingActionButton: _currentIndex != 2
|
floatingActionButton: _currentIndex != 2 ? CreateProgressButton() : null,
|
||||||
? FloatingActionButton(
|
|
||||||
heroTag: "createProgressBTN",
|
|
||||||
child: Icon(Icons.add),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pushNamed(context, ProgressCreationScreen.routeName);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
bottomNavigationBar: HomeBottomNavBar(
|
bottomNavigationBar: HomeBottomNavBar(
|
||||||
currentIndex: _currentIndex,
|
currentIndex: _currentIndex,
|
||||||
onTap: onBottomTabTapped,
|
onTap: onBottomTabTapped,
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
|
||||||
import 'package:redux/redux.dart';
|
|
||||||
import 'package:time_progress_tracker/actions/actions.dart';
|
|
||||||
import 'package:time_progress_tracker/models/app_settings.dart';
|
|
||||||
import 'package:time_progress_tracker/models/app_state.dart';
|
|
||||||
import 'package:time_progress_tracker/models/time_progress.dart';
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
import 'package:time_progress_tracker/screens/home_screen.dart';
|
import 'package:time_progress_tracker/screens/home_screen.dart';
|
||||||
import 'package:time_progress_tracker/selectors/time_progress_selectors.dart';
|
|
||||||
import 'package:time_progress_tracker/widgets/detail_screen_floating_action_buttons.dart';
|
import 'package:time_progress_tracker/widgets/detail_screen_floating_action_buttons.dart';
|
||||||
import 'package:time_progress_tracker/widgets/progress_editor_widget.dart';
|
import 'package:time_progress_tracker/widgets/progress_editor_widget.dart';
|
||||||
import 'package:time_progress_tracker/widgets/progress_view_widget.dart';
|
import 'package:time_progress_tracker/widgets/progress_view_widget.dart';
|
||||||
|
import 'package:time_progress_tracker/widgets/store_connectors/settings_store_connector.dart';
|
||||||
|
import 'package:time_progress_tracker/widgets/store_connectors/time_progress_store_connector.dart';
|
||||||
|
|
||||||
class ProgressDetailScreenArguments {
|
class ProgressDetailScreenArguments {
|
||||||
final String id;
|
final String id;
|
||||||
@ -31,6 +27,13 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
|
|||||||
bool _editMode = false, _isEditedProgressValid = false;
|
bool _editMode = false, _isEditedProgressValid = false;
|
||||||
TimeProgress _editedProgress, _originalProgress;
|
TimeProgress _editedProgress, _originalProgress;
|
||||||
|
|
||||||
|
void _initEditedProgress(TimeProgress tp) {
|
||||||
|
if (_editedProgress == null) {
|
||||||
|
_editedProgress = tp;
|
||||||
|
_originalProgress = tp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _onEditedProgressChanged(
|
void _onEditedProgressChanged(
|
||||||
TimeProgress newProgress, bool isNewProgressValid) {
|
TimeProgress newProgress, bool isNewProgressValid) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -52,87 +55,75 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Widget> _renderColumnChildren(
|
||||||
|
SettingsViewModel settingsVm, TimeProgressViewModel tpVm) {
|
||||||
|
List<Widget> columnChildren = [
|
||||||
|
Expanded(
|
||||||
|
child: ProgressViewWidget(
|
||||||
|
timeProgress: _editMode ? _editedProgress : tpVm.tp,
|
||||||
|
doneColor: settingsVm.appSettings.doneColor,
|
||||||
|
leftColor: settingsVm.appSettings.leftColor,
|
||||||
|
))
|
||||||
|
];
|
||||||
|
if (_editMode)
|
||||||
|
columnChildren.add(Expanded(
|
||||||
|
child: ProgressEditorWidget(
|
||||||
|
timeProgress: _editedProgress,
|
||||||
|
onTimeProgressChanged: _onEditedProgressChanged,
|
||||||
|
)));
|
||||||
|
return columnChildren;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ProgressDetailScreenArguments args =
|
final ProgressDetailScreenArguments args =
|
||||||
ModalRoute.of(context).settings.arguments;
|
ModalRoute.of(context).settings.arguments;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(ProgressDetailScreen.title),
|
title: Text(ProgressDetailScreen.title),
|
||||||
),
|
),
|
||||||
body: Container(
|
body: SettingsStoreConnector(
|
||||||
margin: EdgeInsets.all(8),
|
loadedBuilder: (context, settingsVm) {
|
||||||
child: StoreConnector(
|
return TimeProgressStoreConnector(
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
timeProgressId: args.id,
|
||||||
converter: (store) => timeProgressByIdSelector(store.state, args.id),
|
loadedBuilder: (context, tpVm) {
|
||||||
builder: (BuildContext context, TimeProgress timeProgress) {
|
_initEditedProgress(tpVm.tp);
|
||||||
if (timeProgress == null) //+++++Time Progress Not Found Error+++++
|
return Container(
|
||||||
return Center(
|
margin: EdgeInsets.all(8),
|
||||||
child: Text("Error Invalid Time Progress"),
|
child: Column(
|
||||||
);
|
children: _renderColumnChildren(settingsVm, tpVm),
|
||||||
if (_editedProgress == null) {
|
));
|
||||||
_editedProgress = timeProgress;
|
},
|
||||||
_originalProgress = timeProgress;
|
);
|
||||||
} // initialize _editedProgress
|
},
|
||||||
|
|
||||||
List<Widget> columnChildren = [
|
|
||||||
Expanded(
|
|
||||||
child: StoreConnector<AppState, AppSettings>(
|
|
||||||
onInit: loadSettingsIfUnloaded,
|
|
||||||
converter: (store) => appSettingsSelector(store.state),
|
|
||||||
builder: (BuildContext context, AppSettings settings) {
|
|
||||||
return ProgressViewWidget(
|
|
||||||
timeProgress: _editMode ? _editedProgress : timeProgress,
|
|
||||||
doneColor: settings.doneColor,
|
|
||||||
leftColor: settings.leftColor,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
];
|
|
||||||
if (_editMode)
|
|
||||||
columnChildren.add(Expanded(
|
|
||||||
child: ProgressEditorWidget(
|
|
||||||
timeProgress: _editedProgress,
|
|
||||||
onTimeProgressChanged: _onEditedProgressChanged,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
children: columnChildren,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
||||||
floatingActionButton: StoreConnector(
|
floatingActionButton: TimeProgressStoreConnector(
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
timeProgressId: args.id,
|
||||||
converter: (store) => timeProgressByIdSelector(store.state, args.id),
|
loadedBuilder: (context, tpVm) {
|
||||||
builder: (BuildContext context, TimeProgress timeProgress) {
|
void _saveEditedProgress() {
|
||||||
final Store<AppState> store = StoreProvider.of<AppState>(context);
|
tpVm.updateTimeProgress(_editedProgress);
|
||||||
|
_switchEditMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
void _saveEditedProgress() {
|
void _deleteTimeProgress() {
|
||||||
store
|
tpVm.deleteTimeProgress();
|
||||||
.dispatch(UpdateTimeProgressAction(args.id, _editedProgress));
|
Navigator.popUntil(
|
||||||
_switchEditMode(false);
|
context, ModalRoute.withName(HomeScreen.routeName));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deleteTimeProgress() {
|
return DetailScreenFloatingActionButtons(
|
||||||
store.dispatch(DeleteTimeProgressAction(args.id));
|
editMode: _editMode,
|
||||||
Navigator.popUntil(
|
originalProgress: tpVm.tp,
|
||||||
context, ModalRoute.withName(HomeScreen.routeName));
|
editedProgress: _editedProgress,
|
||||||
}
|
isEditedProgressValid: _isEditedProgressValid,
|
||||||
|
onEditProgress: () => _switchEditMode(true),
|
||||||
return DetailScreenFloatingActionButtons(
|
onSaveEditedProgress: _saveEditedProgress,
|
||||||
editMode: _editMode,
|
onCancelEditProgress: _cancelEditMode,
|
||||||
originalProgress: timeProgress,
|
onDeleteProgress: _deleteTimeProgress);
|
||||||
editedProgress: _editedProgress,
|
},
|
||||||
isEditedProgressValid: _isEditedProgressValid,
|
),
|
||||||
onEditProgress: () => _switchEditMode(true),
|
|
||||||
onSaveEditedProgress: _saveEditedProgress,
|
|
||||||
onCancelEditProgress: _cancelEditMode,
|
|
||||||
onDeleteProgress: _deleteTimeProgress);
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
|
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
|
||||||
|
import 'package:time_progress_tracker/helper_functions.dart';
|
||||||
|
|
||||||
class ColorPickerButton extends StatelessWidget {
|
class ColorPickerButton extends StatelessWidget {
|
||||||
final String title, dialogTitle;
|
final String title, dialogTitle;
|
||||||
@ -15,13 +16,7 @@ class ColorPickerButton extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Color getBtnPrimaryColor() => Color.fromARGB(
|
ThemeData appTheme = Theme.of(context);
|
||||||
selectedColor.alpha,
|
|
||||||
selectedColor.alpha - selectedColor.red,
|
|
||||||
selectedColor.alpha - selectedColor.green,
|
|
||||||
selectedColor.alpha - selectedColor.blue,
|
|
||||||
);
|
|
||||||
|
|
||||||
return TextButton(
|
return TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
@ -41,7 +36,9 @@ class ColorPickerButton extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Text(title),
|
child: Text(title),
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
primary: getBtnPrimaryColor(),
|
primary: useBrightBackground(selectedColor)
|
||||||
|
? appTheme.primaryTextTheme.button.color
|
||||||
|
: appTheme.textTheme.button.color,
|
||||||
backgroundColor: selectedColor,
|
backgroundColor: selectedColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
18
lib/widgets/buttons/create_progress_button.dart
Normal file
18
lib/widgets/buttons/create_progress_button.dart
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:time_progress_tracker/screens/progress_creation_screen.dart';
|
||||||
|
|
||||||
|
class CreateProgressButton extends StatelessWidget {
|
||||||
|
final String _heroTag = "createProgressBTN";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
void _onButtonPressed() =>
|
||||||
|
Navigator.pushNamed(context, ProgressCreationScreen.routeName);
|
||||||
|
|
||||||
|
return FloatingActionButton(
|
||||||
|
heroTag: _heroTag,
|
||||||
|
child: Icon(Icons.add),
|
||||||
|
onPressed: _onButtonPressed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -11,21 +11,26 @@ class DatePickerBtn extends StatelessWidget {
|
|||||||
@required this.onDatePicked,
|
@required this.onDatePicked,
|
||||||
}) : super();
|
}) : super();
|
||||||
|
|
||||||
|
void _onButtonPressed(BuildContext context) async {
|
||||||
|
onDatePicked(await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: pickedDate,
|
||||||
|
firstDate: DateTime(1900),
|
||||||
|
lastDate: DateTime(2100),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
ThemeData appTheme = Theme.of(context);
|
ThemeData appTheme = Theme.of(context);
|
||||||
return FlatButton(
|
return TextButton(
|
||||||
onPressed: () async {
|
onPressed: () => _onButtonPressed(context),
|
||||||
onDatePicked(await showDatePicker(
|
|
||||||
context: context,
|
|
||||||
initialDate: pickedDate,
|
|
||||||
firstDate: DateTime(1900),
|
|
||||||
lastDate: DateTime(2100),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
child: Text(
|
child: Text(
|
||||||
"$leadingString ${pickedDate.toLocal().toString().split(" ")[0]}"),
|
"$leadingString ${pickedDate.toLocal().toString().split(" ")[0]}"),
|
||||||
color: appTheme.accentColor,
|
style: TextButton.styleFrom(
|
||||||
|
primary: appTheme.primaryTextTheme.button.color,
|
||||||
|
backgroundColor: appTheme.accentColor,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
47
lib/widgets/buttons/select_duration_btn.dart
Normal file
47
lib/widgets/buttons/select_duration_btn.dart
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_picker/flutter_picker.dart';
|
||||||
|
|
||||||
|
class SelectDurationBtn extends StatelessWidget {
|
||||||
|
final Duration duration;
|
||||||
|
final void Function(Duration) updateDuration;
|
||||||
|
|
||||||
|
SelectDurationBtn({
|
||||||
|
@required this.duration,
|
||||||
|
@required this.updateDuration,
|
||||||
|
});
|
||||||
|
|
||||||
|
void _onPickerConfirm(Picker picker, List<int> values) {
|
||||||
|
int years = values[0], months = values[1], days = values[2];
|
||||||
|
days = (years * 365) + (months * 31) + days;
|
||||||
|
Duration newDuration = Duration(days: days);
|
||||||
|
updateDuration(newDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onButtonPressed(BuildContext context, ThemeData appTheme) => Picker(
|
||||||
|
adapter: NumberPickerAdapter(data: [
|
||||||
|
const NumberPickerColumn(begin: 0, end: 999, suffix: Text(" Y")),
|
||||||
|
const NumberPickerColumn(begin: 0, end: 11, suffix: Text(" M")),
|
||||||
|
const NumberPickerColumn(begin: 0, end: 31, suffix: Text(" D")),
|
||||||
|
]),
|
||||||
|
hideHeader: false,
|
||||||
|
title: const Text("Default Duration"),
|
||||||
|
selectedTextStyle: TextStyle(color: appTheme.accentColor),
|
||||||
|
onConfirm: _onPickerConfirm)
|
||||||
|
.showModal(context);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ThemeData appTheme = Theme.of(context);
|
||||||
|
|
||||||
|
int years = duration.inDays ~/ 365;
|
||||||
|
int months = (duration.inDays - (365 * years)) ~/ 30;
|
||||||
|
int days = duration.inDays - (365 * years) - (30 * months);
|
||||||
|
return TextButton(
|
||||||
|
onPressed: () => _onButtonPressed(context, appTheme),
|
||||||
|
child: Text("$years Years $months Months $days Days"),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
primary: appTheme.primaryTextTheme.button.color,
|
||||||
|
backgroundColor: appTheme.accentColor,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:time_progress_tracker/models/time_progress.dart';
|
|
||||||
import 'package:time_progress_tracker/widgets/progress_list_view/progress_list_tile.dart';
|
|
||||||
|
|
||||||
class HomeProgressListTile extends StatelessWidget {
|
|
||||||
final TimeProgress timeProgress;
|
|
||||||
final Color doneColor;
|
|
||||||
final Color leftColor;
|
|
||||||
|
|
||||||
HomeProgressListTile({
|
|
||||||
@required this.timeProgress,
|
|
||||||
@required this.doneColor,
|
|
||||||
@required this.leftColor,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Card(
|
|
||||||
child: ProgressListTile(
|
|
||||||
timeProgress: timeProgress,
|
|
||||||
doneColor: doneColor,
|
|
||||||
leftColor: leftColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,51 +1,32 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:time_progress_tracker/helper_functions.dart';
|
||||||
import 'package:time_progress_tracker/actions/actions.dart';
|
|
||||||
import 'package:time_progress_tracker/models/app_settings.dart';
|
|
||||||
import 'package:time_progress_tracker/models/app_state.dart';
|
|
||||||
import 'package:time_progress_tracker/models/time_progress.dart';
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
import 'package:time_progress_tracker/selectors/time_progress_selectors.dart';
|
import 'package:time_progress_tracker/widgets/progress_list_view/progress_list_view.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/home_progress_list_tile.dart';
|
import 'package:time_progress_tracker/widgets/store_connectors/settings_store_connector.dart';
|
||||||
|
import 'package:time_progress_tracker/widgets/store_connectors/time_progress_list_store_connector.dart';
|
||||||
|
|
||||||
class HomeActiveProgressesTab extends StatelessWidget {
|
class HomeActiveProgressesTab extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StoreConnector(
|
return SettingsStoreConnector(
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
loadedBuilder: (context, settingsVm) {
|
||||||
converter: (store) => store.state.hasProgressesLoaded,
|
return TimeProgressListStoreConnector(
|
||||||
builder: (context, hasLoaded) {
|
loadedBuilder: (context, tpListVm) {
|
||||||
if (!(hasLoaded as bool))
|
List<TimeProgress> activeTpList =
|
||||||
return Center(
|
selectActiveProgresses(tpListVm.tpList);
|
||||||
child: CircularProgressIndicator(),
|
if (activeTpList.length < 1)
|
||||||
);
|
return Container(
|
||||||
return StoreConnector<AppState, AppSettings>(
|
padding: EdgeInsets.all(16),
|
||||||
onInit: loadSettingsIfUnloaded,
|
child: Center(
|
||||||
converter: (store) => appSettingsSelector(store.state),
|
child: Text(
|
||||||
builder: (context, AppSettings settings) {
|
"You don't have any active time progress, that are tracked."),
|
||||||
if (settings == null)
|
),
|
||||||
return Center(child: CircularProgressIndicator());
|
);
|
||||||
return StoreConnector<AppState, List<TimeProgress>>(
|
|
||||||
converter: (store) => activeTimeProgressesSelector(store.state),
|
return ProgressListView(
|
||||||
builder: (context, List<TimeProgress> timeProgresses) {
|
timeProgressList: activeTpList,
|
||||||
if (timeProgresses.length < 1)
|
doneColor: settingsVm.appSettings.doneColor,
|
||||||
return Container(
|
leftColor: settingsVm.appSettings.leftColor,
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
"You don't have any currently active time progresses, that are tracked."),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return ListView(
|
|
||||||
padding: EdgeInsets.all(8),
|
|
||||||
children: timeProgresses
|
|
||||||
.map((timeProgress) => HomeProgressListTile(
|
|
||||||
timeProgress: timeProgress,
|
|
||||||
doneColor: settings.doneColor,
|
|
||||||
leftColor: settings.leftColor,
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,50 +1,32 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:time_progress_tracker/helper_functions.dart';
|
||||||
import 'package:time_progress_tracker/actions/actions.dart';
|
|
||||||
import 'package:time_progress_tracker/models/app_settings.dart';
|
|
||||||
import 'package:time_progress_tracker/models/time_progress.dart';
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
import 'package:time_progress_tracker/selectors/time_progress_selectors.dart';
|
import 'package:time_progress_tracker/widgets/progress_list_view/progress_list_view.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/home_progress_list_tile.dart';
|
import 'package:time_progress_tracker/widgets/store_connectors/settings_store_connector.dart';
|
||||||
|
import 'package:time_progress_tracker/widgets/store_connectors/time_progress_list_store_connector.dart';
|
||||||
|
|
||||||
class HomeInactiveProgressesTab extends StatelessWidget {
|
class HomeInactiveProgressesTab extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StoreConnector(
|
return SettingsStoreConnector(
|
||||||
onInit: loadSettingsIfUnloaded,
|
loadedBuilder: (context, settingsVm) {
|
||||||
converter: (store) => appSettingsSelector(store.state),
|
return TimeProgressListStoreConnector(
|
||||||
builder: (context, AppSettings settings) {
|
loadedBuilder: (context, tpListVm) {
|
||||||
return StoreConnector(
|
List<TimeProgress> inactiveTpList =
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
selectInactiveProgresses(tpListVm.tpList);
|
||||||
converter: (store) => store.state.hasProgressesLoaded,
|
if (inactiveTpList.length < 1)
|
||||||
builder: (BuildContext context, dynamic hasLoaded) {
|
return Container(
|
||||||
if (!(hasLoaded as bool))
|
padding: EdgeInsets.all(16),
|
||||||
return Center(
|
child: Center(
|
||||||
child: CircularProgressIndicator(),
|
child: Text(
|
||||||
|
"You don't have any currently inactive time progresses, that are tracked."),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return StoreConnector(
|
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
return ProgressListView(
|
||||||
converter: (store) => inactiveTimeProgressesSelector(store.state),
|
timeProgressList: inactiveTpList,
|
||||||
builder:
|
doneColor: settingsVm.appSettings.doneColor,
|
||||||
(BuildContext context, List<TimeProgress> timeProgresses) {
|
leftColor: settingsVm.appSettings.leftColor,
|
||||||
if (timeProgresses.length < 1)
|
|
||||||
return Container(
|
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
"You don't have any currently inactive time progresses, that are tracked."),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return ListView(
|
|
||||||
padding: EdgeInsets.all(8),
|
|
||||||
children: timeProgresses
|
|
||||||
.map((timeProgress) => HomeProgressListTile(
|
|
||||||
timeProgress: timeProgress,
|
|
||||||
doneColor: settings.doneColor,
|
|
||||||
leftColor: settings.leftColor,
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,21 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.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/app.dart';
|
||||||
import 'package:time_progress_tracker/models/app_settings.dart';
|
|
||||||
import 'package:time_progress_tracker/models/app_state.dart';
|
|
||||||
import 'package:time_progress_tracker/selectors/time_progress_selectors.dart';
|
|
||||||
import 'package:time_progress_tracker/widgets/home/tabs/settings/color_settings_widget.dart';
|
import 'package:time_progress_tracker/widgets/home/tabs/settings/color_settings_widget.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/tabs/settings/duration_settings_widget.dart';
|
import 'package:time_progress_tracker/widgets/home/tabs/settings/duration_settings_widget.dart';
|
||||||
|
import 'package:time_progress_tracker/widgets/store_connectors/settings_store_connector.dart';
|
||||||
|
|
||||||
class HomeSettingsTab extends StatelessWidget {
|
class HomeSettingsTab extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StoreConnector<AppState, _ViewModel>(
|
return SettingsStoreConnector(
|
||||||
onInit: loadSettingsIfUnloaded,
|
loadedBuilder: (context, settingsVm) {
|
||||||
converter: (store) => _ViewModel.create(store),
|
|
||||||
builder: (context, _ViewModel vm) {
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
child: Center(
|
child: Center(
|
||||||
@ -23,16 +16,16 @@ class HomeSettingsTab extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ColorSettingsWidget(
|
child: ColorSettingsWidget(
|
||||||
doneColor: vm.doneColor,
|
doneColor: settingsVm.appSettings.doneColor,
|
||||||
leftColor: vm.leftColor,
|
leftColor: settingsVm.appSettings.leftColor,
|
||||||
updateDoneColor: vm.onDoneColorChanged,
|
updateDoneColor: settingsVm.updateDoneColor,
|
||||||
updateLeftColor: vm.onLeftColorChanged,
|
updateLeftColor: settingsVm.updateLeftColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: DurationSettingsWidget(
|
child: DurationSettingsWidget(
|
||||||
duration: vm.duration,
|
duration: settingsVm.appSettings.duration,
|
||||||
updateDuration: vm.onDurationChanged,
|
updateDuration: settingsVm.updateDuration,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
@ -57,39 +50,3 @@ class HomeSettingsTab extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ViewModel {
|
|
||||||
final Color doneColor, leftColor;
|
|
||||||
final void Function(Color) onDoneColorChanged, onLeftColorChanged;
|
|
||||||
final Duration duration;
|
|
||||||
final void Function(Duration) onDurationChanged;
|
|
||||||
|
|
||||||
_ViewModel({
|
|
||||||
@required this.doneColor,
|
|
||||||
@required this.leftColor,
|
|
||||||
@required this.onDoneColorChanged,
|
|
||||||
@required this.onLeftColorChanged,
|
|
||||||
@required this.duration,
|
|
||||||
@required this.onDurationChanged,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory _ViewModel.create(Store<AppState> store) {
|
|
||||||
AppSettings settings = appSettingsSelector(store.state);
|
|
||||||
|
|
||||||
void _onDoneColorChanged(Color c) => store
|
|
||||||
.dispatch(UpdateAppSettingsActions(settings.copyWith(doneColor: c)));
|
|
||||||
void _onLeftColorChanged(Color c) => store
|
|
||||||
.dispatch(UpdateAppSettingsActions(settings.copyWith(leftColor: c)));
|
|
||||||
|
|
||||||
void _onDurationChanged(Duration d) => store
|
|
||||||
.dispatch(UpdateAppSettingsActions(settings.copyWith(duration: d)));
|
|
||||||
|
|
||||||
return _ViewModel(
|
|
||||||
doneColor: settings.doneColor,
|
|
||||||
leftColor: settings.leftColor,
|
|
||||||
onDoneColorChanged: _onDoneColorChanged,
|
|
||||||
onLeftColorChanged: _onLeftColorChanged,
|
|
||||||
duration: settings.duration,
|
|
||||||
onDurationChanged: _onDurationChanged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/tabs/settings/color_picker_btn.dart';
|
import 'package:time_progress_tracker/widgets/buttons/color_picker_btn.dart';
|
||||||
|
|
||||||
class ColorSettingsWidget extends StatelessWidget {
|
class ColorSettingsWidget extends StatelessWidget {
|
||||||
final Color doneColor, leftColor;
|
final Color doneColor, leftColor;
|
||||||
@ -14,13 +14,14 @@ class ColorSettingsWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
ThemeData appTheme = Theme.of(context);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Color Settings",
|
"Color Settings",
|
||||||
style:
|
style: appTheme.textTheme.headline6,
|
||||||
TextStyle(fontWeight: FontWeight.bold, color: Colors.black87),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_picker/flutter_picker.dart';
|
import 'package:time_progress_tracker/widgets/buttons/select_duration_btn.dart';
|
||||||
|
|
||||||
class DurationSettingsWidget extends StatelessWidget {
|
class DurationSettingsWidget extends StatelessWidget {
|
||||||
final Duration duration;
|
final Duration duration;
|
||||||
@ -12,49 +12,29 @@ class DurationSettingsWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
ThemeData appTheme = Theme.of(context);
|
||||||
|
|
||||||
int years = duration.inDays ~/ 365;
|
int years = duration.inDays ~/ 365;
|
||||||
int months = (duration.inDays - (365 * years)) ~/ 30;
|
int months = (duration.inDays - (365 * years)) ~/ 30;
|
||||||
int days = duration.inDays - (365 * years) - (30 * months);
|
int days = duration.inDays - (365 * years) - (30 * months);
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextButton(
|
child: Text(
|
||||||
onPressed: () {
|
"Duration Settings",
|
||||||
Picker(
|
style: appTheme.textTheme.headline6,
|
||||||
adapter: NumberPickerAdapter(
|
|
||||||
data: [
|
|
||||||
const NumberPickerColumn(
|
|
||||||
begin: 0,
|
|
||||||
end: 999,
|
|
||||||
suffix: Text(" Y"),
|
|
||||||
),
|
|
||||||
const NumberPickerColumn(
|
|
||||||
begin: 0,
|
|
||||||
end: 11,
|
|
||||||
suffix: Text(" M"),
|
|
||||||
),
|
|
||||||
const NumberPickerColumn(
|
|
||||||
begin: 0,
|
|
||||||
end: 30,
|
|
||||||
suffix: Text(" D"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
hideHeader: true,
|
|
||||||
confirmText: "OK",
|
|
||||||
title: const Text("Select Duration"),
|
|
||||||
selectedTextStyle: TextStyle(color: Colors.blue),
|
|
||||||
onConfirm: (Picker picker, List<int> value) {
|
|
||||||
int years = value[0], months = value[1], days = value[2];
|
|
||||||
days = (years * 365) + (months * 30) + days;
|
|
||||||
Duration newDuration = Duration(days: days);
|
|
||||||
updateDuration(newDuration);
|
|
||||||
},
|
|
||||||
).showDialog(context);
|
|
||||||
},
|
|
||||||
child: Text("Default Duration: $years Y - $months M - $days D"),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: SelectDurationBtn(
|
||||||
|
duration: duration,
|
||||||
|
updateDuration: updateDuration,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:time_progress_tracker/models/time_progress.dart';
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
import 'package:time_progress_tracker/widgets/date_picker_btn.dart';
|
import 'package:time_progress_tracker/widgets/buttons/date_picker_btn.dart';
|
||||||
|
|
||||||
class ProgressEditorWidget extends StatefulWidget {
|
class ProgressEditorWidget extends StatefulWidget {
|
||||||
final TimeProgress timeProgress;
|
final TimeProgress timeProgress;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||||
import 'package:time_progress_tracker/models/time_progress.dart';
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
|
import 'package:time_progress_tracker/screens/progress_detail_screen.dart';
|
||||||
|
|
||||||
class ProgressListTileStrings {
|
class ProgressListTileStrings {
|
||||||
static String percentString(TimeProgress tp) =>
|
static String percentString(TimeProgress tp) =>
|
||||||
@ -39,9 +40,14 @@ class ProgressListTile extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
void _onTileTap() =>
|
||||||
|
Navigator.pushNamed(context, ProgressDetailScreen.routeName,
|
||||||
|
arguments: ProgressDetailScreenArguments(timeProgress.id));
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(timeProgress.name),
|
title: Text(timeProgress.name),
|
||||||
subtitle: _renderSubtitle(context),
|
subtitle: _renderSubtitle(context),
|
||||||
|
onTap: _onTileTap,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,20 +13,21 @@ class ProgressListView extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
List<Widget> _renderListViewChildren() {
|
List<Widget> _renderListViewChildren() {
|
||||||
return timeProgressList.map((e) =>
|
return timeProgressList
|
||||||
Card(
|
.map((e) => Card(
|
||||||
child: ProgressListTile(
|
child: ProgressListTile(
|
||||||
timeProgress: e,
|
timeProgress: e,
|
||||||
doneColor: doneColor,
|
doneColor: doneColor,
|
||||||
leftColor: leftColor,
|
leftColor: leftColor,
|
||||||
),
|
),
|
||||||
)
|
))
|
||||||
).toList(growable: false);
|
.toList(growable: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
return ListView(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
children: _renderListViewChildren(),
|
children: _renderListViewChildren(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
60
lib/widgets/store_connectors/settings_store_connector.dart
Normal file
60
lib/widgets/store_connectors/settings_store_connector.dart
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
import 'package:redux/redux.dart';
|
||||||
|
import 'package:time_progress_tracker/actions/actions.dart';
|
||||||
|
import 'package:time_progress_tracker/models/app_settings.dart';
|
||||||
|
import 'package:time_progress_tracker/models/app_state.dart';
|
||||||
|
|
||||||
|
class SettingsStoreConnector extends StatelessWidget {
|
||||||
|
final Widget Function(BuildContext, SettingsViewModel) loadedBuilder;
|
||||||
|
|
||||||
|
SettingsStoreConnector({
|
||||||
|
@required this.loadedBuilder,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return StoreConnector<AppState, SettingsViewModel>(
|
||||||
|
onInit: loadSettingsIfUnloaded,
|
||||||
|
converter: (store) => SettingsViewModel._create(store),
|
||||||
|
builder: (context, SettingsViewModel vm) {
|
||||||
|
if (!vm.hasSettingsLoaded)
|
||||||
|
return Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
return loadedBuilder(context, vm);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsViewModel {
|
||||||
|
final AppSettings appSettings;
|
||||||
|
final bool hasSettingsLoaded;
|
||||||
|
|
||||||
|
final void Function(Color) updateDoneColor, updateLeftColor;
|
||||||
|
final void Function(Duration) updateDuration;
|
||||||
|
|
||||||
|
SettingsViewModel(
|
||||||
|
this.appSettings,
|
||||||
|
this.hasSettingsLoaded,
|
||||||
|
this.updateDoneColor,
|
||||||
|
this.updateLeftColor,
|
||||||
|
this.updateDuration,
|
||||||
|
);
|
||||||
|
|
||||||
|
factory SettingsViewModel._create(Store<AppState> store) {
|
||||||
|
AppSettings _appSettings = store.state.appSettings;
|
||||||
|
|
||||||
|
void _updateDoneColor(Color dC) => store.dispatch(
|
||||||
|
UpdateAppSettingsActions(_appSettings.copyWith(doneColor: dC)));
|
||||||
|
void _updateLeftColor(Color lC) => store.dispatch(
|
||||||
|
UpdateAppSettingsActions(_appSettings.copyWith(leftColor: lC)));
|
||||||
|
|
||||||
|
void _updateDuration(Duration d) => store
|
||||||
|
.dispatch(UpdateAppSettingsActions(_appSettings.copyWith(duration: d)));
|
||||||
|
|
||||||
|
return SettingsViewModel(_appSettings, store.state.hasSettingsLoaded,
|
||||||
|
_updateDoneColor, _updateLeftColor, _updateDuration);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
import 'package:redux/redux.dart';
|
||||||
|
import 'package:time_progress_tracker/actions/actions.dart';
|
||||||
|
import 'package:time_progress_tracker/models/app_state.dart';
|
||||||
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
|
|
||||||
|
class TimeProgressListStoreConnector extends StatelessWidget {
|
||||||
|
final Widget Function(BuildContext, TimeProgressListViewModel) loadedBuilder;
|
||||||
|
|
||||||
|
TimeProgressListStoreConnector({
|
||||||
|
@required this.loadedBuilder,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return StoreConnector<AppState, TimeProgressListViewModel>(
|
||||||
|
onInit: loadTimeProgressListIfUnloaded,
|
||||||
|
converter: (store) => TimeProgressListViewModel._create(store),
|
||||||
|
builder: (context, TimeProgressListViewModel vm) {
|
||||||
|
if (!vm.hasTpListLoaded)
|
||||||
|
return Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
return loadedBuilder(context, vm);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeProgressListViewModel {
|
||||||
|
final List<TimeProgress> tpList;
|
||||||
|
final bool hasTpListLoaded;
|
||||||
|
|
||||||
|
TimeProgressListViewModel(this.tpList, this.hasTpListLoaded);
|
||||||
|
|
||||||
|
factory TimeProgressListViewModel._create(Store<AppState> store) =>
|
||||||
|
TimeProgressListViewModel(
|
||||||
|
store.state.timeProgressList, store.state.hasProgressesLoaded);
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
import 'package:redux/redux.dart';
|
||||||
|
import 'package:time_progress_tracker/actions/actions.dart';
|
||||||
|
import 'package:time_progress_tracker/models/app_state.dart';
|
||||||
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
|
|
||||||
|
import '../../helper_functions.dart';
|
||||||
|
|
||||||
|
class TimeProgressStoreConnector extends StatelessWidget {
|
||||||
|
final String timeProgressId;
|
||||||
|
final Widget Function(BuildContext, TimeProgressViewModel) loadedBuilder;
|
||||||
|
|
||||||
|
TimeProgressStoreConnector({
|
||||||
|
@required this.timeProgressId,
|
||||||
|
@required this.loadedBuilder,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return StoreConnector<AppState, TimeProgressViewModel>(
|
||||||
|
onInit: loadTimeProgressListIfUnloaded,
|
||||||
|
converter: (store) =>
|
||||||
|
TimeProgressViewModel._create(store, timeProgressId),
|
||||||
|
builder: (context, TimeProgressViewModel vm) {
|
||||||
|
if (!vm.hasTpListLoaded)
|
||||||
|
return Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
if (vm.tp == null)
|
||||||
|
return Center(
|
||||||
|
child: Text("Error Invalid Time Progress"),
|
||||||
|
);
|
||||||
|
return loadedBuilder(context, vm);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeProgressViewModel {
|
||||||
|
final TimeProgress tp;
|
||||||
|
final bool hasTpListLoaded;
|
||||||
|
|
||||||
|
final void Function(TimeProgress) updateTimeProgress;
|
||||||
|
final void Function() deleteTimeProgress;
|
||||||
|
|
||||||
|
TimeProgressViewModel(
|
||||||
|
this.tp,
|
||||||
|
this.hasTpListLoaded,
|
||||||
|
this.updateTimeProgress,
|
||||||
|
this.deleteTimeProgress,
|
||||||
|
);
|
||||||
|
|
||||||
|
factory TimeProgressViewModel._create(Store<AppState> store, String id) {
|
||||||
|
void _updateTimeProgress(TimeProgress tp) =>
|
||||||
|
store.dispatch(UpdateTimeProgressAction(id, tp));
|
||||||
|
void _deleteTimeProgress() => store.dispatch(DeleteTimeProgressAction(id));
|
||||||
|
|
||||||
|
return TimeProgressViewModel(
|
||||||
|
selectProgressById(store.state.timeProgressList, id),
|
||||||
|
store.state.hasProgressesLoaded,
|
||||||
|
_updateTimeProgress,
|
||||||
|
_deleteTimeProgress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 0.0.18+18
|
version: 0.0.19+19
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.7.0 <3.0.0"
|
sdk: ">=2.7.0 <3.0.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user