Feature/change progress colors (#6)
* Added Settings Actions * Created App Settings and Repo + Entity * Code cleanup Time Progress * Created App Settings Middleware * Has Progresses ad has Settings loaded * Created Load and Update Settings reducers * Added Settings store middleware to renamed store middleware * Load Default Settings if not Saved. Use Redux AppState to showprogress colors. Colors are not yet changeable. * Added ColorPicker for Done and Left Color Fixed Loading App Settings Bug * Fixed Version Number * Fixed Android App Logo * Extracted Color Settings into Widget * Fixed Home Settings Tab Layout and Color Settings Button now show Text in complementary color
This commit is contained in:
parent
c580e45361
commit
b520d56d1a
@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 46;
|
objectVersion = 50;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@ -132,7 +132,6 @@
|
|||||||
FF252FCCD702699EBF6FC287 /* Pods-Runner.release.xcconfig */,
|
FF252FCCD702699EBF6FC287 /* Pods-Runner.release.xcconfig */,
|
||||||
F9B8D838B24E4D784CD9D717 /* Pods-Runner.profile.xcconfig */,
|
F9B8D838B24E4D784CD9D717 /* Pods-Runner.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -354,7 +353,10 @@
|
|||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
@ -482,7 +484,10 @@
|
|||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
@ -505,7 +510,10 @@
|
|||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Time Progress Tracker</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
@ -1,7 +1,24 @@
|
|||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.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/app_state.dart';
|
||||||
import 'package:time_progress_tracker/models/time_progress.dart';
|
import 'package:time_progress_tracker/models/time_progress.dart';
|
||||||
|
|
||||||
|
class LoadSettingsAction {}
|
||||||
|
|
||||||
|
class AppSettingsLoadedActions {
|
||||||
|
final AppSettings appSettings;
|
||||||
|
|
||||||
|
AppSettingsLoadedActions(this.appSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpdateAppSettingsActions {
|
||||||
|
final AppSettings appSettings;
|
||||||
|
|
||||||
|
UpdateAppSettingsActions(this.appSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppSettingsNotLoadedAction {}
|
||||||
|
|
||||||
class LoadTimeProgressListAction {}
|
class LoadTimeProgressListAction {}
|
||||||
|
|
||||||
class TimeProgressListLoadedAction {
|
class TimeProgressListLoadedAction {
|
||||||
@ -32,7 +49,10 @@ class DeleteTimeProgressAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loadTimeProgressListIfUnloaded(Store<AppState> store) {
|
void loadTimeProgressListIfUnloaded(Store<AppState> store) {
|
||||||
if (!store.state.hasLoaded) {
|
if (!store.state.hasProgressesLoaded)
|
||||||
store.dispatch(LoadTimeProgressListAction());
|
store.dispatch(LoadTimeProgressListAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadSettingsIfUnloaded(Store<AppState> store) {
|
||||||
|
if (!store.state.hasSettingsLoaded) store.dispatch(LoadSettingsAction());
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:package_info/package_info.dart';
|
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:time_progress_tracker/app.dart';
|
import 'package:time_progress_tracker/app.dart';
|
||||||
import 'package:time_progress_tracker/middleware/store_time_progress_middleware.dart';
|
import 'package:time_progress_tracker/middleware/store_middleware.dart';
|
||||||
import 'package:time_progress_tracker/models/app_state.dart';
|
import 'package:time_progress_tracker/models/app_state.dart';
|
||||||
|
import 'package:time_progress_tracker/persistence/app_settings.dart';
|
||||||
import 'package:time_progress_tracker/persistence/time_progress_repository.dart';
|
import 'package:time_progress_tracker/persistence/time_progress_repository.dart';
|
||||||
import 'package:time_progress_tracker/reducers/app_state_reducer.dart';
|
import 'package:time_progress_tracker/reducers/app_state_reducer.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
runApp(TimeProgressTrackerApp(
|
runApp(TimeProgressTrackerApp(
|
||||||
store: Store<AppState>(
|
store: Store<AppState>(
|
||||||
appStateReducer,
|
appStateReducer,
|
||||||
initialState: AppState.initial(),
|
initialState: AppState.initial(),
|
||||||
middleware: createStoreTimeProgressListMiddleware(
|
middleware: createStoreMiddleware(
|
||||||
TimeProgressRepository(await SharedPreferences.getInstance()),
|
TimeProgressRepository(prefs), AppSettingsRepository(prefs)),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -1,21 +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';
|
||||||
|
import 'package:time_progress_tracker/models/app_settings.dart';
|
||||||
import 'package:time_progress_tracker/models/app_state.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/persistence/app_settings.dart';
|
||||||
import 'package:time_progress_tracker/persistence/time_progress_entity.dart';
|
import 'package:time_progress_tracker/persistence/time_progress_entity.dart';
|
||||||
import 'package:time_progress_tracker/persistence/time_progress_repository.dart';
|
import 'package:time_progress_tracker/persistence/time_progress_repository.dart';
|
||||||
import 'package:time_progress_tracker/selectors/time_progress_selectors.dart';
|
import 'package:time_progress_tracker/selectors/time_progress_selectors.dart';
|
||||||
|
|
||||||
List<Middleware<AppState>> createStoreTimeProgressListMiddleware(
|
List<Middleware<AppState>> createStoreMiddleware(
|
||||||
TimeProgressRepository repository) {
|
TimeProgressRepository progressRepo, AppSettingsRepository settingsRepo) {
|
||||||
final saveTimeProgressList = _createSaveTimeProgressList(repository);
|
final saveTimeProgressList = _createSaveTimeProgressList(progressRepo);
|
||||||
final loadTimeProgressList = _createLoadTimeProgressList(repository);
|
final loadTimeProgressList = _createLoadTimeProgressList(progressRepo);
|
||||||
|
|
||||||
|
final saveSettings = _createSaveAppSettings(settingsRepo);
|
||||||
|
final loadSettings = _createLoadAppSettings(settingsRepo);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
TypedMiddleware<AppState, LoadTimeProgressListAction>(loadTimeProgressList),
|
TypedMiddleware<AppState, LoadTimeProgressListAction>(loadTimeProgressList),
|
||||||
TypedMiddleware<AppState, AddTimeProgressAction>(saveTimeProgressList),
|
TypedMiddleware<AppState, AddTimeProgressAction>(saveTimeProgressList),
|
||||||
TypedMiddleware<AppState, UpdateTimeProgressAction>(saveTimeProgressList),
|
TypedMiddleware<AppState, UpdateTimeProgressAction>(saveTimeProgressList),
|
||||||
TypedMiddleware<AppState, DeleteTimeProgressAction>(saveTimeProgressList),
|
TypedMiddleware<AppState, DeleteTimeProgressAction>(saveTimeProgressList),
|
||||||
|
TypedMiddleware<AppState, LoadSettingsAction>(loadSettings),
|
||||||
|
TypedMiddleware<AppState, UpdateAppSettingsActions>(saveSettings)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,3 +54,17 @@ Middleware<AppState> _createLoadTimeProgressList(
|
|||||||
}).catchError((_) => store.dispatch(TimeProgressListNotLoadedAction()));
|
}).catchError((_) => store.dispatch(TimeProgressListNotLoadedAction()));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Middleware<AppState> _createSaveAppSettings(AppSettingsRepository repo) =>
|
||||||
|
(Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||||
|
next(action);
|
||||||
|
repo.saveAppSettings(store.state.appSettings.toEntity());
|
||||||
|
};
|
||||||
|
|
||||||
|
Middleware<AppState> _createLoadAppSettings(AppSettingsRepository repo) =>
|
||||||
|
(Store<AppState> store, dynamic action, NextDispatcher next) {
|
||||||
|
repo.loadAppSettings().then((appSettings) {
|
||||||
|
store.dispatch(
|
||||||
|
AppSettingsLoadedActions(AppSettings.fromEntity(appSettings)));
|
||||||
|
});
|
||||||
|
};
|
44
lib/models/app_settings.dart
Normal file
44
lib/models/app_settings.dart
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:time_progress_tracker/persistence/app_settings.dart';
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class AppSettings {
|
||||||
|
final Color doneColor;
|
||||||
|
final Color leftColor;
|
||||||
|
final Duration duration;
|
||||||
|
|
||||||
|
AppSettings({
|
||||||
|
this.doneColor,
|
||||||
|
this.leftColor,
|
||||||
|
this.duration,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory AppSettings.defaults() =>
|
||||||
|
AppSettings(doneColor: Colors.green, leftColor: Colors.red);
|
||||||
|
|
||||||
|
AppSettings copyWith({
|
||||||
|
Color doneColor,
|
||||||
|
Color leftColor,
|
||||||
|
}) =>
|
||||||
|
AppSettings(
|
||||||
|
doneColor: doneColor ?? this.doneColor,
|
||||||
|
leftColor: leftColor ?? this.leftColor);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => doneColor.hashCode ^ leftColor.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is AppSettings &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
doneColor == other.doneColor &&
|
||||||
|
leftColor == other.leftColor;
|
||||||
|
|
||||||
|
AppSettingsEntity toEntity() =>
|
||||||
|
AppSettingsEntity(doneColor.value, leftColor.value);
|
||||||
|
|
||||||
|
static AppSettings fromEntity(AppSettingsEntity entity) => AppSettings(
|
||||||
|
doneColor: Color(entity.doneColorValue),
|
||||||
|
leftColor: Color(entity.leftColorValue));
|
||||||
|
}
|
@ -1,36 +1,40 @@
|
|||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.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';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class AppState {
|
class AppState {
|
||||||
final bool hasLoaded;
|
final bool hasProgressesLoaded, hasSettingsLoaded;
|
||||||
final List<TimeProgress> timeProgressList;
|
final List<TimeProgress> timeProgressList;
|
||||||
|
final AppSettings appSettings;
|
||||||
|
|
||||||
AppState({
|
AppState(
|
||||||
this.hasLoaded = false,
|
{this.hasProgressesLoaded = false,
|
||||||
|
this.hasSettingsLoaded = false,
|
||||||
this.timeProgressList = const [],
|
this.timeProgressList = const [],
|
||||||
});
|
this.appSettings});
|
||||||
|
|
||||||
factory AppState.initial() => AppState(hasLoaded: false);
|
factory AppState.initial() =>
|
||||||
|
AppState(hasProgressesLoaded: false, appSettings: AppSettings.defaults());
|
||||||
|
|
||||||
AppState copyWith({
|
AppState copyWith({
|
||||||
bool hasLoaded,
|
bool hasLoaded,
|
||||||
List<TimeProgress> timeProgressList,
|
List<TimeProgress> timeProgressList,
|
||||||
}) {
|
}) {
|
||||||
return AppState(
|
return AppState(
|
||||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
hasProgressesLoaded: hasLoaded ?? this.hasProgressesLoaded,
|
||||||
timeProgressList: timeProgressList ?? this.timeProgressList,
|
timeProgressList: timeProgressList ?? this.timeProgressList,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => hasLoaded.hashCode ^ timeProgressList.hashCode;
|
int get hashCode => hasProgressesLoaded.hashCode ^ timeProgressList.hashCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is AppState &&
|
other is AppState &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
hasLoaded == other.hasLoaded &&
|
hasProgressesLoaded == other.hasProgressesLoaded &&
|
||||||
timeProgressList == other.timeProgressList;
|
timeProgressList == other.timeProgressList;
|
||||||
}
|
}
|
||||||
|
@ -20,26 +20,19 @@ class TimeProgress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TimeProgress copyWith(
|
TimeProgress copyWith(
|
||||||
{String id, String name, DateTime startTime, DateTime endTime}) {
|
{String id, String name, DateTime startTime, DateTime endTime}) =>
|
||||||
return TimeProgress(
|
TimeProgress(
|
||||||
name ?? this.name,
|
name ?? this.name,
|
||||||
startTime ?? this.startTime,
|
startTime ?? this.startTime,
|
||||||
endTime ?? this.endTime,
|
endTime ?? this.endTime,
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
int daysBehind() {
|
int daysBehind() => DateTime.now().difference(startTime).inDays;
|
||||||
return DateTime.now().difference(startTime).inDays;
|
|
||||||
}
|
|
||||||
|
|
||||||
int daysLeft() {
|
int daysLeft() => endTime.difference(DateTime.now()).inDays;
|
||||||
return endTime.difference(DateTime.now()).inDays;
|
|
||||||
}
|
|
||||||
|
|
||||||
int allDays() {
|
int allDays() => endTime.difference(startTime).inDays;
|
||||||
return endTime.difference(startTime).inDays;
|
|
||||||
}
|
|
||||||
|
|
||||||
double percentDone() {
|
double percentDone() {
|
||||||
double percent = this.daysBehind() / (this.allDays() / 100) / 100;
|
double percent = this.daysBehind() / (this.allDays() / 100) / 100;
|
||||||
@ -48,15 +41,11 @@ class TimeProgress {
|
|||||||
return percent;
|
return percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasStarted() {
|
bool hasStarted() =>
|
||||||
return DateTime.now().millisecondsSinceEpoch >
|
DateTime.now().millisecondsSinceEpoch > startTime.millisecondsSinceEpoch;
|
||||||
startTime.millisecondsSinceEpoch;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasEnded() {
|
bool hasEnded() =>
|
||||||
return DateTime.now().millisecondsSinceEpoch >
|
DateTime.now().millisecondsSinceEpoch > endTime.millisecondsSinceEpoch;
|
||||||
endTime.millisecondsSinceEpoch;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
@ -73,9 +62,8 @@ class TimeProgress {
|
|||||||
endTime == other.endTime;
|
endTime == other.endTime;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() =>
|
||||||
return "TimeProgress{id: $id, name: $name, startTime: $startTime, endTime: $endTime}";
|
"TimeProgress{id: $id, name: $name, startTime: $startTime, endTime: $endTime}";
|
||||||
}
|
|
||||||
|
|
||||||
TimeProgressEntity toEntity() {
|
TimeProgressEntity toEntity() {
|
||||||
if (!TimeProgress.isNameValid(name))
|
if (!TimeProgress.isNameValid(name))
|
||||||
@ -86,25 +74,17 @@ class TimeProgress {
|
|||||||
return TimeProgressEntity(id, name, startTime, endTime);
|
return TimeProgressEntity(id, name, startTime, endTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TimeProgress fromEntity(TimeProgressEntity entity) {
|
static TimeProgress fromEntity(TimeProgressEntity entity) =>
|
||||||
return TimeProgress(
|
TimeProgress(entity.name, entity.startTime, entity.endTime,
|
||||||
entity.name,
|
id: entity.id ?? Uuid().generateV4());
|
||||||
entity.startTime,
|
|
||||||
entity.endTime,
|
|
||||||
id: entity.id ?? Uuid().generateV4(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isValid(TimeProgress tp) {
|
static bool isValid(TimeProgress tp) =>
|
||||||
return TimeProgress.isNameValid(tp.name) &&
|
TimeProgress.isNameValid(tp.name) &&
|
||||||
TimeProgress.areTimesValid(tp.startTime, tp.endTime);
|
TimeProgress.areTimesValid(tp.startTime, tp.endTime);
|
||||||
}
|
|
||||||
|
|
||||||
static bool isNameValid(String name) {
|
static bool isNameValid(String name) =>
|
||||||
return name != null && name != "" && name.length > 2 && name.length < 21;
|
name != null && name != "" && name.length > 2 && name.length < 21;
|
||||||
}
|
|
||||||
|
|
||||||
static bool areTimesValid(DateTime startTime, DateTime endTime) {
|
static bool areTimesValid(DateTime startTime, DateTime endTime) =>
|
||||||
return startTime.isBefore(endTime);
|
startTime.isBefore(endTime);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
49
lib/persistence/app_settings.dart
Normal file
49
lib/persistence/app_settings.dart
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:time_progress_tracker/models/app_settings.dart';
|
||||||
|
|
||||||
|
class AppSettingsRepository {
|
||||||
|
static const String _key = "app_settings";
|
||||||
|
final SharedPreferences prefs;
|
||||||
|
final JsonCodec codec;
|
||||||
|
|
||||||
|
AppSettingsRepository(this.prefs, {this.codec = json});
|
||||||
|
|
||||||
|
Future<AppSettingsEntity> loadAppSettings() {
|
||||||
|
final String jsonString = this.prefs.getString(_key);
|
||||||
|
if (jsonString == null)
|
||||||
|
return Future<AppSettingsEntity>.value(AppSettingsEntity.defaults());
|
||||||
|
return Future<AppSettingsEntity>.value(
|
||||||
|
AppSettingsEntity.fromJson(codec.decode(jsonString)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> saveAppSettings(AppSettingsEntity appSettings) =>
|
||||||
|
this.prefs.setString(_key, codec.encode(appSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppSettingsEntity {
|
||||||
|
static const String _doneKey = "doneColorValue", _leftKey = "leftColorValue";
|
||||||
|
final int doneColorValue, leftColorValue;
|
||||||
|
|
||||||
|
AppSettingsEntity(this.doneColorValue, this.leftColorValue);
|
||||||
|
|
||||||
|
factory AppSettingsEntity.defaults() => AppSettings.defaults().toEntity();
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => doneColorValue.hashCode ^ leftColorValue.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is AppSettingsEntity &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
doneColorValue == other.doneColorValue &&
|
||||||
|
leftColorValue == other.leftColorValue;
|
||||||
|
|
||||||
|
Map<String, Object> toJson() =>
|
||||||
|
{_doneKey: doneColorValue, _leftKey: leftColorValue};
|
||||||
|
|
||||||
|
static AppSettingsEntity fromJson(Map<String, Object> json) =>
|
||||||
|
AppSettingsEntity(json[_doneKey], json[_leftKey]);
|
||||||
|
}
|
@ -2,8 +2,6 @@ import 'dart:convert';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:time_progress_tracker/persistence/time_progress_entity.dart';
|
import 'package:time_progress_tracker/persistence/time_progress_entity.dart';
|
||||||
|
|
||||||
import 'dart:developer' as developer;
|
|
||||||
|
|
||||||
class TimeProgressRepository {
|
class TimeProgressRepository {
|
||||||
static const String _key = "time_progress_repo";
|
static const String _key = "time_progress_repo";
|
||||||
final SharedPreferences prefs;
|
final SharedPreferences prefs;
|
||||||
|
@ -1,10 +1,32 @@
|
|||||||
|
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/app_state.dart';
|
||||||
import 'package:time_progress_tracker/reducers/has_loaded_reducer.dart';
|
import 'package:time_progress_tracker/reducers/has_loaded_reducer.dart';
|
||||||
import 'package:time_progress_tracker/reducers/time_progress_list_reducer.dart';
|
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(
|
||||||
hasLoaded: hasLoadedReducer(state.hasLoaded, action),
|
hasProgressesLoaded: hasLoadedReducer(state.hasProgressesLoaded, action),
|
||||||
timeProgressList: timeProgressListReducer(state.timeProgressList, action),
|
timeProgressList: timeProgressListReducer(state.timeProgressList, action),
|
||||||
|
appSettings: appSettingsReducers(state.appSettings, action),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final appSettingsReducers = combineReducers<AppSettings>([
|
||||||
|
TypedReducer<AppSettings, AppSettingsLoadedActions>(_loadAppSettings),
|
||||||
|
TypedReducer<AppSettings, UpdateAppSettingsActions>(_updateAppSettings),
|
||||||
|
TypedReducer<AppSettings, AppSettingsNotLoadedAction>(_setDefaultSettings)
|
||||||
|
]);
|
||||||
|
|
||||||
|
AppSettings _loadAppSettings(
|
||||||
|
AppSettings appSettings, AppSettingsLoadedActions nS) =>
|
||||||
|
nS.appSettings;
|
||||||
|
|
||||||
|
AppSettings _setDefaultSettings(
|
||||||
|
AppSettings appSettings, AppSettingsNotLoadedAction action) =>
|
||||||
|
AppSettings.defaults();
|
||||||
|
|
||||||
|
AppSettings _updateAppSettings(
|
||||||
|
AppSettings appSettings, UpdateAppSettingsActions nS) =>
|
||||||
|
nS.appSettings;
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
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';
|
||||||
|
import 'package:time_progress_tracker/models/app_settings.dart';
|
||||||
import 'package:time_progress_tracker/models/app_state.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';
|
||||||
@ -76,8 +77,17 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
|
|||||||
|
|
||||||
List<Widget> columnChildren = [
|
List<Widget> columnChildren = [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ProgressViewWidget(
|
child: StoreConnector<AppState, AppSettings>(
|
||||||
timeProgress: _editMode ? _editedProgress : timeProgress),
|
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)
|
if (_editMode)
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:time_progress_tracker/models/app_settings.dart';
|
||||||
import 'package:time_progress_tracker/models/app_state.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';
|
||||||
|
|
||||||
@ -47,3 +50,9 @@ TimeProgress timeProgressByIdSelector(AppState state, String id) {
|
|||||||
return state.timeProgressList
|
return state.timeProgressList
|
||||||
.firstWhere((timeProgress) => timeProgress.id == id, orElse: () => null);
|
.firstWhere((timeProgress) => timeProgress.id == id, orElse: () => null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppSettings appSettingsSelector(AppState state) {
|
||||||
|
return state.appSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color doneColorSelector(AppState state) => state.appSettings.doneColor;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
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';
|
||||||
@ -6,21 +5,27 @@ import 'package:time_progress_tracker/screens/progress_detail_screen.dart';
|
|||||||
|
|
||||||
class HomeProgressListTile extends StatelessWidget {
|
class HomeProgressListTile extends StatelessWidget {
|
||||||
final TimeProgress timeProgress;
|
final TimeProgress timeProgress;
|
||||||
|
final Color doneColor;
|
||||||
|
final Color leftColor;
|
||||||
|
|
||||||
HomeProgressListTile({
|
HomeProgressListTile({
|
||||||
Key key,
|
|
||||||
@required this.timeProgress,
|
@required this.timeProgress,
|
||||||
}) : super(key: key);
|
@required this.doneColor,
|
||||||
|
@required this.leftColor,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget listTileSubTitle;
|
Widget listTileSubTitle;
|
||||||
if (timeProgress.hasStarted() && !timeProgress.hasEnded())
|
if (timeProgress.hasStarted() && !timeProgress.hasEnded())
|
||||||
listTileSubTitle = LinearPercentIndicator(
|
listTileSubTitle = LinearPercentIndicator(
|
||||||
center: Text("${(timeProgress.percentDone() * 100).floor()} %"),
|
center: Text(
|
||||||
|
"${(timeProgress.percentDone() * 100).floor()} %",
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
percent: timeProgress.percentDone(),
|
percent: timeProgress.percentDone(),
|
||||||
progressColor: Colors.green,
|
progressColor: doneColor,
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: leftColor,
|
||||||
lineHeight: 20,
|
lineHeight: 20,
|
||||||
);
|
);
|
||||||
if (!timeProgress.hasStarted())
|
if (!timeProgress.hasStarted())
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:time_progress_tracker/actions/actions.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/selectors/time_progress_selectors.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/home_progress_list_tile.dart';
|
import 'package:time_progress_tracker/widgets/home/home_progress_list_tile.dart';
|
||||||
@ -10,16 +12,21 @@ class HomeActiveProgressesTab extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StoreConnector(
|
return StoreConnector(
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
onInit: loadTimeProgressListIfUnloaded,
|
||||||
converter: (store) => store.state.hasLoaded,
|
converter: (store) => store.state.hasProgressesLoaded,
|
||||||
builder: (BuildContext context, dynamic hasLoaded) {
|
builder: (context, hasLoaded) {
|
||||||
if (!(hasLoaded as bool))
|
if (!(hasLoaded as bool))
|
||||||
return Center(
|
return Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
);
|
);
|
||||||
return StoreConnector(
|
return StoreConnector<AppState, AppSettings>(
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
onInit: loadSettingsIfUnloaded,
|
||||||
|
converter: (store) => appSettingsSelector(store.state),
|
||||||
|
builder: (context, AppSettings settings) {
|
||||||
|
if (settings == null)
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
return StoreConnector<AppState, List<TimeProgress>>(
|
||||||
converter: (store) => activeTimeProgressesSelector(store.state),
|
converter: (store) => activeTimeProgressesSelector(store.state),
|
||||||
builder: (BuildContext context, List<TimeProgress> timeProgresses) {
|
builder: (context, List<TimeProgress> timeProgresses) {
|
||||||
if (timeProgresses.length < 1)
|
if (timeProgresses.length < 1)
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
@ -33,6 +40,8 @@ class HomeActiveProgressesTab extends StatelessWidget {
|
|||||||
children: timeProgresses
|
children: timeProgresses
|
||||||
.map((timeProgress) => HomeProgressListTile(
|
.map((timeProgress) => HomeProgressListTile(
|
||||||
timeProgress: timeProgress,
|
timeProgress: timeProgress,
|
||||||
|
doneColor: settings.doneColor,
|
||||||
|
leftColor: settings.leftColor,
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
@ -40,5 +49,7 @@ class HomeActiveProgressesTab extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:time_progress_tracker/actions/actions.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/selectors/time_progress_selectors.dart';
|
||||||
import 'package:time_progress_tracker/widgets/home/home_progress_list_tile.dart';
|
import 'package:time_progress_tracker/widgets/home/home_progress_list_tile.dart';
|
||||||
@ -8,9 +9,13 @@ import 'package:time_progress_tracker/widgets/home/home_progress_list_tile.dart'
|
|||||||
class HomeInactiveProgressesTab extends StatelessWidget {
|
class HomeInactiveProgressesTab extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
return StoreConnector(
|
||||||
|
onInit: loadSettingsIfUnloaded,
|
||||||
|
converter: (store) => appSettingsSelector(store.state),
|
||||||
|
builder: (context, AppSettings settings) {
|
||||||
return StoreConnector(
|
return StoreConnector(
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
onInit: loadTimeProgressListIfUnloaded,
|
||||||
converter: (store) => store.state.hasLoaded,
|
converter: (store) => store.state.hasProgressesLoaded,
|
||||||
builder: (BuildContext context, dynamic hasLoaded) {
|
builder: (BuildContext context, dynamic hasLoaded) {
|
||||||
if (!(hasLoaded as bool))
|
if (!(hasLoaded as bool))
|
||||||
return Center(
|
return Center(
|
||||||
@ -19,7 +24,8 @@ class HomeInactiveProgressesTab extends StatelessWidget {
|
|||||||
return StoreConnector(
|
return StoreConnector(
|
||||||
onInit: loadTimeProgressListIfUnloaded,
|
onInit: loadTimeProgressListIfUnloaded,
|
||||||
converter: (store) => inactiveTimeProgressesSelector(store.state),
|
converter: (store) => inactiveTimeProgressesSelector(store.state),
|
||||||
builder: (BuildContext context, List<TimeProgress> timeProgresses) {
|
builder:
|
||||||
|
(BuildContext context, List<TimeProgress> timeProgresses) {
|
||||||
if (timeProgresses.length < 1)
|
if (timeProgresses.length < 1)
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
@ -31,13 +37,18 @@ class HomeInactiveProgressesTab extends StatelessWidget {
|
|||||||
return ListView(
|
return ListView(
|
||||||
padding: EdgeInsets.all(8),
|
padding: EdgeInsets.all(8),
|
||||||
children: timeProgresses
|
children: timeProgresses
|
||||||
.map((timeProgress) =>
|
.map((timeProgress) => HomeProgressListTile(
|
||||||
HomeProgressListTile(timeProgress: timeProgress))
|
timeProgress: timeProgress,
|
||||||
|
doneColor: settings.doneColor,
|
||||||
|
leftColor: settings.leftColor,
|
||||||
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,62 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:package_info/package_info.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';
|
||||||
|
|
||||||
class HomeSettingsTab extends StatelessWidget {
|
class HomeSettingsTab extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
return StoreConnector<AppState, AppSettings>(
|
||||||
|
onInit: loadSettingsIfUnloaded,
|
||||||
|
converter: (store) => appSettingsSelector(store.state),
|
||||||
|
builder: (context, AppSettings settings) {
|
||||||
|
Store<AppState> store = StoreProvider.of<AppState>(context);
|
||||||
|
void updateDoneColor(Color newDoneColor) => store.dispatch(
|
||||||
|
UpdateAppSettingsActions(
|
||||||
|
settings.copyWith(doneColor: newDoneColor)),
|
||||||
|
);
|
||||||
|
void updateLeftColor(Color newLeftColor) => store.dispatch(
|
||||||
|
UpdateAppSettingsActions(
|
||||||
|
settings.copyWith(leftColor: newLeftColor)),
|
||||||
|
);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text("The Settings of this App are not yet implemented."),
|
Expanded(
|
||||||
FlatButton(
|
child: ColorSettingsWidget(
|
||||||
|
doneColor: settings.doneColor,
|
||||||
|
leftColor: settings.leftColor,
|
||||||
|
updateDoneColor: updateDoneColor,
|
||||||
|
updateLeftColor: updateLeftColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Expanded(
|
||||||
|
child: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showAboutDialog(
|
showAboutDialog(
|
||||||
context: context,
|
context: context,
|
||||||
applicationName: TimeProgressTrackerApp.name,
|
applicationName: TimeProgressTrackerApp.name,
|
||||||
applicationVersion: "Beta",
|
applicationVersion: "Beta",
|
||||||
applicationLegalese: '\u00a9Andreas Fahrecker 2020-2021');
|
applicationLegalese:
|
||||||
|
'\u00a9Andreas Fahrecker 2020-2021');
|
||||||
},
|
},
|
||||||
child: Text("About"))
|
child: Text("About"),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
lib/widgets/home/tabs/settings/color_picker_btn.dart
Normal file
49
lib/widgets/home/tabs/settings/color_picker_btn.dart
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
|
||||||
|
|
||||||
|
class ColorPickerButton extends StatelessWidget {
|
||||||
|
final String title, dialogTitle;
|
||||||
|
final Color selectedColor;
|
||||||
|
final void Function(Color) onColorPicked;
|
||||||
|
|
||||||
|
ColorPickerButton({
|
||||||
|
@required this.title,
|
||||||
|
@required this.dialogTitle,
|
||||||
|
@required this.selectedColor,
|
||||||
|
@required this.onColorPicked,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color getBtnPrimaryColor() => Color.fromARGB(
|
||||||
|
selectedColor.alpha,
|
||||||
|
selectedColor.alpha - selectedColor.red,
|
||||||
|
selectedColor.alpha - selectedColor.green,
|
||||||
|
selectedColor.alpha - selectedColor.blue,
|
||||||
|
);
|
||||||
|
|
||||||
|
return TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(dialogTitle),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: BlockPicker(
|
||||||
|
pickerColor: selectedColor,
|
||||||
|
onColorChanged: onColorPicked,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text(title),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
primary: getBtnPrimaryColor(),
|
||||||
|
backgroundColor: selectedColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
55
lib/widgets/home/tabs/settings/color_settings_widget.dart
Normal file
55
lib/widgets/home/tabs/settings/color_settings_widget.dart
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:time_progress_tracker/widgets/home/tabs/settings/color_picker_btn.dart';
|
||||||
|
|
||||||
|
class ColorSettingsWidget extends StatelessWidget {
|
||||||
|
final Color doneColor, leftColor;
|
||||||
|
final void Function(Color) updateDoneColor, updateLeftColor;
|
||||||
|
|
||||||
|
ColorSettingsWidget({
|
||||||
|
@required this.doneColor,
|
||||||
|
@required this.leftColor,
|
||||||
|
@required this.updateDoneColor,
|
||||||
|
@required this.updateLeftColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Color Settings",
|
||||||
|
style:
|
||||||
|
TextStyle(fontWeight: FontWeight.bold, color: Colors.black87),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(right: 5),
|
||||||
|
child: ColorPickerButton(
|
||||||
|
title: "Done Color",
|
||||||
|
dialogTitle: "Select Done Color",
|
||||||
|
selectedColor: doneColor,
|
||||||
|
onColorPicked: updateDoneColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(left: 5),
|
||||||
|
child: ColorPickerButton(
|
||||||
|
title: "Left Color",
|
||||||
|
dialogTitle: "Select Left Color",
|
||||||
|
selectedColor: leftColor,
|
||||||
|
onColorPicked: updateLeftColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
39
lib/widgets/home/tabs/settings/direct_select_item.dart
Normal file
39
lib/widgets/home/tabs/settings/direct_select_item.dart
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class DirectSelectItem extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final bool isForList;
|
||||||
|
|
||||||
|
DirectSelectItem({this.title, this.isForList});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 60,
|
||||||
|
child: isForList
|
||||||
|
? Padding(
|
||||||
|
child: _buildItem(context),
|
||||||
|
padding: EdgeInsets.all(10),
|
||||||
|
)
|
||||||
|
: Card(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
_buildItem(context),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: Icon(Icons.arrow_drop_down),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Container _buildItem(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(title),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,13 @@ import 'package:time_progress_tracker/models/time_progress.dart';
|
|||||||
|
|
||||||
class ProgressViewWidget extends StatelessWidget {
|
class ProgressViewWidget extends StatelessWidget {
|
||||||
final TimeProgress timeProgress;
|
final TimeProgress timeProgress;
|
||||||
|
final Color doneColor;
|
||||||
|
final Color leftColor;
|
||||||
|
|
||||||
ProgressViewWidget({
|
ProgressViewWidget({
|
||||||
@required this.timeProgress,
|
@required this.timeProgress,
|
||||||
|
@required this.doneColor,
|
||||||
|
@required this.leftColor,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -33,8 +37,8 @@ class ProgressViewWidget extends StatelessWidget {
|
|||||||
radius: 100,
|
radius: 100,
|
||||||
lineWidth: 10,
|
lineWidth: 10,
|
||||||
percent: timeProgress.percentDone(),
|
percent: timeProgress.percentDone(),
|
||||||
progressColor: Colors.green,
|
progressColor: doneColor,
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: leftColor,
|
||||||
center: Text("${(timeProgress.percentDone() * 100).floor()} %"),
|
center: Text("${(timeProgress.percentDone() * 100).floor()} %"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -43,10 +47,13 @@ class ProgressViewWidget extends StatelessWidget {
|
|||||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||||
percent: timeProgress.percentDone(),
|
percent: timeProgress.percentDone(),
|
||||||
leading: Text("${timeProgress.daysBehind()} Days"),
|
leading: Text("${timeProgress.daysBehind()} Days"),
|
||||||
center: Text("${(timeProgress.percentDone() * 100).floor()} %"),
|
center: Text(
|
||||||
|
"${(timeProgress.percentDone() * 100).floor()} %",
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
trailing: Text("${timeProgress.daysLeft()} Days"),
|
trailing: Text("${timeProgress.daysLeft()} Days"),
|
||||||
progressColor: Colors.green,
|
progressColor: doneColor,
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: leftColor,
|
||||||
lineHeight: 25,
|
lineHeight: 25,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
14
pubspec.lock
14
pubspec.lock
@ -78,6 +78,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.3"
|
version: "0.1.3"
|
||||||
|
direct_select:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: direct_select
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -104,6 +111,13 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_colorpicker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_colorpicker
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.5"
|
||||||
flutter_launcher_icons:
|
flutter_launcher_icons:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -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.14+14
|
version: 0.0.17+17
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.7.0 <3.0.0"
|
sdk: ">=2.7.0 <3.0.0"
|
||||||
@ -23,7 +23,9 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_colorpicker:
|
||||||
flutter_redux:
|
flutter_redux:
|
||||||
|
direct_select:
|
||||||
meta:
|
meta:
|
||||||
package_info:
|
package_info:
|
||||||
percent_indicator:
|
percent_indicator:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user