Compare commits

...

8 Commits

Author SHA1 Message Date
3940184975 Fix Displaying Bug 2024-05-14 20:58:22 +02:00
eee1d12851 Fix Version Name for new Release 2024-03-15 23:05:33 +01:00
e11a73d37e Fixed Android Label 2024-03-15 23:02:13 +01:00
ead31e12c0 Fixed Remaining Migration Errors 2024-03-15 22:47:43 +01:00
421d19f91f Fixed Remaining Problems 2024-03-15 21:09:16 +01:00
3085a295e5 Fixed Simple Problem, that occured after migrating to new version.
Still WIP need to fix more Problems
2024-03-15 07:05:10 +01:00
c12ba48e15 Used Flutter Migrate tool and fixed flutter_picker in pubspec.yaml 2024-03-15 04:34:08 +01:00
Andreas Fahrecker
d2b4b6ee71 Created Project readme
Signed-off-by: Andreas Fahrecker <AndreasFahrecker@gmail.com>
2021-03-12 00:29:58 +01:00
65 changed files with 908 additions and 615 deletions

104
.gitignore vendored
View File

@ -1,6 +1,5 @@
# Miscellaneous
*.class
*.lock
*.log
*.pyc
*.swp
@ -9,6 +8,7 @@
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
@ -16,102 +16,28 @@
*.iws
.idea/
# Visual Studio Code related
.classpath
.project
.settings/
.vscode/
# Flutter repo-specific
/bin/cache/
/bin/internal/bootstrap.bat
/bin/internal/bootstrap.sh
/bin/mingit/
/dev/benchmarks/mega_gallery/
/dev/bots/.recipe_deps
/dev/bots/android_tools/
/dev/devicelab/ABresults*.json
/dev/docs/doc/
/dev/docs/flutter.docs.zip
/dev/docs/lib/
/dev/docs/pubspec.yaml
/dev/integration_tests/**/xcuserdata
/dev/integration_tests/**/Pods
/packages/flutter/coverage/
version
analysis_benchmark.json
# packages file containing multi-root paths
.packages.generated
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
**/generated_plugin_registrant.dart
.packages
.pub-cache/
.pub/
build/
flutter_*.png
linked_*.ds
unlinked.ds
unlinked_spec.ds
/build/
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
*.jks
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/.last_build_id
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# macOS
**/macos/Flutter/GeneratedPluginRegistrant.swift
# Coverage
coverage/
# Symbols
# Symbolication related
app.*.symbols
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

View File

@ -4,7 +4,42 @@
# This file should be version controlled and should not be manually edited.
version:
revision: fba99f6cf9a14512e461e3122c8ddfaa25394e89
channel: stable
revision: "ba393198430278b6595976de84fe170f553cc728"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: android
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: ios
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: linux
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: macos
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: web
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: windows
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View File

