diff --git a/lib/actions/actions.dart b/lib/actions/actions.dart new file mode 100644 index 0000000..27dcfe9 --- /dev/null +++ b/lib/actions/actions.dart @@ -0,0 +1,30 @@ +import 'package:time_progress_calculator/models/time_progress.dart'; + +class LoadTimeProgressListAction {} + +class TimeProgressListLoadedAction { + final List timeProgressList; + + TimeProgressListLoadedAction(this.timeProgressList); +} + +class TimeProgressListNotLoadedAction {} + +class AddTimeProgressAction { + final TimeProgress timeProgress; + + AddTimeProgressAction(this.timeProgress); +} + +class UpdateTimeProgressAction { + final String id; + final TimeProgress updatedTimeProgress; + + UpdateTimeProgressAction(this.id, this.updatedTimeProgress); +} + +class DeleteTimeProgressAction { + final String id; + + DeleteTimeProgressAction(this.id); +} diff --git a/lib/actions/timer_actions.dart b/lib/actions/timer_actions.dart deleted file mode 100644 index f9075c2..0000000 --- a/lib/actions/timer_actions.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:time_progress_calculator/models/timer.dart'; - -class LoadTimersAction {} - -class TimersLoadedAction { - final List timers; - - TimersLoadedAction(this.timers); -} - -class TimersNotLoadedAction {} - -class AddTimerAction { - final Timer timer; - - AddTimerAction(this.timer); -} - -class UpdateTimerAction { - final String id; - final Timer updatedTimer; - - UpdateTimerAction(this.id, this.updatedTimer); -} - -class DeleteTimerAction { - final String id; - - DeleteTimerAction(this.id); -} diff --git a/lib/main.dart b/lib/main.dart index 236d7f6..5a43827 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:redux/redux.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:time_progress_calculator/app.dart'; -import 'package:time_progress_calculator/middleware/store_timers_middleware.dart'; +import 'package:time_progress_calculator/middleware/store_time_progress_middleware.dart'; import 'package:time_progress_calculator/models/app_state.dart'; -import 'package:time_progress_calculator/persistence/timers_repository.dart'; +import 'package:time_progress_calculator/persistence/time_progress_repository.dart'; import 'package:time_progress_calculator/reducers/app_state_reducer.dart'; Future main() async { @@ -14,8 +14,8 @@ Future main() async { store: Store( appStateReducer, initialState: AppState.initial(), - middleware: createStoreTimersMiddleware( - TimersRepository(await SharedPreferences.getInstance()), + middleware: createStoreTimeProgressListMiddleware( + TimeProgressRepository(await SharedPreferences.getInstance()), ), ), )); diff --git a/lib/middleware/store_time_progress_middleware.dart b/lib/middleware/store_time_progress_middleware.dart new file mode 100644 index 0000000..9cd207c --- /dev/null +++ b/lib/middleware/store_time_progress_middleware.dart @@ -0,0 +1,42 @@ +import 'package:redux/redux.dart'; +import 'package:time_progress_calculator/actions/actions.dart'; +import 'package:time_progress_calculator/models/app_state.dart'; +import 'package:time_progress_calculator/models/time_progress.dart'; +import 'package:time_progress_calculator/persistence/time_progress_entity.dart'; +import 'package:time_progress_calculator/persistence/time_progress_repository.dart'; +import 'package:time_progress_calculator/selectors/time_progress_selectors.dart'; + +List> createStoreTimeProgressListMiddleware( + TimeProgressRepository repository) { + final saveTimeProgressList = _createSaveTimeProgressList(repository); + final loadTimeProgressList = _createLoadTimeProgressList(repository); + + return [ + TypedMiddleware(loadTimeProgressList), + TypedMiddleware(saveTimeProgressList), + TypedMiddleware(saveTimeProgressList), + TypedMiddleware(saveTimeProgressList), + ]; +} + +Middleware _createSaveTimeProgressList(TimeProgressRepository repository) { + return (Store store, dynamic action, NextDispatcher next) { + next(action); + + repository.saveTimeProgressList( + timeProgressListSelector(store.state) + .map((timeProgress) => timeProgress.toEntity()) + .toList(growable: false), + ); + }; +} + +Middleware _createLoadTimeProgressList(TimeProgressRepository repository) { + return (Store store, dynamic action, NextDispatcher next) { + repository.loadTimeProgressList().then((timeProgresses) { + store.dispatch( + TimeProgressListLoadedAction(timeProgresses.map(TimeProgress.fromEntity).toList()), + ); + }).catchError((_) => store.dispatch(TimeProgressListNotLoadedAction())); + }; +} diff --git a/lib/middleware/store_timers_middleware.dart b/lib/middleware/store_timers_middleware.dart deleted file mode 100644 index 10a2a9d..0000000 --- a/lib/middleware/store_timers_middleware.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:redux/redux.dart'; -import 'package:time_progress_calculator/actions/timer_actions.dart'; -import 'package:time_progress_calculator/models/app_state.dart'; -import 'package:time_progress_calculator/models/timer.dart'; -import 'package:time_progress_calculator/persistence/timer_entity.dart'; -import 'package:time_progress_calculator/persistence/timers_repository.dart'; -import 'package:time_progress_calculator/selectors/timer_selectors.dart'; - -List> createStoreTimersMiddleware( - TimersRepository repository) { - final saveTimers = _createSaveTimers(repository); - final loadTimers = _createLoadTimers(repository); - - return [ - TypedMiddleware(loadTimers), - TypedMiddleware(saveTimers), - TypedMiddleware(saveTimers), - TypedMiddleware(saveTimers), - ]; -} - -Middleware _createSaveTimers(TimersRepository repository) { - return (Store store, dynamic action, NextDispatcher next) { - next(action); - - repository.saveTimers( - timersSelector(store.state) - .map((timer) => timer.toEntity()) - .toList(growable: false), - ); - }; -} - -Middleware _createLoadTimers(TimersRepository repository) { - return (Store store, dynamic action, NextDispatcher next) { - repository.loadTimers().then((timers) { - store.dispatch( - TimersLoadedAction(timers.map(Timer.fromEntity).toList()), - ); - }).catchError((_) => store.dispatch(TimersNotLoadedAction())); - }; -} diff --git a/lib/models/app_state.dart b/lib/models/app_state.dart index 4f56a3c..1876cc5 100644 --- a/lib/models/app_state.dart +++ b/lib/models/app_state.dart @@ -1,35 +1,35 @@ import 'package:meta/meta.dart'; -import 'package:time_progress_calculator/models/timer.dart'; +import 'package:time_progress_calculator/models/time_progress.dart'; @immutable class AppState { final bool isLoading; - final List timers; + final List timeProgressList; AppState({ this.isLoading = false, - this.timers = const [], + this.timeProgressList = const [], }); factory AppState.initial() => AppState(isLoading: true); AppState copyWith({ bool isLoading, - List timers, + List timeProgressList, }) { return AppState( isLoading: isLoading ?? this.isLoading, - timers: timers ?? this.timers, + timeProgressList: timeProgressList ?? this.timeProgressList, ); } @override - int get hashCode => timers.hashCode; + int get hashCode => timeProgressList.hashCode; @override bool operator ==(Object other) => identical(this, other) || other is AppState && runtimeType == other.runtimeType && - timers == other.timers; + timeProgressList == other.timeProgressList; } diff --git a/lib/models/timer.dart b/lib/models/time_progress.dart similarity index 64% rename from lib/models/timer.dart rename to lib/models/time_progress.dart index 5861639..f9fc88a 100644 --- a/lib/models/timer.dart +++ b/lib/models/time_progress.dart @@ -1,18 +1,18 @@ import 'package:meta/meta.dart'; -import 'package:time_progress_calculator/persistence/timer_entity.dart'; +import 'package:time_progress_calculator/persistence/time_progress_entity.dart'; import 'package:time_progress_calculator/uuid.dart'; @immutable -class Timer { +class TimeProgress { final String id; final DateTime startTime; final DateTime endTime; - Timer(this.startTime, this.endTime, {String id}) + TimeProgress(this.startTime, this.endTime, {String id}) : id = id ?? Uuid().generateV4(); - Timer copyWith({String id, DateTime startTime, DateTime endTime}) { - return Timer( + TimeProgress copyWith({String id, DateTime startTime, DateTime endTime}) { + return TimeProgress( startTime ?? this.startTime, endTime ?? this.endTime, id: id ?? this.id, @@ -25,7 +25,7 @@ class Timer { @override bool operator ==(Object other) => identical(this, other) || - other is Timer && + other is TimeProgress && runtimeType == other.runtimeType && id == other.id && startTime == other.startTime && @@ -36,12 +36,12 @@ class Timer { return "Timer{id: $id, startTimer: $startTime, endTimer: $endTime}"; } - TimerEntity toEntity() { - return TimerEntity(id, startTime, endTime); + TimeProgressEntity toEntity() { + return TimeProgressEntity(id, startTime, endTime); } - static Timer fromEntity(TimerEntity entity) { - return Timer( + static TimeProgress fromEntity(TimeProgressEntity entity) { + return TimeProgress( entity.startTime, entity.endTime, id: entity.id ?? Uuid().generateV4(), diff --git a/lib/persistence/timer_entity.dart b/lib/persistence/time_progress_entity.dart similarity index 77% rename from lib/persistence/timer_entity.dart rename to lib/persistence/time_progress_entity.dart index 81d0ca5..6fde489 100644 --- a/lib/persistence/timer_entity.dart +++ b/lib/persistence/time_progress_entity.dart @@ -1,9 +1,9 @@ -class TimerEntity { +class TimeProgressEntity { final String id; final DateTime startTime; final DateTime endTime; - TimerEntity(this.id, this.startTime, this.endTime); + TimeProgressEntity(this.id, this.startTime, this.endTime); @override int get hashCode => id.hashCode ^ startTime.hashCode ^ endTime.hashCode; @@ -11,7 +11,7 @@ class TimerEntity { @override bool operator ==(Object other) => identical(this, other) || - other is TimerEntity && + other is TimeProgressEntity && runtimeType == other.runtimeType && id == other.id && startTime == other.startTime && @@ -25,12 +25,12 @@ class TimerEntity { }; } - static TimerEntity fromJson(Map json) { + static TimeProgressEntity fromJson(Map json) { final String id = json["id"] as String; final DateTime startTime = DateTime.fromMillisecondsSinceEpoch(json["startTime"] as int); final DateTime endTime = DateTime.fromMillisecondsSinceEpoch(json["endTime"] as int); - return TimerEntity(id, startTime, endTime); + return TimeProgressEntity(id, startTime, endTime); } } diff --git a/lib/persistence/time_progress_repository.dart b/lib/persistence/time_progress_repository.dart new file mode 100644 index 0000000..59babd9 --- /dev/null +++ b/lib/persistence/time_progress_repository.dart @@ -0,0 +1,27 @@ +import 'dart:convert'; + +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:time_progress_calculator/persistence/time_progress_entity.dart'; + +class TimeProgressRepository { + static const String _key = "time_progress_repo"; + final SharedPreferences prefs; + final JsonCodec codec; + + TimeProgressRepository(this.prefs, {this.codec = json}); + + Future> loadTimeProgressList() { + final String jsonString = this.prefs.getString(_key); + return codec + .decode(jsonString)["timers"] + .cast>() + .map(TimeProgressEntity.fromJson) + .toList(growable: false); + } + + Future saveTimeProgressList(List timeProgressList) { + final String jsonString = codec + .encode({"timers": timeProgressList.map((timer) => timer.toJson()).toList()}); + return this.prefs.setString(_key, jsonString); + } +} diff --git a/lib/persistence/timers_repository.dart b/lib/persistence/timers_repository.dart deleted file mode 100644 index 9c40d55..0000000 --- a/lib/persistence/timers_repository.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'dart:convert'; - -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:time_progress_calculator/persistence/timer_entity.dart'; - -class TimersRepository { - static const String _key = "timers_repo"; - final SharedPreferences prefs; - final JsonCodec codec; - - TimersRepository(this.prefs, {this.codec = json}); - - Future> loadTimers() { - final String jsonString = this.prefs.getString(_key); - return codec - .decode(jsonString)["timers"] - .cast>() - .map(TimerEntity.fromJson) - .toList(growable: false); - } - - Future saveTimers(List timers) { - final String jsonString = codec - .encode({"timers": timers.map((timer) => timer.toJson()).toList()}); - return this.prefs.setString(_key, jsonString); - } -} diff --git a/lib/reducers/app_state_reducer.dart b/lib/reducers/app_state_reducer.dart index 7beccd0..729f4b3 100644 --- a/lib/reducers/app_state_reducer.dart +++ b/lib/reducers/app_state_reducer.dart @@ -1,6 +1,6 @@ import 'package:time_progress_calculator/models/app_state.dart'; -import 'package:time_progress_calculator/reducers/timer_reducer.dart'; +import 'package:time_progress_calculator/reducers/time_progress_list_reducer.dart'; AppState appStateReducer(AppState state, dynamic action) { - return AppState(timers: timersReducer(state.timers, action)); + return AppState(timeProgressList: timeProgressListReducer(state.timeProgressList, action)); } diff --git a/lib/reducers/time_progress_list_reducer.dart b/lib/reducers/time_progress_list_reducer.dart new file mode 100644 index 0000000..6f9c38d --- /dev/null +++ b/lib/reducers/time_progress_list_reducer.dart @@ -0,0 +1,45 @@ +import 'package:time_progress_calculator/actions/actions.dart'; +import 'package:time_progress_calculator/models/time_progress.dart'; +import 'package:redux/redux.dart'; + +final timeProgressListReducer = combineReducers>([ + TypedReducer, TimeProgressListLoadedAction>( + _setLoadedTimeProgressList), + TypedReducer, TimeProgressListNotLoadedAction>( + _setEmptyTimeProgressList), + TypedReducer, AddTimeProgressAction>(_addTimeProgress), + TypedReducer, UpdateTimeProgressAction>( + _updateTimeProgress), + TypedReducer, DeleteTimeProgressAction>(_deleteTimeProgress), +]); + +List _setLoadedTimeProgressList( + List timeProgressList, TimeProgressListLoadedAction action) { + return action.timeProgressList; +} + +List _setEmptyTimeProgressList( + List timeProgressList, TimeProgressListNotLoadedAction action) { + return []; +} + +List _addTimeProgress( + List timeProgressList, AddTimeProgressAction action) { + return List.from(timeProgressList) + ..add(action.timeProgress) + ..toList(growable: false); +} + +List _updateTimeProgress( + List timeProgressList, UpdateTimeProgressAction action) { + return timeProgressList + .map((timeProgress) => timeProgress.id == action.id + ? action.updatedTimeProgress + : timeProgress) + .toList(growable: false); +} + +List _deleteTimeProgress( + List timeProgressList, DeleteTimeProgressAction action) { + return timeProgressList.where((timeProgress) => timeProgress.id != action.id).toList(growable: false); +} diff --git a/lib/reducers/timer_reducer.dart b/lib/reducers/timer_reducer.dart deleted file mode 100644 index 9f6124a..0000000 --- a/lib/reducers/timer_reducer.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:time_progress_calculator/actions/timer_actions.dart'; -import 'package:time_progress_calculator/models/timer.dart'; -import 'package:redux/redux.dart'; - -final timersReducer = combineReducers>([ - TypedReducer, TimersLoadedAction>(_setLoadedTimers), - TypedReducer, TimersNotLoadedAction>(_setEmptyTimers), - TypedReducer, AddTimerAction>(_addTimer), - TypedReducer, UpdateTimerAction>(_updateTimer), - TypedReducer, DeleteTimerAction>(_deleteTimer), -]); - -List _setLoadedTimers(List timers, TimersLoadedAction action) { - return action.timers; -} - -List _setEmptyTimers(List timers, TimersNotLoadedAction action) { - return []; -} - -List _addTimer(List timers, AddTimerAction action) { - return List.from(timers) - ..add(action.timer) - ..toList(growable: false); -} - -List _updateTimer(List timers, UpdateTimerAction action) { - return timers - .map((timer) => timer.id == action.id ? action.updatedTimer : timer) - .toList(growable: false); -} - -List _deleteTimer(List timers, DeleteTimerAction action) { - return timers.where((timer) => timer.id != action.id).toList(growable: false); -} diff --git a/lib/screens/progress_screen.dart b/lib/screens/progress_screen.dart index 00710e8..ddc6b4d 100644 --- a/lib/screens/progress_screen.dart +++ b/lib/screens/progress_screen.dart @@ -3,9 +3,9 @@ import 'package:flutter_redux/flutter_redux.dart'; import 'package:percent_indicator/circular_percent_indicator.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:redux/redux.dart'; -import 'package:time_progress_calculator/actions/timer_actions.dart'; +import 'package:time_progress_calculator/actions/actions.dart'; import 'package:time_progress_calculator/models/app_state.dart'; -import 'package:time_progress_calculator/models/timer.dart'; +import 'package:time_progress_calculator/models/time_progress.dart'; class ProgressScreen extends StatefulWidget { const ProgressScreen({Key key, @required this.context, this.name}) @@ -25,13 +25,13 @@ class _ProgressScreenState extends State { Store store = StoreProvider.of(context); final DateTime picked = await showDatePicker( context: context, - initialDate: store.state.timers[0].startTime, + initialDate: store.state.timeProgressList[0].startTime, firstDate: DateTime(2000), lastDate: DateTime(2100)); - if (picked != null && picked != store.state.timers[0].startTime) { - store.dispatch(UpdateTimerAction( - store.state.timers[0].id, - store.state.timers[0].copyWith(startTime: picked), + if (picked != null && picked != store.state.timeProgressList[0].startTime) { + store.dispatch(UpdateTimeProgressAction( + store.state.timeProgressList[0].id, + store.state.timeProgressList[0].copyWith(startTime: picked), )); } } @@ -40,13 +40,13 @@ class _ProgressScreenState extends State { Store store = StoreProvider.of(context); final DateTime picked = await showDatePicker( context: context, - initialDate: store.state.timers[0].endTime, + initialDate: store.state.timeProgressList[0].endTime, firstDate: DateTime(2000), lastDate: DateTime(2100)); - if (picked != null && picked != store.state.timers[0].endTime) { - store.dispatch(UpdateTimerAction( - store.state.timers[0].id, - store.state.timers[0].copyWith(endTime: picked), + if (picked != null && picked != store.state.timeProgressList[0].endTime) { + store.dispatch(UpdateTimeProgressAction( + store.state.timeProgressList[0].id, + store.state.timeProgressList[0].copyWith(endTime: picked), )); } } @@ -54,8 +54,8 @@ class _ProgressScreenState extends State { @override void initState() { super.initState(); - if (StoreProvider.of(widget.context).state.timers.length < 1) { - StoreProvider.of(widget.context).dispatch(AddTimerAction(Timer( + if (StoreProvider.of(widget.context).state.timeProgressList.length < 1) { + StoreProvider.of(widget.context).dispatch(AddTimeProgressAction(TimeProgress( DateTime(2000), DateTime(2100), ))); @@ -72,11 +72,11 @@ class _ProgressScreenState extends State { converter: _ViewModel.fromStore, builder: (context, _ViewModel vm) { final int daysDone = - DateTime.now().difference(vm.timer.startTime).inDays; + DateTime.now().difference(vm.timeProgress.startTime).inDays; final int daysLeft = - vm.timer.endTime.difference(DateTime.now()).inDays; + vm.timeProgress.endTime.difference(DateTime.now()).inDays; final int allDays = - vm.timer.endTime.difference(vm.timer.startTime).inDays; + vm.timeProgress.endTime.difference(vm.timeProgress.startTime).inDays; final double percent = daysDone / (allDays / 100) / 100; return Container( @@ -97,7 +97,7 @@ class _ProgressScreenState extends State { Expanded( flex: 2, child: Text( - "${vm.timer.startTime.toLocal()}".split(" ")[0]), + "${vm.timeProgress.startTime.toLocal()}".split(" ")[0]), ), Expanded( flex: 2, @@ -125,7 +125,7 @@ class _ProgressScreenState extends State { Expanded( flex: 2, child: Text( - "${vm.timer.endTime.toLocal()}".split(" ")[0]), + "${vm.timeProgress.endTime.toLocal()}".split(" ")[0]), ), Expanded( flex: 2, @@ -176,15 +176,15 @@ class _ProgressScreenState extends State { } class _ViewModel { - final Timer timer; + final TimeProgress timeProgress; _ViewModel({ - @required this.timer, + @required this.timeProgress, }); static _ViewModel fromStore(Store store) { return _ViewModel( - timer: store.state.timers[0], + timeProgress: store.state.timeProgressList[0], ); } } diff --git a/lib/selectors/time_progress_selectors.dart b/lib/selectors/time_progress_selectors.dart new file mode 100644 index 0000000..0ffa851 --- /dev/null +++ b/lib/selectors/time_progress_selectors.dart @@ -0,0 +1,4 @@ +import 'package:time_progress_calculator/models/app_state.dart'; +import 'package:time_progress_calculator/models/time_progress.dart'; + +List timeProgressListSelector(AppState state) => state.timeProgressList; diff --git a/lib/selectors/timer_selectors.dart b/lib/selectors/timer_selectors.dart deleted file mode 100644 index 01b6c34..0000000 --- a/lib/selectors/timer_selectors.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:time_progress_calculator/models/app_state.dart'; -import 'package:time_progress_calculator/models/timer.dart'; - -List timersSelector(AppState state) => state.timers;