@ -1,8 +1,32 @@
# time_progress_tracker
# Time Progress Tracker
A Flutter Application to create Timers with a percentage indicator.
The Idea for this Application came to me while, I was doing my civil service.
It is a really simple app at this state. You can enter Time Progresses, which are made up of
a name, a start date, and a end date.
Then you can see a list of all currently active and a list of all currently inactive progresses,
including their current percentages.
## Getting Started
## Current State of the repo.
Currently, the code in this branch is pretty messed up. Since I wrote that application from a
prototype which, was developed as my first flutter project and in a very short time.
Since, then most of the work that went into this project was cleanup work.
Currently I am working on a clean codebase in the feature/platform-widget branch.
At this state, the base screens of the app are located in lib/screens,
all other ui widgets are located in li/widgets,
the model classes are located in lib/model,
files related to persisting the data are in lib/persistence,
and redux related files are spread over lib/actions lib/middleware lib/reducers and lib/reducers.
- [Google Play](https://play.google.com/store/apps/details?id=com.fahrecker.time_progress_calculator)
## Original Readme
### Getting Started
This project is a starting point for a Flutter application.

28
analysis_options.yaml Normal file
View File

@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

2
android/.gitignore vendored
View File

@ -9,3 +9,5 @@ GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks

View File

@ -1,3 +1,9 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
@ -6,11 +12,6 @@ if (localPropertiesFile.exists()) {
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
@ -21,10 +22,6 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
@ -32,21 +29,30 @@ if (keystorePropertiesFile.exists()) {
}
android {
compileSdkVersion 28
namespace "com.fahrecker.time_progress_calculator"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.fahrecker.time_progress_calculator"
minSdkVersion 16
targetSdkVersion 29
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
@ -71,6 +77,4 @@ flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
dependencies {}

View File

@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fahrecker.time_progress_calculator">
<!-- Flutter needs it to communicate with the running application
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>

View File

@ -1,16 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fahrecker.time_progress_calculator">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="Time Progress Tracker"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
@ -24,15 +20,6 @@
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@ -44,4 +31,15 @@
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility?hl=en and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

View File

@ -3,14 +3,14 @@
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>

View File

@ -1,18 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">@android:color/white</item>
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fahrecker.time_progress_calculator">
<!-- Flutter needs it to communicate with the running application
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>

View File

@ -1,20 +1,7 @@
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
@ -26,6 +13,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View File

@ -1,4 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true

View File

@ -1,6 +1,5 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip

View File

@ -1,11 +1,26 @@
include ':app'
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}
include ":app"

2
ios/.gitignore vendored
View File

@ -1,3 +1,4 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
@ -18,6 +19,7 @@ Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/

View File

@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
<string>12.0</string>
</dict>
</plist>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@ -38,8 +36,19 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -61,8 +70,6 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"

View File

@ -41,7 +41,9 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View File

@ -49,8 +49,9 @@ class DeleteTimeProgressAction {
}
void loadTimeProgressListIfUnloaded(Store<AppState> store) {
if (!store.state.hasProgressesLoaded)
if (!store.state.hasProgressesLoaded) {
store.dispatch(LoadTimeProgressListAction());
}
}
void loadSettingsIfUnloaded(Store<AppState> store) {

View File

@ -11,10 +11,10 @@ class TimeProgressTrackerApp extends StatelessWidget {
final Store<AppState> store;
TimeProgressTrackerApp({
Key key,
this.store,
}) : super(key: key);
const TimeProgressTrackerApp({
super.key,
required this.store,
});
@override
Widget build(BuildContext context) {
@ -24,18 +24,21 @@ class TimeProgressTrackerApp extends StatelessWidget {
title: name,
theme: ThemeData(
primarySwatch: Colors.indigo,
accentColor: Colors.indigoAccent,
colorScheme: ColorScheme.fromSwatch(
primarySwatch: Colors.indigo,
accentColor: Colors.indigoAccent,
backgroundColor: Colors.white
),
brightness: Brightness.light,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
initialRoute: HomeScreen.routeName,
routes: {
HomeScreen.routeName: (BuildContext context) =>
HomeScreen(),
HomeScreen.routeName: (BuildContext context) => const HomeScreen(),
ProgressDetailScreen.routeName: (BuildContext context) =>
ProgressDetailScreen(),
const ProgressDetailScreen(),
ProgressCreationScreen.routeName: (BuildContext context) =>
ProgressCreationScreen(),
const ProgressCreationScreen(),
},
),
);

View File

@ -3,7 +3,7 @@ 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);
tpList.firstWhere((tp) => tp.id == id, orElse: () => TimeProgress.initialDefault());
List<TimeProgress> selectActiveProgresses(List<TimeProgress> tpList) =>
tpList.where((tp) => tp.hasStarted() && !tp.hasEnded()).toList();

View File

@ -17,12 +17,12 @@ List<Middleware<AppState>> createStoreMiddleware(
final loadSettings = _createLoadAppSettings(settingsRepo);
return [
TypedMiddleware<AppState, LoadTimeProgressListAction>(loadTimeProgressList),
TypedMiddleware<AppState, AddTimeProgressAction>(saveTimeProgressList),
TypedMiddleware<AppState, UpdateTimeProgressAction>(saveTimeProgressList),
TypedMiddleware<AppState, DeleteTimeProgressAction>(saveTimeProgressList),
TypedMiddleware<AppState, LoadSettingsAction>(loadSettings),
TypedMiddleware<AppState, UpdateAppSettingsActions>(saveSettings)
TypedMiddleware<AppState, LoadTimeProgressListAction>(loadTimeProgressList).call,
TypedMiddleware<AppState, AddTimeProgressAction>(saveTimeProgressList).call,
TypedMiddleware<AppState, UpdateTimeProgressAction>(saveTimeProgressList).call,
TypedMiddleware<AppState, DeleteTimeProgressAction>(saveTimeProgressList).call,
TypedMiddleware<AppState, LoadSettingsAction>(loadSettings).call,
TypedMiddleware<AppState, UpdateAppSettingsActions>(saveSettings).call
];
}
@ -45,9 +45,6 @@ Middleware<AppState> _createLoadTimeProgressList(
repository.loadTimeProgressList().then((timeProgresses) {
List<TimeProgress> timeProgressList =
timeProgresses.map<TimeProgress>(TimeProgress.fromEntity).toList();
if (timeProgressList == null) {
timeProgressList = [];
}
store.dispatch(TimeProgressListLoadedAction(
timeProgressList,
));

View File

@ -1,5 +1,5 @@
class TimeProgressInvalidNameException implements Exception {
final invalidName;
final String invalidName;
TimeProgressInvalidNameException(this.invalidName);
@ -7,8 +7,8 @@ class TimeProgressInvalidNameException implements Exception {
}
class TimeProgressStartTimeIsNotBeforeEndTimeException implements Exception {
final startTime;
final endTime;
final DateTime startTime;
final DateTime endTime;
TimeProgressStartTimeIsNotBeforeEndTimeException(
this.startTime, this.endTime);

View File

@ -7,22 +7,22 @@ class AppSettings {
final Color leftColor;
final Duration duration;
AppSettings({
this.doneColor,
this.leftColor,
this.duration,
const AppSettings({
required this.doneColor,
required this.leftColor,
required this.duration,
});
factory AppSettings.defaults() => AppSettings(
factory AppSettings.defaults() => const AppSettings(
doneColor: Colors.green,
leftColor: Colors.red,
duration: Duration(days: 365),
);
AppSettings copyWith({
Color doneColor,
Color leftColor,
Duration duration,
Color? doneColor,
Color? leftColor,
Duration? duration,
}) =>
AppSettings(
doneColor: doneColor ?? this.doneColor,

View File

@ -8,22 +8,24 @@ class AppState {
final List<TimeProgress> timeProgressList;
final AppSettings appSettings;
AppState(
const AppState(
{this.hasProgressesLoaded = false,
this.hasSettingsLoaded = false,
this.timeProgressList = const [],
this.appSettings});
required this.appSettings});
factory AppState.initial() =>
AppState(hasProgressesLoaded: false, appSettings: AppSettings.defaults());
AppState copyWith({
bool hasLoaded,
List<TimeProgress> timeProgressList,
bool? hasLoaded,
List<TimeProgress>? timeProgressList,
AppSettings? appSettings,
}) {
return AppState(
hasProgressesLoaded: hasLoaded ?? this.hasProgressesLoaded,
hasProgressesLoaded: hasLoaded ?? hasProgressesLoaded,
timeProgressList: timeProgressList ?? this.timeProgressList,
appSettings: appSettings ?? this.appSettings,
);
}

View File

@ -10,7 +10,7 @@ class TimeProgress {
final DateTime startTime;
final DateTime endTime;
TimeProgress(this.name, this.startTime, this.endTime, {String id})
TimeProgress(this.name, this.startTime, this.endTime, {String? id})
: id = id ?? Uuid().generateV4();
factory TimeProgress.initialDefault() {
@ -23,7 +23,7 @@ class TimeProgress {
TimeProgress("", DateTime.now(), DateTime.now().add(duration));
TimeProgress copyWith(
{String id, String name, DateTime startTime, DateTime endTime}) =>
{String? id, String? name, DateTime? startTime, DateTime? endTime}) =>
TimeProgress(
name ?? this.name,
startTime ?? this.startTime,
@ -38,7 +38,7 @@ class TimeProgress {
int allDays() => endTime.difference(startTime).inDays;
double percentDone() {
double percent = this.daysBehind() / (this.allDays() / 100) / 100;
double percent = daysBehind() / (allDays() / 100) / 100;
if (percent < 0) percent = 0;
if (percent > 1) percent = 1;
return percent;
@ -48,7 +48,7 @@ class TimeProgress {
DateTime.now().millisecondsSinceEpoch > startTime.millisecondsSinceEpoch;
int daysTillStart() {
if (hasStarted()) throw new TimeProgressHasStartedException();
if (hasStarted()) throw TimeProgressHasStartedException();
return startTime.difference(DateTime.now()).inDays;
}
@ -56,7 +56,7 @@ class TimeProgress {
DateTime.now().millisecondsSinceEpoch > endTime.millisecondsSinceEpoch;
int daysSinceEnd() {
if (!hasEnded()) throw new TimeProgressHasNotEndedException();
if (!hasEnded()) throw TimeProgressHasNotEndedException();
return DateTime.now().difference(endTime).inDays;
}
@ -79,24 +79,26 @@ class TimeProgress {
"TimeProgress{id: $id, name: $name, startTime: $startTime, endTime: $endTime}";
TimeProgressEntity toEntity() {
if (!TimeProgress.isNameValid(name))
throw new TimeProgressInvalidNameException(name);
if (!TimeProgress.areTimesValid(startTime, endTime))
throw new TimeProgressStartTimeIsNotBeforeEndTimeException(
if (!TimeProgress.isNameValid(name)) {
throw TimeProgressInvalidNameException(name);
}
if (!TimeProgress.areTimesValid(startTime, endTime)) {
throw TimeProgressStartTimeIsNotBeforeEndTimeException(
startTime, endTime);
}
return TimeProgressEntity(id, name, startTime, endTime);
}
static TimeProgress fromEntity(TimeProgressEntity entity) =>
TimeProgress(entity.name, entity.startTime, entity.endTime,
id: entity.id ?? Uuid().generateV4());
id: entity.id);
static bool isValid(TimeProgress tp) =>
TimeProgress.isNameValid(tp.name) &&
TimeProgress.areTimesValid(tp.startTime, tp.endTime);
static bool isNameValid(String name) =>
name != null && name != "" && name.length > 2 && name.length < 21;
name != "" && name.length > 2 && name.length < 21;
static bool areTimesValid(DateTime startTime, DateTime endTime) =>
startTime.isBefore(endTime);

View File

@ -11,15 +11,16 @@ class AppSettingsRepository {
AppSettingsRepository(this.prefs, {this.codec = json});
Future<AppSettingsEntity> loadAppSettings() {
final String jsonString = this.prefs.getString(_key);
if (jsonString == null)
final String? jsonString = 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));
prefs.setString(_key, codec.encode(appSettings));
}
class AppSettingsEntity {
@ -52,8 +53,8 @@ class AppSettingsEntity {
static AppSettingsEntity fromJson(Map<String, Object> json) =>
AppSettingsEntity(
json[_doneKey],
json[_leftKey],
json[_durationDaysKey],
json[_doneKey] as int,
json[_leftKey] as int,
json[_durationDaysKey] as int,
);
}

View File

@ -29,7 +29,7 @@ class TimeProgressEntity {
};
}
static TimeProgressEntity fromJson(Map<String, Object> json) {
static TimeProgressEntity fromJson(dynamic json) {
final String id = json["id"] as String;
final String name = json["name"] as String;
final DateTime startTime =

View File

@ -10,13 +10,12 @@ class TimeProgressRepository {
TimeProgressRepository(this.prefs, {this.codec = json});
Future<List<TimeProgressEntity>> loadTimeProgressList() {
final String jsonString = this.prefs.getString(_key);
final String? jsonString = prefs.getString(_key);
if (jsonString == null) {
return Future<List<TimeProgressEntity>>.value([]);
}
return Future<List<TimeProgressEntity>>.value(codec
.decode(jsonString)["timers"]
.cast<Map<String, Object>>()
.map<TimeProgressEntity>(TimeProgressEntity.fromJson)
.toList(growable: false));
}
@ -24,6 +23,6 @@ class TimeProgressRepository {
Future<bool> saveTimeProgressList(List<TimeProgressEntity> timeProgressList) {
final String jsonString = codec.encode(
{"timers": timeProgressList.map((timer) => timer.toJson()).toList()});
return this.prefs.setString(_key, jsonString);
return prefs.setString(_key, jsonString);
}
}

View File

@ -17,9 +17,9 @@ AppState appStateReducer(AppState state, dynamic action) {
}
final appSettingsReducers = combineReducers<AppSettings>([
TypedReducer<AppSettings, AppSettingsLoadedActions>(_loadAppSettings),
TypedReducer<AppSettings, UpdateAppSettingsActions>(_updateAppSettings),
TypedReducer<AppSettings, AppSettingsNotLoadedAction>(_setDefaultSettings)
TypedReducer<AppSettings, AppSettingsLoadedActions>(_loadAppSettings).call,
TypedReducer<AppSettings, UpdateAppSettingsActions>(_updateAppSettings).call,
TypedReducer<AppSettings, AppSettingsNotLoadedAction>(_setDefaultSettings).call
]);
AppSettings _loadAppSettings(

View File

@ -2,8 +2,8 @@ import 'package:redux/redux.dart';
import 'package:time_progress_tracker/actions/actions.dart';
final hasProgressesLoadedReducer = combineReducers<bool>([
TypedReducer<bool, TimeProgressListLoadedAction>(_setProgressesLoaded),
TypedReducer<bool, TimeProgressListNotLoadedAction>(_setProgressesUnloaded)
TypedReducer<bool, TimeProgressListLoadedAction>(_setProgressesLoaded).call,
TypedReducer<bool, TimeProgressListNotLoadedAction>(_setProgressesUnloaded).call
]);
bool _setProgressesLoaded(bool hasLoaded, TimeProgressListLoadedAction action) {
@ -15,8 +15,8 @@ bool _setProgressesUnloaded(bool hasLoaded, TimeProgressListNotLoadedAction acti
}
final hasSettingsLoadedReducer = combineReducers<bool>([
TypedReducer<bool, AppSettingsLoadedActions>(_setSettingsLoaded),
TypedReducer<bool, AppSettingsNotLoadedAction>(_setSettingsUnloaded)
TypedReducer<bool, AppSettingsLoadedActions>(_setSettingsLoaded).call,
TypedReducer<bool, AppSettingsNotLoadedAction>(_setSettingsUnloaded).call
]);
bool _setSettingsLoaded(bool hasLoaded, AppSettingsLoadedActions action) {

View File

@ -4,13 +4,13 @@ import 'package:time_progress_tracker/models/time_progress.dart';
final timeProgressListReducer = combineReducers<List<TimeProgress>>([
TypedReducer<List<TimeProgress>, TimeProgressListLoadedAction>(
_setLoadedTimeProgressList),
_setLoadedTimeProgressList).call,
TypedReducer<List<TimeProgress>, TimeProgressListNotLoadedAction>(
_setEmptyTimeProgressList),
TypedReducer<List<TimeProgress>, AddTimeProgressAction>(_addTimeProgress),
_setEmptyTimeProgressList).call,
TypedReducer<List<TimeProgress>, AddTimeProgressAction>(_addTimeProgress).call,
TypedReducer<List<TimeProgress>, UpdateTimeProgressAction>(
_updateTimeProgress),
TypedReducer<List<TimeProgress>, DeleteTimeProgressAction>(_deleteTimeProgress),
_updateTimeProgress).call,
TypedReducer<List<TimeProgress>, DeleteTimeProgressAction>(_deleteTimeProgress).call,
]);
List<TimeProgress> _setLoadedTimeProgressList(

View File

@ -9,6 +9,8 @@ class HomeScreen extends StatefulWidget {
static const routeName = "/home";
static const title = "Time Progress Tracker";
const HomeScreen({super.key});
@override
State<StatefulWidget> createState() {
return _HomeScreenState();
@ -18,9 +20,9 @@ class HomeScreen extends StatefulWidget {
class _HomeScreenState extends State<HomeScreen> {
int _currentIndex = 0;
final List<Widget> _children = [
HomeActiveProgressesTab(),
HomeInactiveProgressesTab(),
HomeSettingsTab(),
const HomeActiveProgressesTab(),
const HomeInactiveProgressesTab(),
const HomeSettingsTab(),
];
void onBottomTabTapped(int index) {
@ -31,13 +33,16 @@ class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
final ThemeData appTheme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Text(HomeScreen.title),
title: const Text(HomeScreen.title),
backgroundColor: appTheme.colorScheme.primary,
),
body: _children[_currentIndex],
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: _currentIndex != 2 ? CreateProgressButton() : null,
floatingActionButton: _currentIndex != 2 ? const CreateProgressButton() : null,
bottomNavigationBar: HomeBottomNavBar(
currentIndex: _currentIndex,
onTap: onBottomTabTapped,

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:time_progress_tracker/actions/actions.dart';
@ -13,6 +12,8 @@ class ProgressCreationScreen extends StatefulWidget {
static const routeName = "/create-progress";
static const title = "Create Time Progress";
const ProgressCreationScreen({super.key});
@override
State<StatefulWidget> createState() {
return _ProgressCreationScreenState();
@ -20,14 +21,15 @@ class ProgressCreationScreen extends StatefulWidget {
}
class _ProgressCreationScreenState extends State<ProgressCreationScreen> {
TimeProgress timeProgressToCreate;
TimeProgress? timeProgressToCreate;
bool _isProgressValid = false;
void initTimeProgress(TimeProgress timeProgress) {
if (timeProgressToCreate == null)
if (timeProgressToCreate == null) {
setState(() {
timeProgressToCreate = timeProgress;
});
}
}
void onTimeProgressChanged(
@ -40,19 +42,25 @@ class _ProgressCreationScreenState extends State<ProgressCreationScreen> {
@override
Widget build(BuildContext context) {
final ThemeData appTheme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Text(ProgressCreationScreen.title),
title: const Text(ProgressCreationScreen.title),
backgroundColor: appTheme.colorScheme.primary,
),
body: Container(
padding: EdgeInsets.all(12),
padding: const EdgeInsets.all(12),
child: StoreConnector<AppState, _ViewModel>(
onInit: loadSettingsIfUnloaded,
converter: (store) => _ViewModel.create(store),
builder: (context, _ViewModel viewModel) {
initTimeProgress(viewModel.defaultDurationProgress);
WidgetsBinding.instance.addPostFrameCallback((_) {
initTimeProgress(viewModel.defaultDurationProgress);
});
return ProgressEditorWidget(
timeProgress: timeProgressToCreate,
timeProgress:
timeProgressToCreate ?? viewModel.defaultDurationProgress,
onTimeProgressChanged: onTimeProgressChanged,
);
}),
@ -66,23 +74,24 @@ class _ProgressCreationScreenState extends State<ProgressCreationScreen> {
converter: (store) => _ViewModel.create(store),
builder: (context, _ViewModel vm) => FloatingActionButton(
heroTag: "createTimeProgressBTN",
child: Icon(Icons.save),
onPressed: _isProgressValid
? () {
vm.onAddTimeProgress(timeProgressToCreate);
vm.onAddTimeProgress(
timeProgressToCreate ?? vm.defaultDurationProgress);
Navigator.pop(context);
}
: null,
child: const Icon(Icons.save),
),
),
),
Expanded(
child: FloatingActionButton(
heroTag: "cancelTimeProgressCreationBTN",
child: Icon(Icons.cancel),
onPressed: () {
Navigator.pop(context);
},
child: const Icon(Icons.cancel),
),
)
],
@ -96,21 +105,21 @@ class _ViewModel {
final void Function(TimeProgress) onAddTimeProgress;
_ViewModel({
@required this.defaultDurationProgress,
@required this.onAddTimeProgress,
required this.defaultDurationProgress,
required this.onAddTimeProgress,
});
factory _ViewModel.create(Store<AppState> store) {
AppSettings settings = appSettingsSelector(store.state);
_onAddTimeProgress(TimeProgress tp) {
onAddTimeProgress(TimeProgress tp) {
if (TimeProgress.isValid(tp)) store.dispatch(AddTimeProgressAction(tp));
}
return _ViewModel(
defaultDurationProgress:
TimeProgress.defaultFromDuration(settings.duration),
onAddTimeProgress: _onAddTimeProgress,
onAddTimeProgress: onAddTimeProgress,
);
}
}

View File

@ -17,6 +17,8 @@ class ProgressDetailScreen extends StatefulWidget {
static const routeName = "/progress";
static const title = "Progress View";
const ProgressDetailScreen({super.key});
@override
State<StatefulWidget> createState() {
return _ProgressDetailScreenState();
@ -25,7 +27,7 @@ class ProgressDetailScreen extends StatefulWidget {
class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
bool _editMode = false, _isEditedProgressValid = false;
TimeProgress _editedProgress, _originalProgress;
TimeProgress? _editedProgress, _originalProgress;
void _initEditedProgress(TimeProgress tp) {
if (_editedProgress == null) {
@ -57,31 +59,35 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
List<Widget> _renderColumnChildren(
SettingsViewModel settingsVm, TimeProgressViewModel tpVm) {
List<Widget> columnChildren = [
Expanded(
List<Widget> columnChildren = [];
if (!_editMode) {
columnChildren.add(Expanded(
child: ProgressViewWidget(
timeProgress: _editMode ? _editedProgress : tpVm.tp,
timeProgress: _editMode ? _editedProgress ?? tpVm.tp : tpVm.tp,
doneColor: settingsVm.appSettings.doneColor,
leftColor: settingsVm.appSettings.leftColor,
))
];
if (_editMode)
)));
} else {
columnChildren.add(Expanded(
child: ProgressEditorWidget(
timeProgress: _editedProgress,
timeProgress: _editedProgress ?? tpVm.tp,
onTimeProgressChanged: _onEditedProgressChanged,
)));
}
return columnChildren;
}
@override
Widget build(BuildContext context) {
final ProgressDetailScreenArguments args =
ModalRoute.of(context).settings.arguments;
final ThemeData appTheme = Theme.of(context);
final ProgressDetailScreenArguments args = ModalRoute.of(context)
?.settings
.arguments as ProgressDetailScreenArguments;
return Scaffold(
appBar: AppBar(
title: Text(ProgressDetailScreen.title),
title: const Text(ProgressDetailScreen.title),
backgroundColor: appTheme.colorScheme.primary,
),
body: SettingsStoreConnector(
loadedBuilder: (context, settingsVm) {
@ -90,10 +96,11 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
loadedBuilder: (context, tpVm) {
_initEditedProgress(tpVm.tp);
return Container(
margin: EdgeInsets.all(8),
child: Column(
children: _renderColumnChildren(settingsVm, tpVm),
));
margin: const EdgeInsets.all(8),
child: Column(
children: _renderColumnChildren(settingsVm, tpVm),
),
);
},
);
},
@ -102,12 +109,12 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
floatingActionButton: TimeProgressStoreConnector(
timeProgressId: args.id,
loadedBuilder: (context, tpVm) {
void _saveEditedProgress() {
tpVm.updateTimeProgress(_editedProgress);
void saveEditedProgress() {
tpVm.updateTimeProgress(_editedProgress ?? tpVm.tp);
_switchEditMode(false);
}
void _deleteTimeProgress() {
void deleteTimeProgress() {
tpVm.deleteTimeProgress();
Navigator.popUntil(
context, ModalRoute.withName(HomeScreen.routeName));
@ -116,12 +123,12 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
return DetailScreenFloatingActionButtons(
editMode: _editMode,
originalProgress: tpVm.tp,
editedProgress: _editedProgress,
editedProgress: _editedProgress ?? tpVm.tp,
isEditedProgressValid: _isEditedProgressValid,
onEditProgress: () => _switchEditMode(true),
onSaveEditedProgress: _saveEditedProgress,
onSaveEditedProgress: saveEditedProgress,
onCancelEditProgress: _cancelEditMode,
onDeleteProgress: _deleteTimeProgress);
onDeleteProgress: deleteTimeProgress);
},
),
);

View File

@ -45,10 +45,11 @@ List<TimeProgress> pastTimeProgressesSelector(AppState state) =>
DateTime.now().millisecondsSinceEpoch)
.toList();
TimeProgress timeProgressByIdSelector(AppState state, String id) {
if (state.timeProgressList.length < 1) return null;
return state.timeProgressList
.firstWhere((timeProgress) => timeProgress.id == id, orElse: () => null);
TimeProgress? timeProgressByIdSelector(AppState state, String id) {
if (state.timeProgressList.isEmpty) return null;
return state.timeProgressList.firstWhere(
(timeProgress) => timeProgress.id == id,
orElse: () => TimeProgress.initialDefault());
}
AppSettings appSettingsSelector(AppState state) {

View File

@ -5,12 +5,12 @@ class AppYesNoDialog extends StatelessWidget {
final String contentText;
final void Function() onYesPressed;
AppYesNoDialog({
Key key,
@required this.titleText,
@required this.contentText,
@required this.onYesPressed,
}) : super(key: key);
const AppYesNoDialog({
super.key,
required this.titleText,
required this.contentText,
required this.onYesPressed,
});
@override
Widget build(BuildContext context) {
@ -18,15 +18,15 @@ class AppYesNoDialog extends StatelessWidget {
title: Text(titleText),
content: Text(contentText),
actions: <Widget>[
FlatButton(
child: Text("Yes"),
TextButton(
onPressed: onYesPressed,
child: const Text("Yes"),
),
FlatButton(
child: Text("No"),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("No"),
)
],
);

View File

@ -7,11 +7,12 @@ class ColorPickerButton extends StatelessWidget {
final Color selectedColor;
final void Function(Color) onColorPicked;
ColorPickerButton({
@required this.title,
@required this.dialogTitle,
@required this.selectedColor,
@required this.onColorPicked,
const ColorPickerButton({
super.key,
required this.title,
required this.dialogTitle,
required this.selectedColor,
required this.onColorPicked,
});
@override
@ -34,13 +35,13 @@ class ColorPickerButton extends StatelessWidget {
},
);
},
child: Text(title),
style: TextButton.styleFrom(
primary: useBrightBackground(selectedColor)
? appTheme.primaryTextTheme.button.color
: appTheme.textTheme.button.color,
foregroundColor: useBrightBackground(selectedColor)
? appTheme.primaryTextTheme.labelLarge?.color
: appTheme.textTheme.labelLarge?.color,
backgroundColor: selectedColor,
),
child: Text(title),
);
}
}

View File

@ -4,15 +4,17 @@ import 'package:time_progress_tracker/screens/progress_creation_screen.dart';
class CreateProgressButton extends StatelessWidget {
final String _heroTag = "createProgressBTN";
const CreateProgressButton({super.key});
@override
Widget build(BuildContext context) {
void _onButtonPressed() =>
void onButtonPressed() =>
Navigator.pushNamed(context, ProgressCreationScreen.routeName);
return FloatingActionButton(
heroTag: _heroTag,
child: Icon(Icons.add),
onPressed: _onButtonPressed,
onPressed: onButtonPressed,
child: const Icon(Icons.add),
);
}
}

View File

@ -3,13 +3,14 @@ import 'package:flutter/material.dart';
class DatePickerBtn extends StatelessWidget {
final String leadingString;
final DateTime pickedDate;
final void Function(DateTime) onDatePicked;
final void Function(DateTime?) onDatePicked;
DatePickerBtn({
@required this.leadingString,
@required this.pickedDate,
@required this.onDatePicked,
}) : super();
const DatePickerBtn({
super.key,
required this.leadingString,
required this.pickedDate,
required this.onDatePicked,
});
void _onButtonPressed(BuildContext context) async {
onDatePicked(await showDatePicker(
@ -25,12 +26,12 @@ class DatePickerBtn extends StatelessWidget {
ThemeData appTheme = Theme.of(context);
return TextButton(
onPressed: () => _onButtonPressed(context),
style: TextButton.styleFrom(
foregroundColor: appTheme.primaryTextTheme.labelLarge?.color,
backgroundColor: appTheme.colorScheme.secondary,
),
child: Text(
"$leadingString ${pickedDate.toLocal().toString().split(" ")[0]}"),
style: TextButton.styleFrom(
primary: appTheme.primaryTextTheme.button.color,
backgroundColor: appTheme.accentColor,
),
);
}
}

View File

@ -5,9 +5,10 @@ class SelectDurationBtn extends StatelessWidget {
final Duration duration;
final void Function(Duration) updateDuration;
SelectDurationBtn({
@required this.duration,
@required this.updateDuration,
const SelectDurationBtn({
super.key,
required this.duration,
required this.updateDuration,
});
void _onPickerConfirm(Picker picker, List<int> values) {
@ -25,7 +26,7 @@ class SelectDurationBtn extends StatelessWidget {
]),
hideHeader: false,
title: const Text("Default Duration"),
selectedTextStyle: TextStyle(color: appTheme.accentColor),
selectedTextStyle: TextStyle(color: appTheme.colorScheme.secondary),
onConfirm: _onPickerConfirm)
.showModal(context);
@ -38,10 +39,10 @@ class SelectDurationBtn extends StatelessWidget {
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,
));
foregroundColor: appTheme.primaryTextTheme.labelLarge?.color,
backgroundColor: appTheme.colorScheme.secondary,
),
child: Text("$years Years $months Months $days Days"));
}
}

View File

@ -10,25 +10,26 @@ class DetailScreenFloatingActionButtons extends StatelessWidget {
onCancelEditProgress,
onDeleteProgress;
DetailScreenFloatingActionButtons({
@required this.editMode,
@required this.originalProgress,
@required this.editedProgress,
@required this.isEditedProgressValid,
@required this.onEditProgress,
@required this.onSaveEditedProgress,
@required this.onCancelEditProgress,
@required this.onDeleteProgress,
const DetailScreenFloatingActionButtons({
super.key,
required this.editMode,
required this.originalProgress,
required this.editedProgress,
required this.isEditedProgressValid,
required this.onEditProgress,
required this.onSaveEditedProgress,
required this.onCancelEditProgress,
required this.onDeleteProgress,
});
@override
Widget build(BuildContext context) {
final ThemeData appTheme = Theme.of(context);
void _onCancelEditTimeProgressBTN() {
if (originalProgress == editedProgress)
void onCancelEditTimeProgressBTN() {
if (originalProgress == editedProgress) {
onCancelEditProgress();
else {
} else {
showDialog(
context: context,
builder: (_) => AppYesNoDialog(
@ -44,7 +45,7 @@ class DetailScreenFloatingActionButtons extends StatelessWidget {
}
}
void _onDeleteTimeProgressBTN() {
void onDeleteTimeProgressBTN() {
showDialog(
context: context,
builder: (_) => AppYesNoDialog(
@ -61,13 +62,13 @@ class DetailScreenFloatingActionButtons extends StatelessWidget {
child: FloatingActionButton(
heroTag:
editMode ? "saveEditedTimeProgressBTN" : "editTimeProgressBTN",
child: editMode ? Icon(Icons.save) : Icon(Icons.edit),
backgroundColor: editMode ? Colors.green : appTheme.accentColor,
backgroundColor: editMode ? Colors.green : appTheme.colorScheme.secondary,
onPressed: editMode
? isEditedProgressValid
? onSaveEditedProgress
: null
: onEditProgress,
child: editMode ? const Icon(Icons.save) : const Icon(Icons.edit),
),
),
Expanded(
@ -75,11 +76,11 @@ class DetailScreenFloatingActionButtons extends StatelessWidget {
heroTag: editMode
? "cancelEditTimeProgressBTN"
: "deleteTimeProgressBTN",
child: editMode ? Icon(Icons.cancel) : Icon(Icons.delete),
backgroundColor: Colors.red,
onPressed: editMode
? _onCancelEditTimeProgressBTN
: _onDeleteTimeProgressBTN,
? onCancelEditTimeProgressBTN
: onDeleteTimeProgressBTN,
child: editMode ? const Icon(Icons.cancel) : const Icon(Icons.delete),
),
),
],

View File

@ -2,13 +2,13 @@ import 'package:flutter/material.dart';
class HomeBottomNavBar extends StatelessWidget {
final int currentIndex;
final Function onTap;
final void Function(int)? onTap;
HomeBottomNavBar({
Key key,
@required this.currentIndex,
@required this.onTap,
}) : super(key: key);
const HomeBottomNavBar({
super.key,
required this.currentIndex,
required this.onTap,
});
@override
Widget build(BuildContext context) {
@ -19,21 +19,21 @@ class HomeBottomNavBar extends StatelessWidget {
currentIndex: currentIndex,
items: [
BottomNavigationBarItem(
icon: new Icon(
icon: Icon(
Icons.alarm,
color: appTheme.primaryColor,
),
label: "Active Progresses",
),
BottomNavigationBarItem(
icon: new Icon(
icon: Icon(
Icons.alarm_off,
color: appTheme.primaryColor,
),
label: "Inactive Progresses",
),
BottomNavigationBarItem(
icon: new Icon(
icon: Icon(
Icons.settings,
color: appTheme.primaryColor,
),

View File

@ -6,6 +6,8 @@ import 'package:time_progress_tracker/widgets/store_connectors/settings_store_co
import 'package:time_progress_tracker/widgets/store_connectors/time_progress_list_store_connector.dart';
class HomeActiveProgressesTab extends StatelessWidget {
const HomeActiveProgressesTab({super.key});
@override
Widget build(BuildContext context) {
return SettingsStoreConnector(
@ -14,14 +16,15 @@ class HomeActiveProgressesTab extends StatelessWidget {
loadedBuilder: (context, tpListVm) {
List<TimeProgress> activeTpList =
selectActiveProgresses(tpListVm.tpList);
if (activeTpList.length < 1)
if (activeTpList.isEmpty) {
return Container(
padding: EdgeInsets.all(16),
child: Center(
padding: const EdgeInsets.all(16),
child: const Center(
child: Text(
"You don't have any active time progress, that are tracked."),
),
);
}
return ProgressListView(
timeProgressList: activeTpList,

View File

@ -6,6 +6,8 @@ import 'package:time_progress_tracker/widgets/store_connectors/settings_store_co
import 'package:time_progress_tracker/widgets/store_connectors/time_progress_list_store_connector.dart';
class HomeInactiveProgressesTab extends StatelessWidget {
const HomeInactiveProgressesTab({super.key});
@override
Widget build(BuildContext context) {
return SettingsStoreConnector(
@ -14,14 +16,15 @@ class HomeInactiveProgressesTab extends StatelessWidget {
loadedBuilder: (context, tpListVm) {
List<TimeProgress> inactiveTpList =
selectInactiveProgresses(tpListVm.tpList);
if (inactiveTpList.length < 1)
if (inactiveTpList.isEmpty) {
return Container(
padding: EdgeInsets.all(16),
child: Center(
padding: const EdgeInsets.all(16),
child: const Center(
child: Text(
"You don't have any currently inactive time progresses, that are tracked."),
),
);
}
return ProgressListView(
timeProgressList: inactiveTpList,

View File

@ -5,12 +5,14 @@ import 'package:time_progress_tracker/widgets/home/tabs/settings/duration_settin
import 'package:time_progress_tracker/widgets/store_connectors/settings_store_connector.dart';
class HomeSettingsTab extends StatelessWidget {
const HomeSettingsTab({super.key});
@override
Widget build(BuildContext context) {
return SettingsStoreConnector(
loadedBuilder: (context, settingsVm) {
return Container(
padding: EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
child: Center(
child: Column(
children: [
@ -28,7 +30,7 @@ class HomeSettingsTab extends StatelessWidget {
updateDuration: settingsVm.updateDuration,
),
),
Spacer(),
const Spacer(),
Expanded(
child: TextButton(
onPressed: () {
@ -39,7 +41,7 @@ class HomeSettingsTab extends StatelessWidget {
applicationLegalese:
'\u00a9Andreas Fahrecker 2020-2021');
},
child: Text("About"),
child: const Text("About"),
),
),
],

View File

@ -5,11 +5,12 @@ 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,
const ColorSettingsWidget({
super.key,
required this.doneColor,
required this.leftColor,
required this.updateDoneColor,
required this.updateLeftColor,
});
@override
@ -21,14 +22,14 @@ class ColorSettingsWidget extends StatelessWidget {
Expanded(
child: Text(
"Color Settings",
style: appTheme.textTheme.headline6,
style: appTheme.textTheme.titleLarge,
),
),
Row(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.only(right: 5),
padding: const EdgeInsets.only(right: 5),
child: ColorPickerButton(
title: "Done Color",
dialogTitle: "Select Done Color",
@ -39,7 +40,7 @@ class ColorSettingsWidget extends StatelessWidget {
),
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 5),
padding: const EdgeInsets.only(left: 5),
child: ColorPickerButton(
title: "Left Color",
dialogTitle: "Select Left Color",

View File

@ -5,24 +5,25 @@ class DurationSettingsWidget extends StatelessWidget {
final Duration duration;
final void Function(Duration) updateDuration;
DurationSettingsWidget({
@required this.duration,
@required this.updateDuration,
const DurationSettingsWidget({
super.key,
required this.duration,
required this.updateDuration,
});
@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);
//int years = duration.inDays ~/ 365;
//int months = (duration.inDays - (365 * years)) ~/ 30;
//int days = duration.inDays - (365 * years) - (30 * months);
return Column(
children: [
Expanded(
child: Text(
"Duration Settings",
style: appTheme.textTheme.headline6,
style: appTheme.textTheme.titleLarge,
),
),
Row(

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:time_progress_tracker/models/time_progress.dart';
import 'package:time_progress_tracker/widgets/buttons/date_picker_btn.dart';
@ -6,9 +7,10 @@ class ProgressEditorWidget extends StatefulWidget {
final TimeProgress timeProgress;
final Function(TimeProgress, bool) onTimeProgressChanged;
ProgressEditorWidget({
@required this.timeProgress,
@required this.onTimeProgressChanged,
const ProgressEditorWidget({
super.key,
required this.timeProgress,
required this.onTimeProgressChanged,
});
@override
@ -31,7 +33,10 @@ class _ProgressEditorWidgetState extends State<ProgressEditorWidget> {
});
}
void _onStartDateChanged(DateTime newStartDate) {
void _onStartDateChanged(DateTime? newStartDate) {
if (newStartDate == null) {
return;
}
TimeProgress newProgress =
widget.timeProgress.copyWith(startTime: newStartDate);
widget.onTimeProgressChanged(
@ -42,7 +47,10 @@ class _ProgressEditorWidgetState extends State<ProgressEditorWidget> {
});
}
void _onEndDateChanged(DateTime newEndDate) {
void _onEndDateChanged(DateTime? newEndDate) {
if (newEndDate == null) {
return;
}
TimeProgress newProgress =
widget.timeProgress.copyWith(endTime: newEndDate);
widget.onTimeProgressChanged(
@ -62,12 +70,15 @@ class _ProgressEditorWidgetState extends State<ProgressEditorWidget> {
@override
Widget build(BuildContext context) {
double heightFactor = (!_validDate) ? 0.3 : 0.5;
List<Widget> columnChildren = [
Expanded(
SizedBox(
height: MediaQuery.of(context).size.height * heightFactor,
child: TextField(
controller: _nameTextController,
decoration: InputDecoration(
border: OutlineInputBorder(),
border: const OutlineInputBorder(),
labelText: "Progress Name",
errorText: _validName
? null
@ -75,12 +86,13 @@ class _ProgressEditorWidgetState extends State<ProgressEditorWidget> {
),
),
),
Expanded(
SizedBox(
height: MediaQuery.of(context).size.height * heightFactor,
child: Row(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.only(right: 5),
padding: const EdgeInsets.only(right: 5),
child: DatePickerBtn(
leadingString: "Start Date:",
pickedDate: widget.timeProgress.startTime,
@ -90,7 +102,7 @@ class _ProgressEditorWidgetState extends State<ProgressEditorWidget> {
),
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 5),
padding: const EdgeInsets.only(left: 5),
child: DatePickerBtn(
leadingString: "End Date:",
pickedDate: widget.timeProgress.endTime,
@ -103,10 +115,11 @@ class _ProgressEditorWidgetState extends State<ProgressEditorWidget> {
)
];
if (!_validDate)
if (!_validDate) {
columnChildren.add(
Expanded(
child: Center(
SizedBox(
height: MediaQuery.of(context).size.height * heightFactor,
child: const Center(
child: Text(
"Invalid Dates. The Start Date has to be before the End Date",
style: TextStyle(color: Colors.red),
@ -114,8 +127,10 @@ class _ProgressEditorWidgetState extends State<ProgressEditorWidget> {
),
),
);
}
return Container(
return SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: columnChildren,
),

View File

@ -18,17 +18,19 @@ class ProgressListTile extends StatelessWidget {
final TimeProgress timeProgress;
final Color doneColor, leftColor;
ProgressListTile({
@required this.timeProgress,
@required this.doneColor,
@required this.leftColor,
const ProgressListTile({super.key,
required this.timeProgress,
required this.doneColor,
required this.leftColor,
});
Widget _renderSubtitle(BuildContext context) {
if (!timeProgress.hasStarted())
if (!timeProgress.hasStarted()) {
return Text(ProgressListTileStrings.startsInDaysString(timeProgress));
if (timeProgress.hasEnded())
}
if (timeProgress.hasEnded()) {
return Text(ProgressListTileStrings.endedDaysAgoString(timeProgress));
}
return LinearPercentIndicator(
center: Text(ProgressListTileStrings.percentString(timeProgress)),
percent: timeProgress.percentDone(),
@ -40,14 +42,14 @@ class ProgressListTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
void _onTileTap() =>
void onTileTap() =>
Navigator.pushNamed(context, ProgressDetailScreen.routeName,
arguments: ProgressDetailScreenArguments(timeProgress.id));
return ListTile(
title: Text(timeProgress.name),
subtitle: _renderSubtitle(context),
onTap: _onTileTap,
onTap: onTileTap,
);
}
}

View File

@ -6,10 +6,11 @@ class ProgressListView extends StatelessWidget {
final List<TimeProgress> timeProgressList;
final Color doneColor, leftColor;
ProgressListView({
@required this.timeProgressList,
@required this.doneColor,
@required this.leftColor,
const ProgressListView({
super.key,
required this.timeProgressList,
required this.doneColor,
required this.leftColor,
});
List<Widget> _renderListViewChildren() {
@ -27,7 +28,7 @@ class ProgressListView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
padding: EdgeInsets.all(8),
padding: const EdgeInsets.all(8),
children: _renderListViewChildren(),
);
}

View File

@ -8,31 +8,37 @@ class ProgressViewWidget extends StatelessWidget {
final Color doneColor;
final Color leftColor;
ProgressViewWidget({
@required this.timeProgress,
@required this.doneColor,
@required this.leftColor,
const ProgressViewWidget({
super.key,
required this.timeProgress,
required this.doneColor,
required this.leftColor,
});
@override
Widget build(BuildContext context) {
return Container(
return SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: [
Expanded(
SizedBox(
height: MediaQuery.of(context).size.height *
0.3, // adjust the value as needed
child: FittedBox(
fit: BoxFit.fitWidth,
child: Text(
timeProgress.name,
textAlign: TextAlign.center,
style: TextStyle(
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
),
),
Expanded(
SizedBox(
height: MediaQuery.of(context).size.height *
0.3, // adjust the value as needed
child: CircularPercentIndicator(
radius: 100,
lineWidth: 10,
@ -42,14 +48,16 @@ class ProgressViewWidget extends StatelessWidget {
center: Text("${(timeProgress.percentDone() * 100).floor()} %"),
),
),
Expanded(
SizedBox(
height: MediaQuery.of(context).size.height *
0.3, // adjust the value as needed
child: LinearPercentIndicator(
padding: EdgeInsets.symmetric(horizontal: 15),
padding: const EdgeInsets.symmetric(horizontal: 15),
percent: timeProgress.percentDone(),
leading: Text("${timeProgress.daysBehind()} Days"),
center: Text(
"${(timeProgress.percentDone() * 100).floor()} %",
style: TextStyle(color: Colors.white),
style: const TextStyle(color: Colors.white),
),
trailing: Text("${timeProgress.daysLeft()} Days"),
progressColor: doneColor,

View File

@ -8,8 +8,9 @@ import 'package:time_progress_tracker/models/app_state.dart';
class SettingsStoreConnector extends StatelessWidget {
final Widget Function(BuildContext, SettingsViewModel) loadedBuilder;
SettingsStoreConnector({
@required this.loadedBuilder,
const SettingsStoreConnector({
super.key,
required this.loadedBuilder,
});
@override
@ -18,10 +19,11 @@ class SettingsStoreConnector extends StatelessWidget {
onInit: loadSettingsIfUnloaded,
converter: (store) => SettingsViewModel._create(store),
builder: (context, SettingsViewModel vm) {
if (!vm.hasSettingsLoaded)
return Center(
if (!vm.hasSettingsLoaded) {
return const Center(
child: CircularProgressIndicator(),
);
}
return loadedBuilder(context, vm);
},
);
@ -44,17 +46,17 @@ class SettingsViewModel {
);
factory SettingsViewModel._create(Store<AppState> store) {
AppSettings _appSettings = store.state.appSettings;
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 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)));
void updateDuration(Duration d) => store
.dispatch(UpdateAppSettingsActions(appSettings.copyWith(duration: d)));
return SettingsViewModel(_appSettings, store.state.hasSettingsLoaded,
_updateDoneColor, _updateLeftColor, _updateDuration);
return SettingsViewModel(appSettings, store.state.hasSettingsLoaded,
updateDoneColor, updateLeftColor, updateDuration);
}
}

View File

@ -8,8 +8,9 @@ import 'package:time_progress_tracker/models/time_progress.dart';
class TimeProgressListStoreConnector extends StatelessWidget {
final Widget Function(BuildContext, TimeProgressListViewModel) loadedBuilder;
TimeProgressListStoreConnector({
@required this.loadedBuilder,
const TimeProgressListStoreConnector({
super.key,
required this.loadedBuilder,
});
@override
@ -18,10 +19,11 @@ class TimeProgressListStoreConnector extends StatelessWidget {
onInit: loadTimeProgressListIfUnloaded,
converter: (store) => TimeProgressListViewModel._create(store),
builder: (context, TimeProgressListViewModel vm) {
if (!vm.hasTpListLoaded)
return Center(
if (!vm.hasTpListLoaded) {
return const Center(
child: CircularProgressIndicator(),
);
}
return loadedBuilder(context, vm);
},
);

View File

@ -11,9 +11,10 @@ class TimeProgressStoreConnector extends StatelessWidget {
final String timeProgressId;
final Widget Function(BuildContext, TimeProgressViewModel) loadedBuilder;
TimeProgressStoreConnector({
@required this.timeProgressId,
@required this.loadedBuilder,
const TimeProgressStoreConnector({
super.key,
required this.timeProgressId,
required this.loadedBuilder,
});
@override
@ -23,14 +24,11 @@ class TimeProgressStoreConnector extends StatelessWidget {
converter: (store) =>
TimeProgressViewModel._create(store, timeProgressId),
builder: (context, TimeProgressViewModel vm) {
if (!vm.hasTpListLoaded)
return Center(
if (!vm.hasTpListLoaded) {
return const Center(
child: CircularProgressIndicator(),
);
if (vm.tp == null)
return Center(
child: Text("Error Invalid Time Progress"),
);
}
return loadedBuilder(context, vm);
},
);
@ -52,15 +50,15 @@ class TimeProgressViewModel {
);
factory TimeProgressViewModel._create(Store<AppState> store, String id) {
void _updateTimeProgress(TimeProgress tp) =>
void updateTimeProgress(TimeProgress tp) =>
store.dispatch(UpdateTimeProgressAction(id, tp));
void _deleteTimeProgress() => store.dispatch(DeleteTimeProgressAction(id));
void deleteTimeProgress() => store.dispatch(DeleteTimeProgressAction(id));
return TimeProgressViewModel(
selectProgressById(store.state.timeProgressList, id),
store.state.hasProgressesLoaded,
_updateTimeProgress,
_deleteTimeProgress,
updateTimeProgress,
deleteTimeProgress,
);
}
}

View File

@ -5,100 +5,122 @@ packages:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
url: "https://pub.dev"
source: hosted
version: "2.0.13"
version: "3.4.10"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
version: "1.6.0"
version: "2.4.2"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.5.0"
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
charcode:
version: "1.3.0"
checked_yaml:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "2.0.3"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
url: "https://pub.dev"
source: hosted
version: "0.4.1"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.18.0"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "3.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "2.1.5"
version: "3.0.3"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
url: "https://pub.dev"
source: hosted
version: "0.1.3"
version: "1.0.6"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "2.1.2"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
version: "7.0.0"
flutter:
dependency: "direct main"
description: flutter
@ -108,32 +130,43 @@ packages:
dependency: "direct main"
description:
name: flutter_colorpicker
url: "https://pub.dartlang.org"
sha256: "458a6ed8ea480eb16ff892aedb4b7092b2804affd7e046591fb03127e8d8ef8b"
url: "https://pub.dev"
source: hosted
version: "0.3.5"
version: "1.0.3"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
url: "https://pub.dartlang.org"
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev"
source: hosted
version: "0.8.1"
version: "0.13.1"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
url: "https://pub.dev"
source: hosted
version: "3.0.1"
flutter_picker:
dependency: "direct main"
description:
path: "."
ref: HEAD
resolved-ref: e95d121f54faba889fbf8a850c86dd5cf4aa5c5a
url: "git://github.com/yangyxd/flutter_picker.git"
resolved-ref: "4a88a436b64d043d2e5412d64035a9bbe7f9d45d"
url: "https://github.com/yangyxd/flutter_picker.git"
source: git
version: "1.1.5"
version: "2.1.1"
flutter_redux:
dependency: "direct main"
description:
name: flutter_redux
url: "https://pub.dartlang.org"
sha256: "3b20be9e08d0038e1452fbfa1fdb1ea0a7c3738c997734530b3c6d0bb5fcdbdc"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
version: "0.10.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -148,142 +181,218 @@ packages:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
url: "https://pub.dev"
source: hosted
version: "2.1.19"
version: "4.1.7"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.6.3"
version: "0.7.1"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
url: "https://pub.dev"
source: hosted
version: "4.8.1"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://pub.dev"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://pub.dev"
source: hosted
version: "2.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "3.0.0"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.10"
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.8.0"
meta:
dependency: "direct main"
description:
name: meta
url: "https://pub.dartlang.org"
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.11.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.8.0"
version: "1.9.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.2.1"
percent_indicator:
dependency: "direct main"
description:
name: percent_indicator
url: "https://pub.dartlang.org"
sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c
url: "https://pub.dev"
source: hosted
version: "2.1.9+1"
version: "4.2.3"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "6.0.2"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
version: "3.1.4"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
process:
version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
name: pointycastle
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
url: "https://pub.dev"
source: hosted
version: "4.1.0"
version: "3.7.4"
redux:
dependency: "direct main"
description:
name: redux
url: "https://pub.dartlang.org"
sha256: "1e86ed5b1a9a717922d0a0ca41f9bf49c1a587d50050e9426fc65b14e85ec4d7"
url: "https://pub.dev"
source: hosted
version: "4.0.0+3"
version: "5.0.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
url: "https://pub.dartlang.org"
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.2.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
url: "https://pub.dev"
source: hosted
version: "2.3.5"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.3.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
url: "https://pub.dartlang.org"
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.3.2"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
url: "https://pub.dartlang.org"
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.3.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.3.2"
sky_engine:
dependency: transitive
description: flutter
@ -293,86 +402,114 @@ packages:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.8.0"
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
version: "0.2.19"
version: "0.6.1"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.3.2"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
url: "https://pub.dev"
source: hosted
version: "13.0.0"
web:
dependency: transitive
description:
name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "5.3.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "1.0.4"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "4.5.1"
version: "6.5.0"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "3.1.2"
sdks:
dart: ">=2.12.0-259.9.beta <3.0.0"
flutter: ">=1.20.0"
dart: ">=3.3.1 <4.0.0"
flutter: ">=3.19.0"

View File

@ -2,7 +2,7 @@ name: time_progress_tracker
description: A Flutter Application to create Timers with a percentage indicator.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
@ -12,21 +12,28 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# 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 is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.0.19+19
version: 0.0.21+21
environment:
sdk: ">=2.7.0 <3.0.0"
sdk: '>=3.3.1 <4.0.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
flutter_colorpicker:
flutter_redux:
flutter_picker:
git: git://github.com/yangyxd/flutter_picker.git
git:
url: https://github.com/yangyxd/flutter_picker.git
meta:
percent_indicator:
redux:
@ -35,17 +42,24 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
cupertino_icons: ^1.0.6
dev_dependencies:
flutter_launcher_icons:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^3.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
@ -59,7 +73,7 @@ flutter:
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages

View File

@ -3,8 +3,9 @@ import 'package:flutter/material.dart';
class MaterialTesterWidget extends StatelessWidget {
final Widget widget;
MaterialTesterWidget({
@required this.widget,
const MaterialTesterWidget({
super.key,
required this.widget,
});
@override

View File

@ -13,34 +13,34 @@ import 'package:time_progress_tracker/models/time_progress.dart';
import 'package:time_progress_tracker/widgets/progress_list_view/progress_list_tile.dart';
import 'package:time_progress_tracker/widgets/progress_list_view/progress_list_view.dart';
import 'MaterialTesterWidget.dart';
import 'material_tester_widget.dart';
void main() {
final AppSettings _defaultAppSettings = AppSettings.defaults();
final int _thisYear = DateTime.now().year;
final TimeProgress _activeProgress = TimeProgress(
"TestProgress", DateTime(_thisYear - 2), DateTime(_thisYear + 2));
final AppSettings defaultAppSettings = AppSettings.defaults();
final int thisYear = DateTime.now().year;
final TimeProgress activeProgress = TimeProgress(
"TestProgress", DateTime(thisYear - 2), DateTime(thisYear + 2));
void _findStringOnce(String str) => expect(find.text(str), findsOneWidget);
void findStringOnce(String str) => expect(find.text(str), findsOneWidget);
testWidgets("Progress List Tile with currently active progress works",
(WidgetTester tester) async {
await tester.pumpWidget(MaterialTesterWidget(
widget: ProgressListTile(
timeProgress: _activeProgress,
doneColor: _defaultAppSettings.doneColor,
leftColor: _defaultAppSettings.leftColor,
timeProgress: activeProgress,
doneColor: defaultAppSettings.doneColor,
leftColor: defaultAppSettings.leftColor,
),
));
_findStringOnce(_activeProgress.name);
_findStringOnce(ProgressListTileStrings.percentString(_activeProgress));
findStringOnce(activeProgress.name);
findStringOnce(ProgressListTileStrings.percentString(activeProgress));
WidgetPredicate linearPercentPredicate = (Widget widget) =>
linearPercentPredicate(Widget widget) =>
widget is LinearPercentIndicator &&
widget.percent == _activeProgress.percentDone() &&
widget.progressColor == _defaultAppSettings.doneColor &&
widget.backgroundColor == _defaultAppSettings.leftColor;
widget.percent == activeProgress.percentDone() &&
widget.progressColor == defaultAppSettings.doneColor &&
widget.backgroundColor == defaultAppSettings.leftColor;
expect(find.byWidgetPredicate(linearPercentPredicate), findsOneWidget);
});
@ -48,40 +48,40 @@ void main() {
(WidgetTester tester) async {
TimeProgress futureProgress = TimeProgress(
"Test Progress",
DateTime(_thisYear + 1),
DateTime(_thisYear + 2),
DateTime(thisYear + 1),
DateTime(thisYear + 2),
);
await tester.pumpWidget(MaterialTesterWidget(
widget: ProgressListTile(
timeProgress: futureProgress,
doneColor: _defaultAppSettings.doneColor,
leftColor: _defaultAppSettings.leftColor,
doneColor: defaultAppSettings.doneColor,
leftColor: defaultAppSettings.leftColor,
),
));
_findStringOnce(futureProgress.name);
_findStringOnce(ProgressListTileStrings.startsInDaysString(futureProgress));
findStringOnce(futureProgress.name);
findStringOnce(ProgressListTileStrings.startsInDaysString(futureProgress));
});
testWidgets("Progress List Tile with past progress works",
(WidgetTester tester) async {
TimeProgress pastProgress = TimeProgress(
"Test Progress",
DateTime(_thisYear - 2),
DateTime(_thisYear - 1),
DateTime(thisYear - 2),
DateTime(thisYear - 1),
);
await tester.pumpWidget(MaterialTesterWidget(
widget: ProgressListTile(
timeProgress: pastProgress,
doneColor: _defaultAppSettings.doneColor,
leftColor: _defaultAppSettings.leftColor,
doneColor: defaultAppSettings.doneColor,
leftColor: defaultAppSettings.leftColor,
),
));
_findStringOnce(pastProgress.name);
_findStringOnce(ProgressListTileStrings.endedDaysAgoString(pastProgress));
findStringOnce(pastProgress.name);
findStringOnce(ProgressListTileStrings.endedDaysAgoString(pastProgress));
});
WidgetPredicate getProgressListTilePredicate(
@ -96,35 +96,37 @@ void main() {
(WidgetTester tester) async {
await tester.pumpWidget(MaterialTesterWidget(
widget: ProgressListView(
timeProgressList: [_activeProgress],
doneColor: _defaultAppSettings.doneColor,
leftColor: _defaultAppSettings.leftColor,
timeProgressList: [activeProgress],
doneColor: defaultAppSettings.doneColor,
leftColor: defaultAppSettings.leftColor,
),
));
_findStringOnce(_activeProgress.name);
findStringOnce(activeProgress.name);
expect(
find.byWidgetPredicate(
getProgressListTilePredicate(_activeProgress, _defaultAppSettings)),
getProgressListTilePredicate(activeProgress, defaultAppSettings)),
findsOneWidget);
});
testWidgets("Progress List View displays file tiles",
(WidgetTester tester) async {
List<TimeProgress> tpList = [];
for (int i = 0; i < 5; i++) tpList.add(_activeProgress);
for (int i = 0; i < 5; i++) {
tpList.add(activeProgress);
}
await tester.pumpWidget(MaterialTesterWidget(
widget: ProgressListView(
timeProgressList: tpList,
doneColor: _defaultAppSettings.doneColor,
leftColor: _defaultAppSettings.leftColor,
doneColor: defaultAppSettings.doneColor,
leftColor: defaultAppSettings.leftColor,
),
));
expect(find.text(_activeProgress.name), findsNWidgets(5));
expect(find.text(activeProgress.name), findsNWidgets(5));
expect(
find.byWidgetPredicate(
getProgressListTilePredicate(_activeProgress, _defaultAppSettings)),
getProgressListTilePredicate(activeProgress, defaultAppSettings)),
findsNWidgets(5));
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -8,10 +8,13 @@
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
Fore more details:
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="/">
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
@ -28,18 +31,29 @@
<title>time_progress_tracker</title>
<link rel="manifest" href="manifest.json">
<script>
// The value below is injected by flutter build, do not touch.
const serviceWorkerVersion = null;
</script>
<!-- This script adds the flutter initialization JS code -->
<script src="flutter.js" defer></script>
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('flutter-first-frame', function () {
navigator.serviceWorker.register('flutter_service_worker.js');
window.addEventListener('load', function(ev) {
// Download main.dart.js
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: function(engineInitializer) {
engineInitializer.initializeEngine().then(function(appRunner) {
appRunner.runApp();
});
}
});
}
});
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

View File

@ -18,6 +18,18 @@
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}