This commit is contained in:
warlock
2022-02-20 04:29:06 +05:30
commit d4dd0864fa
87 changed files with 4738 additions and 0 deletions

46
.gitignore vendored Normal file
View File

@@ -0,0 +1,46 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# 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
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

10
.metadata Normal file
View File

@@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 5f105a6ca7a5ac7b8bc9b241f4c2d86f4188cf5c
channel: stable
project_type: app

16
README.md Normal file
View File

@@ -0,0 +1,16 @@
# tasktracker
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

29
analysis_options.yaml Normal file
View File

@@ -0,0 +1,29 @@
# 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-lang.github.io/linter/lints/index.html.
#
# 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

13
android/.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
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

73
android/app/build.gradle Normal file
View File

@@ -0,0 +1,73 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
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'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion flutter.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.Xperience.TaskTracker"
//minSdkVersion flutter.minSdkVersion
minSdkVersion 19
targetSdkVersion flutter.targetSdkVersion
multiDexEnabled true
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:multidex:1.0.3'
}
apply plugin: 'com.google.gms.google-services'

View File

@@ -0,0 +1,55 @@
{
"project_info": {
"project_number": "584018031136",
"project_id": "timetracker-a8929",
"storage_bucket": "timetracker-a8929.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:584018031136:android:26bd0f616e44f68e24c245",
"android_client_info": {
"package_name": "com.Xperience.TaskTracker"
}
},
"oauth_client": [
{
"client_id": "584018031136-nb4gih6j5qhfgffgatac4ti0v7093u0l.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.Xperience.TaskTracker",
"certificate_hash": "a766d93f9b8aa6e20fce9357bd401d63e3e69d5c"
}
},
{
"client_id": "584018031136-qcbe59kej60t3tua14ou979nokjp1ant.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.Xperience.TaskTracker",
"certificate_hash": "a616913ffe4e775a7db60d095f0de447def5ced7"
}
},
{
"client_id": "584018031136-95qsgo6ps7afapsjivnd7dohvbj6dl7k.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBM3WEkuPJLS7mUN3TgAlPRJAHlburepBA"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "584018031136-95qsgo6ps7afapsjivnd7dohvbj6dl7k.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.Xperience.TaskTracker.tasktracker">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -0,0 +1,39 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.Xperience.TaskTracker.tasktracker">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="tasktracker"
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"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

View File

@@ -0,0 +1,6 @@
package com.Xperience.TaskTracker.tasktracker
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 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 -->
<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>
</style>
</resources>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 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 -->
<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.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.Xperience.TaskTracker.tasktracker">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

32
android/build.gradle Normal file
View File

@@ -0,0 +1,32 @@
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.10'
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

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

View File

@@ -0,0 +1,6 @@
#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-6.7-all.zip

11
android/settings.gradle Normal file
View File

@@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
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"

BIN
fonts/NotoSans-Bold.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
fonts/NotoSans-Italic.ttf Normal file

Binary file not shown.

BIN
fonts/NotoSans-Regular.ttf Normal file

Binary file not shown.

14
gradle.properties Normal file
View File

@@ -0,0 +1,14 @@
## For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx1024m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Tue Feb 08 18:47:54 IST 2022
org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1024M"

BIN
images/Launch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
images/logo_512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
images/offline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
images/sign_in.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

BIN
images/signin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

34
ios/.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
</dict>
</plist>

View File

@@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@@ -0,0 +1,481 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.Xperience.TaskTracker.tasktracker;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.Xperience.TaskTracker.tasktracker;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.Xperience.TaskTracker.tasktracker;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,13 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

47
ios/Runner/Info.plist Normal file
View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Tasktracker</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>tasktracker</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

185
lib/Activities.dart Normal file
View File

@@ -0,0 +1,185 @@
import 'package:flutter/material.dart';
import 'main.dart';
import 'NewTask.dart';
import 'Data.dart';
import 'User.dart' as User;
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
class Activities extends StatefulWidget {
const Activities({Key? key}) : super(key: key);
@override
_ActivitiesState createState() => _ActivitiesState();
}
late ProgressDialog progressDialog;
class _ActivitiesState extends State<Activities> {
@override
void initState() {
// TODO: implement initState
super.initState();
UpdateList();
}
@override
Widget build(BuildContext context) {
progressDialog=ProgressDialog(context: context);
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => NewTask()))
.then((value) => UpdateList());
},
label: Text("New Activity"),
icon: Icon(Icons.add)),
appBar: AppBar(
title: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(children: [
Icon(Icons.task, color: Theme.of(context).primaryColor),
SizedBox(width: 10),
Text('Activities')
]),
(selecting)?Row(children: [
InkWell(onTap: (){
DeleteSelectedTasks();
}, child: Icon(Icons.delete,size: 30,)),
SizedBox(width: 20,),
InkWell(onTap: (){setState(() {
selecting=false;
});}, child: Icon(Icons.close,size: 30),)
]) : Container(),
],
)),
drawer: navDrawer(context, 3),
body: Container(
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(
children: PrintTasks(),
))));
}
void UpdateList() async {
if(progressDialog != null){progressDialog.show(max:100,msg: 'Loading Task Types');}
await User.updateTasksList();
setState(() {});
if(progressDialog != null){progressDialog.update(value: 100);}
}
List<Widget> PrintTasks() {
List<Widget> _tasks = [];
print('Priting cats : ' + User.taskTypes.length.toString());
User.taskTypes.forEach((element) {
String name = element.name;
if (element.cat == null) {
print('Got some null cat : ${element.name}');
} else {
Color color = HexColor.fromHex(element.cat?.color ?? '#000000');
bool productive = element.cat?.productive ?? true;
Widget task = TaskCard(context, name, productive, color);
_tasks.add(task);
}
});
return _tasks;
}
bool selecting = false;
Widget TaskCard(
BuildContext context, String name, bool productive, Color color) {
return Row(children: [
// Container(),
(selecting)
? Checkbox(
value: selectedTasks.contains(name),
onChanged: (value) {
print('selected $name');
OnItemSelected(name);
setState(() {});
})
: Container(),
Expanded(
child: Column(children: [
Card(
// color: color,
elevation:20,
shadowColor: color,
child: InkWell(
onTap: () {
//Open Respective Category
if(selecting){
OnItemSelected(name);
}
setState(() {
});
},
onLongPress: () {
print('gonna delete');
selecting = !selecting;
selectedTasks = [name];
setState(() {});
},
child: Container(
padding: EdgeInsets.all(10),
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(name,
style: TextStyle(color: Colors.white)),
// Icon(Icons.analytics, color: color, size: 20,),
Icon(Icons.circle,
color: (productive)
? Colors.green
: Colors.red)
]),
],
)))),
Container(
margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
height: 2,
color: color)
]),
),
]);
}
void OnItemSelected(String name){
if (!selectedTasks.contains(name)) {
selectedTasks.add(name);
} else {
selectedTasks.remove(name);
}
}
void DeleteSelectedTasks() async{
progressDialog.show(max: 100, msg: 'Deleteing ${selectedTasks.length} Task Types');
selectedTasks.forEach((element) async {
await User.UserOperations.deleteTask(element, bulk:true);
});
await Future.delayed(Duration(seconds: 2));
await User.UserOperations.executeQueries();
selectedTasks=[];
selecting=false;
setState(() {
progressDialog.update(value: 100);
});
}
}
List<String> selectedTasks = [];

213
lib/Categories.dart Normal file
View File

@@ -0,0 +1,213 @@
import 'package:flutter/material.dart';
import 'package:tasktracker/NewCategory.dart';
import 'main.dart';
import 'NewTask.dart';
import 'User.dart' as User;
import 'Data.dart';
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
class Categories extends StatefulWidget {
const Categories({Key? key}) : super(key: key);
@override
_CategoriesState createState() => _CategoriesState();
}
late ProgressDialog progressDialog;
bool selecting=false;
class _CategoriesState extends State<Categories> {
@override
void initState() {
// TODO: implement initState
super.initState();
UpdateList();
}
@override
Widget build(BuildContext context) {
progressDialog=ProgressDialog(context: context);
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => NewCategory()))
.then((value) => UpdateList());
},
label: Text("New Category"),
icon: Icon(Icons.add)),
appBar: AppBar(
title: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(children: [
Icon(Icons.account_tree_outlined, color: Theme.of(context).primaryColor),
SizedBox(width: 10),
Text('Categories')
]),
(selecting)?Row(children: [
InkWell(onTap: (){
DeleteSelectedCats();
}, child: Icon(Icons.delete,size: 30,)),
SizedBox(width: 20,),
InkWell(onTap: (){setState(() {
selecting=false;
});}, child: Icon(Icons.close,size: 30),)
]) : Container(),
],
)),
drawer: navDrawer(context, 4),
body: Container(
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(
children: PrintCats(),
))));
}
void UpdateList() async {
await User.updateCatsList();
setState(() {});
}
List<Widget> PrintCats() {
List<Widget> _cats = [];
print('Priting cats : ' + User.categories.length.toString());
User.categories.forEach((element) {
String name = element.name;
Color color = HexColor.fromHex(element.color);
bool productive = element.productive;
Widget cat = TaskCard(context,name, productive, color);
_cats.add(cat);
});
return _cats;
}
void OnItemSelected(String name){
if (!selectedTasks.contains(name)) {
selectedTasks.add(name);
} else {
selectedTasks.remove(name);
}
}
void DeleteSelectedCats() async{
progressDialog.show(max: 100, msg: 'Deleteing ${selectedTasks.length} Categories');
selectedTasks.forEach((element) async {
await User.UserOperations.deleteCategory(element, bulk:true);
});
await Future.delayed(Duration(seconds: 2));
await User.UserOperations.executeQueries();
selectedTasks=[];
selecting=false;
setState(() {
progressDialog.update(value: 100);
});
}
Widget TaskCard(
BuildContext context, String name, bool productive, Color color) {
return Row(children: [
// Container(),
(selecting)
? Checkbox(
value: selectedTasks.contains(name),
onChanged: (value) {
print('selected $name');
OnItemSelected(name);
setState(() {});
})
: Container(),
Expanded(
child: Column(children: [
Card(
// color: color,
elevation:20,
shadowColor: color,
child: InkWell(
onTap: () {
//Open Respective Category
if(selecting){
OnItemSelected(name);
}
setState(() {
});
},
onLongPress: () {
print('gonna delete');
selecting = !selecting;
selectedTasks = [name];
setState(() {});
},
child: Container(
padding: EdgeInsets.all(10),
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(name,
style: TextStyle(color: Colors.white)),
// Icon(Icons.analytics, color: color, size: 20,),
Icon(Icons.circle,
color: (productive)
? Colors.green
: Colors.red)
]),
],
)))),
Container(
margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
height: 2,
color: color)
]),
),
]);
}
}
List<String> selectedTasks = [];
// Widget TaskCard(String name, bool productive, Color color) {
// return Column(
// children: [Card(
// // color: color,
// elevation: 30,
// shadowColor: color,
// child: InkWell(
// onTap: () {
// //Open Respective Category
// },
// onLongPress: () {
// print('gonna delete');
// },
// child: Container(
// padding: EdgeInsets.all(10),
// child: Column(
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(name, style: TextStyle(color: Colors.white)),
// // Icon(Icons.analytics, color: color, size: 20,),
// Icon(Icons.circle,
// color: (productive) ? Colors.green : Colors.red)
// ]),
// ],
// ))
//
// )),
//
// Container(
// margin: EdgeInsets.fromLTRB(10, 0, 10, 10),
// height: 2,
// color: color
// )
// ]);
// }

94
lib/Data.dart Normal file
View File

@@ -0,0 +1,94 @@
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart';
class Category{
Category(this.category_id, this.name, this.color, this.productive);
String category_id;
String name;
String color;
bool productive;
static String colCatId = "category_id";
static String colName = "name";
static String colColor = "color";
static String colProductive = "productive";
}
class TaskType{
TaskType(this.id, this.name, this.category, [this.cat = null]);
String id;
String name;
String category;
Category? cat;
static String colId = "id";
static String colName="name";
static String colCategory = "category_id";
}
class Activity{
Activity(this.taskType, this.startTime, this.endTime);
TaskType taskType;
DateTime startTime;
DateTime endTime;
static String colType = "type";
static String colStartTime = "s_time";
static String colEndTime = "e_time";
}
class InitialData{
static List<TaskType> getTaskTypes(String username){
List<TaskType> tasks =[
TaskType(username + 'Sleep','Sleep', 'Relax'),
TaskType(username + 'Physics','Physics', 'Study'),
TaskType(username + 'History','History','Study'),
TaskType(username + 'Football','Football', 'Play'),
TaskType(username + 'At work','At work', 'Work'),
TaskType(username + 'Chores','Chores', 'Daily Activities'),
TaskType(username + 'Eat','Eat','Daily Activities'),
TaskType(username + 'Hang out','Hang out', 'Social')
];
return tasks;
}
static List<Category> getCategories(String username){
List<Category> cats = [
Category(username+'Relax','Relax', '#555555', false),
Category(username+'Daily Activities','Daily Activities', '#009955',false),
Category(username+'Study','Study', '#00FF00', true),
Category(username+'Play','Play', '#FF0000', false),
Category(username+'Work','Work', '#00AAFF', true),
Category(username+'Social','Social', '#00AAAA', false)
];
return cats;
}
}
class Queries{
static String colLink= "file";
static String colData = "data";
}
class Settings{
static Future<String> UUID() async{
final prefs = await SharedPreferences.getInstance();
if(prefs.containsKey('uuid')){
return await Future.value(prefs.getString('uuid'));
}else{
var uuid = Uuid();
String _uuid = uuid.v4();
await prefs.setString('uuid',_uuid);
return Future.value(_uuid);
}
}
}

199
lib/NewCategory.dart Normal file
View File

@@ -0,0 +1,199 @@
import 'package:flutter/material.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:intl/intl.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'User.dart' as User;
import 'Data.dart';
DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat durationFormat = DateFormat("HH:mm:ss");
class NewCategory extends StatefulWidget {
const NewCategory({Key? key}) : super(key: key);
@override
_NewCategoryState createState() => _NewCategoryState();
}
class _NewCategoryState extends State<NewCategory> {
TextEditingController nameController = TextEditingController();
bool productive = true;
Color pickerColor = Colors.blue;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('New Category')),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 50, 20, 50),
child: Column(
children: [
Column(children: [
Container(
padding: EdgeInsets.all(10),
child: Text('Category Name')),
Container(
padding: EdgeInsets.all(10),
child: TextField(
controller: nameController,
decoration: InputDecoration(
hintText:
'ex: Study, Games, Relax, etc...',
border: OutlineInputBorder()),
),
),
Divider(),
Container(
padding: EdgeInsets.all(10),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('Productivity',
style: TextStyle(fontSize: 18)),
Switch(
value: productive,
onChanged: (value) {
setState(() {
productive = value;
});
},
)
])),
Divider(),
Container(
margin: EdgeInsets.all(10),
child: InkWell(
onTap: () => pickColor(context),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Text("Category Color ",
style: TextStyle(fontSize: 18)),
Icon(Icons.circle,
size: 40, color: pickerColor)
],
)))
]),
],
))),
Container(
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 5,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 10, vertical: 0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red,
shape: StadiumBorder()),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
child: Text('Back',
style: TextStyle(fontSize: 20))))),
Expanded(
flex: 6,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 10, vertical: 0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.green,
shape: StadiumBorder()),
onPressed: () {
add_action();
},
child: Text('Add Category',
style: TextStyle(fontSize: 20))))),
],
))
])));
}
void pickColor(BuildContext context) => showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Pick Color for Category'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
MaterialPicker(
pickerColor: pickerColor,
onColorChanged: (color){
setState(() {
pickerColor=color;
});
},
enableLabel: false,
portraitOnly: true,
),
TextButton(
child: Text('Select', style: TextStyle(fontSize: 20)),
onPressed: () => Navigator.of(context).pop(),
)
]),
));
void add_action() async{
String catName = nameController.value.text;
if(catName.length< 2){
showAlertDialog(context, 'Category needs a name', 'Please enter a name for this category');
return;
}
var hex = '#${pickerColor.value.toRadixString(16)}';
await User.UserOperations.addCategory(catName, hex, productive);
Navigator.of(context).pop();
}
}
String _printDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
showAlertDialog(BuildContext context, String title, String message) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () { Navigator.of(context).pop(); },
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text(title),
content: Text(message),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}

184
lib/NewTask.dart Normal file
View File

@@ -0,0 +1,184 @@
import 'package:flutter/material.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:intl/intl.dart';
import 'User.dart' as User;
DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat durationFormat = DateFormat("HH:mm:ss");
class NewTask extends StatefulWidget {
const NewTask({Key? key}) : super(key: key);
@override
_NewTaskState createState() => _NewTaskState();
}
List<String> getCategoryNames(){
List<String> _cats = [];
User.categories.forEach((element) {
String name = element.name;
_cats.add(name);
});
return _cats;
}
String selectedCat = User.categories[0].name;
class _NewTaskState extends State<NewTask> {
TextEditingController nameController = TextEditingController();
bool productive = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('New Task Type')),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 50, 20, 50),
child: Column(
children: [
Column(children: [
Container(
padding: EdgeInsets.all(10),
child: Text('Task Type Name')),
Container(
padding: EdgeInsets.all(10),
child: TextField(
controller: nameController,
decoration: InputDecoration(
hintText: 'ex: Study Science, Play CS:GO, etc...',
border: OutlineInputBorder()
),
),
),
Divider(),
Container(
padding: EdgeInsets.all(10),
child: Text('Category')),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
decoration: BoxDecoration(
color: Colors.blueGrey,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey, width: 2)),
child: DropdownButton<String>(
dropdownColor: Colors.blueGrey,
iconSize: 30,
elevation: 10,
borderRadius: BorderRadius.circular(10),
value: selectedCat,
isExpanded: true,
items: getCategoryNames().map<DropdownMenuItem<String>>(
(String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? _value) {
setState(() {
selectedCat = _value!;
});
})),
Container(
child: Divider(
height: 30,
)),
]),
],
))),
Container(
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 5,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: ElevatedButton(
style:ElevatedButton.styleFrom(
primary: Colors.red,
shape: StadiumBorder()
),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
child: Text('Back',
style: TextStyle(fontSize: 20))))),
Expanded(
flex: 6,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: ElevatedButton(
style:ElevatedButton.styleFrom(
primary: Colors.green,
shape: StadiumBorder()
),
onPressed: () {
setState(() {
add_action();
});
},
child: Text('Add Task Type',
style: TextStyle(fontSize: 20))))),
],
))
])));
}
void add_action() async{
String catName = nameController.value.text;
print('adding Task Type : $catName, $selectedCat');
if(catName.length< 2){
showAlertDialog(context, 'Category needs a name', 'Please enter a name for this category');
return;
}
await User.UserOperations.addTaskType(catName,selectedCat);
Navigator.of(context).pop();
}
}
String _printDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
showAlertDialog(BuildContext context, String title, String message) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () { Navigator.of(context).pop(); },
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text(title),
content: Text(message),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}

185
lib/Tasks.dart Normal file
View File

@@ -0,0 +1,185 @@
import 'package:flutter/material.dart';
import 'main.dart';
import 'NewTask.dart';
import 'Data.dart';
import 'User.dart' as User;
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
class Tasks extends StatefulWidget {
const Tasks({Key? key}) : super(key: key);
@override
_TasksState createState() => _TasksState();
}
late ProgressDialog progressDialog;
class _TasksState extends State<Tasks> {
@override
void initState() {
// TODO: implement initState
super.initState();
UpdateList();
}
@override
Widget build(BuildContext context) {
progressDialog=ProgressDialog(context: context);
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => NewTask()))
.then((value) => UpdateList());
},
label: Text("New Task Type"),
icon: Icon(Icons.add)),
appBar: AppBar(
title: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(children: [
Icon(Icons.task, color: Theme.of(context).primaryColor),
SizedBox(width: 10),
Text('Task Types')
]),
(selecting)?Row(children: [
InkWell(onTap: (){
DeleteSelectedTasks();
}, child: Icon(Icons.delete,size: 30,)),
SizedBox(width: 20,),
InkWell(onTap: (){setState(() {
selecting=false;
});}, child: Icon(Icons.close,size: 30),)
]) : Container(),
],
)),
drawer: navDrawer(context, 3),
body: Container(
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(
children: PrintTasks(),
))));
}
void UpdateList() async {
if(progressDialog != null){progressDialog.show(max:100,msg: 'Loading Task Types');}
await User.updateTasksList();
setState(() {});
if(progressDialog != null){progressDialog.update(value: 100);}
}
List<Widget> PrintTasks() {
List<Widget> _tasks = [];
print('Priting cats : ' + User.taskTypes.length.toString());
User.taskTypes.forEach((element) {
String name = element.name;
if (element.cat == null) {
print('Got some null cat : ${element.name}');
} else {
Color color = HexColor.fromHex(element.cat?.color ?? '#000000');
bool productive = element.cat?.productive ?? true;
Widget task = TaskCard(context, name, productive, color);
_tasks.add(task);
}
});
return _tasks;
}
bool selecting = false;
Widget TaskCard(
BuildContext context, String name, bool productive, Color color) {
return Row(children: [
// Container(),
(selecting)
? Checkbox(
value: selectedTasks.contains(name),
onChanged: (value) {
print('selected $name');
OnItemSelected(name);
setState(() {});
})
: Container(),
Expanded(
child: Column(children: [
Card(
// color: color,
elevation:20,
shadowColor: color,
child: InkWell(
onTap: () {
//Open Respective Category
if(selecting){
OnItemSelected(name);
}
setState(() {
});
},
onLongPress: () {
print('gonna delete');
selecting = !selecting;
selectedTasks = [name];
setState(() {});
},
child: Container(
padding: EdgeInsets.all(10),
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(name,
style: TextStyle(color: Colors.white)),
// Icon(Icons.analytics, color: color, size: 20,),
Icon(Icons.circle,
color: (productive)
? Colors.green
: Colors.red)
]),
],
)))),
Container(
margin: EdgeInsets.fromLTRB(15, 0, 15, 10),
height: 2,
color: color)
]),
),
]);
}
void OnItemSelected(String name){
if (!selectedTasks.contains(name)) {
selectedTasks.add(name);
} else {
selectedTasks.remove(name);
}
}
void DeleteSelectedTasks() async{
progressDialog.show(max: 100, msg: 'Deleteing ${selectedTasks.length} Task Types');
selectedTasks.forEach((element) async {
await User.UserOperations.deleteTask(element, bulk:true);
});
await Future.delayed(Duration(seconds: 2));
await User.UserOperations.executeQueries();
selectedTasks=[];
selecting=false;
setState(() {
progressDialog.update(value: 100);
});
}
}
List<String> selectedTasks = [];

564
lib/User.dart Normal file
View File

@@ -0,0 +1,564 @@
import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'Data.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
late http.Response loginResponse;
late Database cacheDb;
late String username;
List<Category> categories = [];
List<TaskType> taskTypes = [];
List<Activity> activities=[];
bool offline = true;
Future<http.Response> login(String _username, String password) async {
username = _username;
var device_id = await Settings.UUID();
try {
loginResponse = (await http.post(
Uri.parse('http://161.97.127.136/task_tracker/login.php'),
body: <String, String>{
"username": _username,
"password": password,
"device_id": device_id ?? 'n/a'
}));
if (loginResponse.body.toLowerCase().contains("success")) {
offline = false;
username = _username;
}
}catch(e){
offline=true;
}
return loginResponse;
}
Future<void> initUserData() async {
await initCacheDatabase();
await UpdateCategoriesFromServer();
await UpdateTaskTypesFromServer();
await GetCategories(true);
await GetTaskTypes(true);
print('Initializing UserData...');
if (offline) {
print('Going offline mode.');
}
}
Future<bool> cacheDbExist() async{
Directory directory = await getApplicationDocumentsDirectory();
return databaseFactory.databaseExists(directory.path + 'cache.db');
}
Future<void> updateCatsList() async{
print('Updating with localCache');
categories = await GetCategories(true);
print('Checking if can refresh');
categories = await GetCategories(false);
}
Future<void> updateTasksList() async{
print('Updating with localCache');
taskTypes = await GetTaskTypes(true);
print('Checking if can refresh');
taskTypes = await GetTaskTypes(false);
}
Future<void> initCacheDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
print('database at ' + directory.path + 'cache.db');
cacheDb = await openDatabase(directory.path + 'cache.db', version: 1, onCreate: onCacheDatabaseCreate, onUpgrade: onCacheDatabaseUpgrade);
await UserOperations.executeQueries();
}
void onCacheDatabaseCreate(Database db, int newVersion) async {
String CategoriesTableSQL =
'CREATE TABLE Categories(${Category.colCatId} VARCHAR(255) PRIMARY KEY,${Category.colName} TEXT, ${Category.colColor} TEXT, ${Category.colProductive} INTEGER)';
// print(CategoriesTableSQL);
await db.execute(CategoriesTableSQL);
print("Initiated Categories Table");
String TaskTableSQL =
'CREATE TABLE TaskTypes(id TEXT PRIMARY KEY, ${TaskType.colName} TEXT, ${TaskType.colCategory} TEXT, '
'FOREIGN KEY (${TaskType.colCategory}) REFERENCES Categories(${Category.colCatId}))';
// print(TaskTableSQL);
await db.execute(TaskTableSQL);
String ActivityTableSQL =
'CREATE TABLE Activities(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Activity.colType} INT, ${Activity.colStartTime} DATETIME, ${Activity.colEndTime} DATETIME, '
'FOREIGN KEY (${Activity.colType}) REFERENCES TaskTypes(id))';
// print(ActivityTableSQL);
await db.execute(ActivityTableSQL);
String QueriesTableSQL = 'CREATE TABLE Queries(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Queries.colLink} TEXT,${Queries.colData} TEXT)';
// print(QueriesTableSQL);
await db.execute(QueriesTableSQL);
addInitialDataToCache();
// GetCategories();
}
Future<void> addInitialDataToCache() async{
await Future.delayed(const Duration(seconds: 1));
//Insert Initial Entries
for(Category element in InitialData.getCategories(username)){
await UserOperations.addCategory(element.name, element.color, element.productive,bulk: true);
}
for(TaskType element in InitialData.getTaskTypes(username)){
await UserOperations.addTaskType(element.name, element.category, bulk: true);
// Map<String,Object> data = {
// TaskType.colName: element.name,
// TaskType.colCategory: element.category
// };
// await cacheDb.insert('TaskTypes', data);
}
UserOperations.executeQueries();
}
void onCacheDatabaseUpgrade(Database db, int oldVersion, int newVersion) async {
//ValidateCacheDB();
print('Upgrading CacheDB from ver.$oldVersion to ver.$newVersion');
}
Future<List<Category>> GetCategories(bool forceOffline) async{
List<Category> _categories = [];
if(offline || forceOffline){
//Retreive from cacheDB
}else{
//Check if server got updated, If not go for cache
var android_id = await Settings.UUID();
//Validate device_id to check updates
bool catsUpdated = true;
try{
http.Response update_response = (await http.post(
Uri.parse('http://161.97.127.136/task_tracker/check_update.php'),
body: <String, String>{"username": username, "device_id":android_id??'n/a'}));
final data = update_response.body.split(',');
catsUpdated = data[0] == '1';
}catch(e){
print(e);
}
print("Need to update : ${!catsUpdated}");
//Update CacheDB
if(!catsUpdated){
await UpdateCategoriesFromServer();
}
}
List<Map> cats = await cacheDb.query('Categories');
print(cats.length);
for(Map element in cats){
String? catName = element[Category.colName].toString();
String? catColor = element[Category.colColor].toString();
String? catProductive = element[Category.colProductive].toString();
if(catName==null || catColor==null || catProductive==null){
print("Something is null!");
print("name:{$catName}, color:{$catColor}, prod:{$Category.colProductive}");
continue;
}
print("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
_categories.add(Category(username + catName, catName, catColor, ParseBool(catProductive)));
}
categories = _categories;
return categories;
}
Future<void> UpdateCategoriesFromServer() async{
print("Updating Categories");
try {
http.Response response = (await http.post(
Uri.parse('http://161.97.127.136/task_tracker/get_categories.php'),
body: <String, String>{
"username": username,
"device_id": await Settings.UUID() ?? 'n/a'
}));
print(response.body);
List<String> data = response.body.split("<td>");
data.forEach((value) async {
Map<String, dynamic> cat = jsonDecode(value);
//print(catData);
await cacheDb.rawInsert(
"INSERT OR REPLACE INTO Categories (${Category.colCatId},${Category
.colName},${Category.colProductive},${Category.colColor}) "
"VALUES ('${cat['category_id']}','${cat['name']}',${cat['productive']},'${cat['color']}') ");
});
}catch(e){
offline=true;
}
}
Future<List<TaskType>> GetTaskTypes(bool forceOffline) async{
List<TaskType> _taskTypes = [];
if(offline || forceOffline){
//Retreive from cacheDB
}else{
//Check if server got updated, If not go for cache
var android_id = await Settings.UUID();
bool updated =true;
try{
//Validate device_id to check updates
http.Response update_response = (await http.post(
Uri.parse('http://161.97.127.136/task_tracker/check_update.php'),
body: <String, String>{"username": username, "device_id":android_id??'n/a'}));
final data = update_response.body.split(',');
updated = data[1] == '1';
}catch(e){
print(e);
}
print("Need to update : ${!updated}");
//Update CacheDB
if(!updated){
await UpdateTaskTypesFromServer();
}
}
List<Map> cats = await cacheDb.query('TaskTypes');
print(cats.length);
for(Map element in cats){
String? id = element[TaskType.colId].toString();
String? name = element[TaskType.colName].toString();
String? category = element[TaskType.colCategory].toString();
Category? cat = await getCatFromId(category);
if(id==null || name==null || category==null){
print("Something is null!");
print("name:{$name}, cat:{$category}, prod:{$id}");
continue;
}
print("name:{$name}, cat:{$category}, prod:{$id}");
_taskTypes.add(TaskType(id,name,category,cat));
}
taskTypes = _taskTypes;
return taskTypes;
}
Future<void> UpdateTaskTypesFromServer() async{
print("Updating TaskTypes");
try {
http.Response response = (await http.post(
Uri.parse('http://161.97.127.136/task_tracker/get_taskTypes.php'),
body: <String, String>{
"username": username,
"device_id": await Settings.UUID() ?? 'n/a'
}));
print(response.body);
List<String> data = response.body.split("<td>");
data.forEach((value) async {
Map<String, dynamic> cat = jsonDecode(value);
//print(catData);
await cacheDb.rawInsert(
"INSERT OR REPLACE INTO TaskTypes (${TaskType.colId},${TaskType
.colName},${TaskType.colCategory}) "
"VALUES ('${cat['id']}','${cat['name']}',${cat['category']}) ");
});
}catch(e){
offline=true;
}
}
Future<List<TaskType>> GetActivities(bool forceOffline) async{
List<Activity> _activities = [];
if(offline || forceOffline){
//Retreive from cacheDB
}else{
//Check if server got updated, If not go for cache
var android_id = await Settings.UUID();
bool updated =true;
try{
//Validate device_id to check updates
http.Response update_response = (await http.post(
Uri.parse('http://161.97.127.136/task_tracker/check_update.php'),
body: <String, String>{"username": username, "device_id":android_id??'n/a'}));
final data = update_response.body.split(',');
updated = data[2] == '1';
}catch(e){
print(e);
}
print("Need to update activities : ${!updated}");
//Update CacheDB
if(!updated){
await UpdateActivitiesFromServer();
}
}
List<Map> cats = await cacheDb.query('Activities');
print(cats.length);
for(Map element in cats){
String? type = element[Activity.colType].toString();
String? startTime = element[Activity.colStartTime].toString();
String? endTime = element[Activity.colStartTime].toString();
TaskType? taskType = await getTaskFromId(type);
if(type==null || startTime==null || endTime==null || taskType==null){
print("Something is null!");
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}");
continue;
}
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}");
_activities.add(Activity(taskType, DateTime.parse(startTime), DateTime.parse(endTime)));
}
activities = _activities;
return taskTypes;
}
Future<void> UpdateActivitiesFromServer() async{
print("Updating TaskTypes");
try {
http.Response response = (await http.post(
Uri.parse('http://161.97.127.136/task_tracker/get_activities.php'),
body: <String, String>{
"username": username,
"device_id": await Settings.UUID() ?? 'n/a'
}));
print(response.body);
List<String> data = response.body.split("<td>");
data.forEach((value) async {
Map<String, dynamic> cat = jsonDecode(value);
//print(catData);
await cacheDb.rawInsert(
"INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}) "
"VALUES ('${cat['type']}', '${cat['sTime']}','${cat['eTime']}') ");
});
}catch(e){
offline=true;
}
}
Future<TaskType?> getTaskFromId(String taskId) async{
// await GetTaskTypes(false);
TaskType? cat = null;
taskTypes.forEach((element) async{
if(element.id == taskId){
cat= element;
cat?.cat = await getCatFromId((cat?.category ?? ''));
}
});
return cat;
}
Future<Category?> getCatFromId(String catId) async{
// await GetTaskTypes(false);
Category? cat = null;
categories.forEach((element) {
if(element.category_id == catId){
cat= element;
}
});
return cat;
}
//Helpers
class Helpers {
Future<String?> _getId() async {
var deviceInfo = DeviceInfoPlugin();
if (Platform.isIOS) { // import 'dart:io'
var iosDeviceInfo = await deviceInfo.iosInfo;
return iosDeviceInfo.identifierForVendor; // unique ID on iOS
} else {
var androidDeviceInfo = await deviceInfo.androidInfo;
return androidDeviceInfo.androidId; // unique ID on Android
}
}
}
bool ParseBool(obj){
return obj.toString().toLowerCase()=="true" || obj.toString()=="1";
}
class UserOperations{
static Future<void> addCategory(String name, String color, bool productive, {bool bulk = false}) async{
Map<String,String> queryBody= <String,String>{
'username': username,
'device_id': await Settings.UUID() ?? 'n/a',
'name' : name,
'color':color,
'productive': productive ? '1':'0'
};
//Add Query
Map<String,Object> query = {
Queries.colLink: 'add_category',
Queries.colData: jsonEncode(queryBody)
};
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query);
//update Cache
Map<String,Object> data = {
Category.colCatId: username+name,
Category.colName: name,
Category.colColor: color,
Category.colProductive: productive
};
await cacheDb.insert('Categories', data);
await GetCategories(true);
if(!bulk){
//Add to server and refresh Cache
await executeQueries();
}
}
static Future<void> addTaskType(String name, String category, {bool bulk = false}) async{
Map<String,String> queryBody= <String,String>{
'id':username+name,
'username': username,
'device_id': await Settings.UUID() ?? 'n/a',
'name' : name,
'category': username + category
};
//Add Query
Map<String,Object> query = {
Queries.colLink: 'add_taskType',
Queries.colData: jsonEncode(queryBody)
};
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query);
//update Cache
Map<String,Object> data = {
TaskType.colId: username+name,
Category.colName: name,
Category.colCatId: username + category
};
await cacheDb.insert('TaskTypes', data);
await GetTaskTypes(true);
if(!bulk){
//Add to server and refresh Cache
await executeQueries();
}
}
static Future<void> deleteTask(String name,{bulk=false}) async{
Map<String,String> queryBody= <String,String>{
'id':username+name,
'username': username,
'device_id': await Settings.UUID() ?? 'n/a',
};
//Add Query
Map<String,Object> query = {
Queries.colLink: 'delete_taskType',
Queries.colData: jsonEncode(queryBody)
};
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query);
//update Cache
Map<String,Object> data = {
TaskType.colId: username+name,
Category.colName: name,
};
await cacheDb.rawDelete("DELETE FROM TaskTypes WHERE id='${username+name}'");
await GetTaskTypes(true);
//Add to server and refresh Cache
if(!bulk) {
await executeQueries();
}
}
static Future<void> deleteCategory(String name,{bulk=false}) async{
Map<String,String> queryBody= <String,String>{
'id':username+name,
'username': username,
'device_id': await Settings.UUID() ?? 'n/a',
};
//Add Query
Map<String,Object> query = {
Queries.colLink: 'delete_category',
Queries.colData: jsonEncode(queryBody)
};
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query);
//update Cache
Map<String,Object> data = {
TaskType.colId: username+name,
Category.colName: name,
};
await cacheDb.rawDelete("DELETE FROM Categories WHERE ${Category.colCatId}='${username+name}'");
await GetCategories(true);
//Add to server and refresh Cache
if(!bulk) {
await executeQueries();
}
}
static Future<void> executeQueries() async{
if(offline){
print("Cannot executre queries, Offline!");
return;
}
List<Map<String,Object?>> queries = await cacheDb.query('Queries');
for(Map<String,Object?> element in queries){
int id = int.parse(element['id'].toString());
String? file = element[Queries.colLink].toString();
String? data = element[Queries.colData].toString();
if(file==null || data==null){
print("Null query, Ignoring...");
continue;
}
print("Query[\n file:$file, \ndata:$data]");
//Execute the http here
Map<String, dynamic> body = jsonDecode(data);
try {
http.Response queryResponse = (await http.post(
Uri.parse('http://161.97.127.136/task_tracker/$file.php'),
body: body));
print("Query executed : Results{${queryResponse.body}");
if (queryResponse.body.toLowerCase().contains("success")) {
await cacheDb.rawDelete('DELETE FROM Queries WHERE id=$id');
}
offline=false;
}catch(e){
offline=true;
}
}
}
}

513
lib/Welcome.dart Normal file
View File

@@ -0,0 +1,513 @@
import 'dart:ui';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'User.dart' as Users;
import 'package:http/http.dart' as http;
class WelcomePage extends StatefulWidget {
const WelcomePage({Key? key}) : super(key: key);
@override
_WelcomePageState createState() => _WelcomePageState();
}
class _WelcomePageState extends State<WelcomePage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
color: Colors.pink,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Container(
// padding: EdgeInsets.all(20),
// alignment: Alignment.centerLeft,
// child: Text(
// 'WELCOME',
// style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
// textAlign: TextAlign.left,
// )),
Container(
height: 300,
padding: EdgeInsets.fromLTRB(0, 100, 0, 0),
child: Expanded(
child: Container(
child: Image(image: AssetImage('images/Launch.png')))),
),
Container(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Let's get started",
style: TextStyle(
fontSize: 30, fontWeight: FontWeight.bold)),
Divider(),
Text(
"Task Tracker is an App where you can track your daily activities, Analyze them and plan a better tomorrow.")
],
)),
Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
child: Text(''),
// onTap: () {
// Navigator.of(context).pushReplacementNamed('/');
// },
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const SignInPage()));
},
child: Text('Next', style: TextStyle(fontSize: 20)))
],
))
],
)),
));
}
}
class SignInPage extends StatefulWidget {
const SignInPage({Key? key}) : super(key: key);
@override
_SignInPageState createState() => _SignInPageState();
}
class _SignInPageState extends State<SignInPage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
color: Colors.deepPurpleAccent,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(padding: EdgeInsets.fromLTRB(0, 100, 0, 0),
height: 400,
child: Expanded(
child: Container(
child:
Image(image: AssetImage('images/signin.png'))),
)),
Container(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Sign in to stay connected",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold)),
Divider(),
Text(
"Sign in and enjoy the flawless connection between all your devices. You can track your day from any device and keep it together.")
],
)),
Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
const offlineLoginPage()));
},
child: Text('Use Offline',
style: TextStyle(fontSize: 20))),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
const onlineLoginPage()));
},
child: Text('Next',
style: TextStyle(fontSize: 20)))
],
))
]))));
}
}
class onlineLoginPage extends StatefulWidget {
const onlineLoginPage({Key? key}) : super(key: key);
@override
_onlineLoginPageState createState() => _onlineLoginPageState();
}
class _onlineLoginPageState extends State<onlineLoginPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
final usernameController = TextEditingController();
final passwordController = TextEditingController();
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 2);
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
color: Colors.purpleAccent,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Container(
// padding: EdgeInsets.all(20),
// alignment: Alignment.centerLeft,
// child: Text(
// 'Sign in online',
// style: TextStyle(
// fontSize: 40, fontWeight: FontWeight.bold),
// textAlign: TextAlign.left,
// ),
// ),
Container(
child: Expanded(
child: Container(
child:
Image(image: AssetImage('images/signin.png'))),
)),
Container(
padding: EdgeInsets.all(20),
child: Column(children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.purple),
child: Padding(
padding: EdgeInsets.all(10),
child: TabBar(
controller: _tabController,
indicator: BoxDecoration(
color: Colors.blueAccent,
borderRadius:
BorderRadius.circular(10)),
tabs: [
TabItem('Our Account'),
TabItem('OAuth')
],
))),
Divider(
height: 30,
),
Container(
height: 320,
child: TabBarView(
controller: _tabController,
children: [
Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(10),
color: Colors.purple),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.fromLTRB(
10, 10, 10, 0),
child: Text(
'Username',
style:
TextStyle(fontSize: 16),
)),
Container(
height: 70,
padding: EdgeInsets.all(10),
child: Expanded(
child: Container(
child: TextField(
controller: usernameController,
autocorrect: false,
style: TextStyle(
color: Colors.black,
),
decoration: InputDecoration(
hintText: 'Username',
filled: true,
fillColor:
Colors.white,
border: OutlineInputBorder(
borderRadius:
BorderRadius
.circular(
10))),
),
),
)),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.fromLTRB(
10, 10, 10, 0),
child: Text(
'Password',
style:
TextStyle(fontSize: 16),
)),
Container(
height: 70,
padding: EdgeInsets.all(10),
child: Expanded(
child: Container(
child: TextField(
controller: passwordController,
obscureText: true,
autocorrect: false,
enableSuggestions: false,
style: TextStyle(
fontWeight:
FontWeight.bold,
color: Colors.black,
),
decoration: InputDecoration(
hintText: 'Password',
filled: true,
fillColor:
Colors.white,
border: OutlineInputBorder(
borderRadius:
BorderRadius
.circular(
10))),
),
),
)),
Container(
width: 200,
padding: EdgeInsets.all(20),
child: ElevatedButton(
style: ElevatedButton
.styleFrom(
primary:
Colors.green),
onPressed: () {
login();
},
child: Text(
'Login',
style: TextStyle(
fontSize: 20),
)))
])),
Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(10),
color: Colors.purple),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Container(
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.green,
),
onPressed: (){}, child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.android),
SizedBox(width: 20,),
Text("Sign with Google", style: TextStyle(fontSize: 20))
],)),
),
Divider(height: 50,),
Container(
padding: EdgeInsets.all(50),
child:Text("New OAuth Sign in methods are on the way...")
)
]))
],
),
)
])),
Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red),
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Back',
style: TextStyle(fontSize: 20))),
SizedBox()
],
))
]))));
}
Widget TabItem(String text) {
return Text(text, style: TextStyle(fontSize: 20, color: Colors.white));
}
Future<void> login() async {
if(usernameController.text.length < 3 || passwordController.text.length < 3){
showAlertDialog(context, "Failed", "Please enter a valid username and password");
return;
}
http.Response loginResponse = await Users.login(usernameController.text, passwordController.text);
print(loginResponse.body);
if(loginResponse.body.toLowerCase().contains("success")){
final prefs = await SharedPreferences.getInstance();
prefs.setString("username", usernameController.text);
prefs.setString("password", passwordController.text);
Navigator.of(context).pushNamedAndRemoveUntil('/splash', (route) => false);
}else{
showAlertDialog(context, "Failed to login", "There was an error trying to authorize you in servers.");
}
}
}
showAlertDialog(BuildContext context, String title, String message) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () { Navigator.of(context).pop(); },
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text(title),
content: Text(message),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
class offlineLoginPage extends StatefulWidget {
const offlineLoginPage({Key? key}) : super(key: key);
@override
_offlineLoginPageState createState() => _offlineLoginPageState();
}
class _offlineLoginPageState extends State<offlineLoginPage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
color: Colors.deepOrange,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Container(
// padding: EdgeInsets.all(20),
// alignment: Alignment.centerLeft,
// child: Text(
// 'Offline Mode',
// style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
// textAlign: TextAlign.left,
// )),
Container(
// padding: EdgeInsets.all(50),
child: Expanded(
child: Container(
height: 400,
child: Image(
image: AssetImage('images/offline.png')))),
),
Container(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(
height: 30,
),
Text("Enter your name to continue",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold)),
SizedBox(
height: 30,
),
TextField(
decoration: InputDecoration(
hintText: 'ex: John doe',
focusColor: Colors.white,
border: OutlineInputBorder()),
),
Divider(
height: 30,
),
Text(
'Note: \nYou cannot use seemless multiple devices support with offline mode. \nYou can sign to online account anytime in settings page')
],
)),
Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.green),
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Sign online',
style: TextStyle(fontSize: 20))),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
const SignInPage()));
},
child: Text('Continue',
style: TextStyle(fontSize: 20)))
],
))
]))));
}
}

298
lib/main.dart Normal file
View File

@@ -0,0 +1,298 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:tasktracker/Categories.dart';
import 'package:tasktracker/Welcome.dart';
import 'package:tasktracker/splash.dart';
import 'package:wakelock/wakelock.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'NewTask.dart';
import 'newActivity.dart';
import 'Tasks.dart';
import 'User.dart' as User;
extension HexColor on Color {
/// String is in the format "aabbcc" or "ffaabbcc" with an optional leading "#".
static Color fromHex(String hexString) {
final buffer = StringBuffer();
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
buffer.write(hexString.replaceFirst('#', ''));
return Color(int.parse(buffer.toString(), radix: 16));
}
/// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`).
String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}'
'${alpha.toRadixString(16).padLeft(2, '0')}'
'${red.toRadixString(16).padLeft(2, '0')}'
'${green.toRadixString(16).padLeft(2, '0')}'
'${blue.toRadixString(16).padLeft(2, '0')}';
}
// To keep the screen on:
final List<PopulationData> data = [
PopulationData(
name: "Rocket League",
value: 45,
barColor: charts.ColorUtil.fromDartColor(Colors.blue)),
PopulationData(
name: "CS:GO",
value: 15,
barColor: charts.ColorUtil.fromDartColor(Colors.yellow)),
PopulationData(
name: "Halo",
value: 10,
barColor: charts.ColorUtil.fromDartColor(Colors.grey)),
PopulationData(
name: "SneakyPeaky",
value: 30,
barColor: charts.ColorUtil.fromDartColor(Colors.red)),
];
void main() {
Wakelock.enable(); // or Wakelock.toggle(on: true);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
accentColor: Colors.redAccent,
brightness: Brightness.dark,
primaryColor: Colors.amber,
fontFamily: 'Noto-Sans'),
//home: const MyHomePage(),
initialRoute: '/splash',
routes:{
'/splash':(context)=> const SplashScreen(),
'/welcome':(context)=> const WelcomePage(),
'/':(context) => const MyHomePage(),
'/Tasks':(context)=> const Tasks(),
'/Categories':(context)=>const Categories()
}
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<charts.Series<PopulationData, String>> series = [
charts.Series(
id: "Subscribers",
data: data,
domainFn: (PopulationData series, _) => series.name,
measureFn: (PopulationData series, _) => series.value,
colorFn: (PopulationData series, _) => series.barColor)
];
@override
void initState() {
// TODO: implement initState
super.initState();
showOfflineSnack();
}
void showOfflineSnack() async{
await Future.delayed(const Duration(seconds: 1));
if(User.offline){
const SnackBar offlineSnack = SnackBar(content: Text('Offline'),duration: Duration(seconds: 100),);
ScaffoldMessenger.of(context).showSnackBar(offlineSnack);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=> NewActivity()));
},
label: Text("New Activity"),
icon: Icon(Icons.add)
),
appBar: AppBar(title: Row(children:[Icon(Icons.article_outlined, color: Theme.of(context).primaryColor),SizedBox(width: 10),Text('Summary')])),
drawer: navDrawer(context,0),
body: SafeArea(
child: Container(
child: Column(
children: [
Container(
height: 300,
padding: EdgeInsets.all(20),
child: Card(
elevation: 8,
shadowColor: Colors.blueGrey,
child: Padding(
padding: EdgeInsets.all(8),
child: Column(
children: [
cardTitle('Daily Average'),
Expanded(
child: charts.BarChart(
series,
animate: true,
barRendererDecorator:
new charts.BarLabelDecorator(
labelPosition:
charts.BarLabelPosition.inside,
labelPadding: 10,
labelAnchor:
charts.BarLabelAnchor.middle),
))
],
)))),
Container(
height: 300,
padding: EdgeInsets.all(20),
child: Card(
elevation: 8,
shadowColor: Colors.green,
child: Padding(
padding: EdgeInsets.all(8),
child: Column(
children: [
cardTitle('Weekly Average'),
Expanded(
child: charts.BarChart(
series,
animate: true,
barRendererDecorator:
new charts.BarLabelDecorator(
labelPosition:
charts.BarLabelPosition.inside,
labelPadding: 10,
labelAnchor:
charts.BarLabelAnchor.middle),
))
],
))))
],
),
),
));
}
}
Widget cardTitle(String title) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:[
Padding(padding: EdgeInsets.all(20),child:Text(title,
style: TextStyle(fontWeight: FontWeight.bold))),
MaterialButton(onPressed: (){},child:moreButton())]);
}
Widget moreButton(){
return MaterialButton(
onPressed: (){
},
color: Colors.green,
child:Row(
children: [
Text('More'),Icon(Icons.keyboard_arrow_right)
],
));
}
class PopulationData {
String name;
int value;
charts.Color barColor;
PopulationData(
{required this.name, required this.value, required this.barColor});
}
Drawer navDrawer(BuildContext context, int pageIndex){
return Drawer(
child: ListView(
children: [
Padding(
padding: EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:[Text("Time Tracker",
style: TextStyle(
fontSize: 25,
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold)),
Icon(Icons.more_time,size: 30,),
])
),
Divider(),
ListTile(
selected: (pageIndex == 0),
title: Text('Summary'),
leading: Icon(Icons.article_outlined,color: Theme.of(context).primaryColor),
onTap: () {
if(pageIndex==0){return;}
Navigator.of(context).pushReplacementNamed('/');
},
),
ListTile(
selected: (pageIndex == 1),
title: Text('Analytics'),
leading: Icon(Icons.analytics_outlined,color: Theme.of(context).primaryColor),
onTap: () {
if(pageIndex==1){return;}
// Navigator.of(context).pushReplacementNamed('/');
},
),
Divider(),
ListTile(
selected: (pageIndex == 2),
title: Text('Activities'),
leading: Icon(Icons.task,color: Theme.of(context).primaryColor),
onTap: () {
if(pageIndex==2){return;}
Navigator.of(context).pushReplacementNamed('/Activities');
},
),
ListTile(
selected: (pageIndex == 3),
title: Text('Task Types'),
leading: Icon(Icons.task,color: Theme.of(context).primaryColor),
onTap: () {
if(pageIndex==3){return;}
Navigator.of(context).pushReplacementNamed('/Tasks');
},
),
ListTile(
selected: (pageIndex == 4),
title: Text('Categories'),
leading: Icon(Icons.account_tree_outlined,color: Theme.of(context).primaryColor),
onTap: () {
if(pageIndex==4){return;}
Navigator.of(context).pushReplacementNamed('/Categories');
},
),
Divider(),
ListTile(
selected: (pageIndex == 5),
title: Text('Settings'),
leading: Icon(Icons.settings,color: Colors.blueGrey),
onTap: () {
},
),
ListTile(
selected: (pageIndex == 6),
title: Text('About'),
leading: Icon(Icons.help_outline_outlined),
onTap: () {
},
),
],
));
}

210
lib/newActivity.dart Normal file
View File

@@ -0,0 +1,210 @@
import 'package:flutter/material.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:intl/intl.dart';
import 'User.dart' as User;
DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat durationFormat = DateFormat("HH:mm:ss");
class NewActivity extends StatefulWidget {
const NewActivity({Key? key}) : super(key: key);
@override
_NewActivity createState() => _NewActivity();
}
List<String> getActivitiesNames(){
List<String> _cats = [];
User.activities.forEach((element) {
String name = element.taskType.name;
_cats.add(name);
});
return _cats;
}
class _NewActivity extends State<NewActivity> {
String value = 'CS:GO';
DateTime startTime = DateTime.now();
DateTime endTime = DateTime.now().add(Duration(minutes: 30));
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('New Activity')),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 50, 20, 50),
child: Column(
children: [
Column(children: [
Container(
padding: EdgeInsets.all(10),
child: Text('Task')),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
decoration: BoxDecoration(
color: Colors.blueGrey,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey, width: 2)),
child: DropdownButton<String>(
dropdownColor: Colors.blueGrey,
iconSize: 30,
elevation: 10,
borderRadius: BorderRadius.circular(10),
value: value,
isExpanded: true,
items: <String>[
'Rocket League',
'CS:GO',
'HALO',
'Unity',
'Add new Task Type...'
].map<DropdownMenuItem<String>>(
(String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? _value) {
setState(() {
value = _value!;
});
})),
Container(
child: Divider(
height: 30,
)),
Container(
padding: EdgeInsets.all(10),
child: Text('Start Time')),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey, width: 2)),
child: MaterialButton(
onPressed: () {
setState(() {
DatePicker.showDateTimePicker(
context,
showTitleActions: true,
onChanged: (date) {
// print('change $date');
}, onConfirm: (date) {
setState(() {
startTime = date;
});
},
currentTime: startTime,
locale: LocaleType.en);
});
},
child: Text(
dateFormat.format(startTime),
style: TextStyle(
color: Colors.blue)))),
SizedBox(
height: 10,
),
Container(
padding: EdgeInsets.all(10),
child: Text('Ended Time')),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey, width: 2)),
child: MaterialButton(
onPressed: () {
setState(() {
DatePicker.showDateTimePicker(
context,
showTitleActions: true,
onChanged: (date) {
// print('change $date');
}, onConfirm: (date) {
setState(() {
endTime = date;
});
},
currentTime: endTime,
locale: LocaleType.en);
});
},
child: Text(dateFormat.format(endTime),
style: TextStyle(
color: Colors.blue)))),
SizedBox(
height: 30,
),
Text('Duration : ' +
_printDuration(
endTime.difference(startTime))),
Divider(
height: 30,
),
]),
],
))),
Container(
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 5,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: ElevatedButton(
style:ElevatedButton.styleFrom(
primary: Colors.red,
shape: StadiumBorder()
),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
child: Text('Back',
style: TextStyle(fontSize: 20))))),
Expanded(
flex: 6,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: ElevatedButton(
style:ElevatedButton.styleFrom(
primary: Colors.green,
shape: StadiumBorder()
),
onPressed: () {
setState(() {});
},
child: Text('Add Entry',
style: TextStyle(fontSize: 20))))),
],
))
])));
}
}
String _printDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}

73
lib/splash.dart Normal file
View File

@@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'User.dart' as Users;
import 'package:http/http.dart' as http;
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
// TODO: implement initState
super.initState();
init();
}
void init() async {
final prefs = await SharedPreferences.getInstance();
// http.Response loginResponse = await Users.login('Test1', 'password');
// print(loginResponse.body);
if (!prefs.containsKey("password") || !prefs.containsKey("username")) {
Navigator.of(context).pushNamedAndRemoveUntil('/welcome', (route) => false);
} else {
try {
http.Response loginResponse = await Users.login(
prefs.getString("username") ?? '',
prefs.getString("password") ?? '');
print(loginResponse.body);
if (loginResponse.body.toLowerCase().contains("success")) { //Login Success
Continue();
} else { //Login Failed
LoginFailed();
}
} catch (error) { //Login Failed
LoginFailed();
}
}
}
void LoginFailed() async{
bool dbExist = await Users.cacheDbExist();
if (dbExist) {
print('cache Database exists, Lets go CACHE!');
Continue();
} else {
Navigator.of(context).pushReplacementNamed('/welcome');
}
}
void Continue() async{
await Users.initUserData();
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.purple,
padding: EdgeInsets.all(80),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(image: AssetImage('images/logo.png')),
// Text('Loading', style:TextStyle(color: Colors.grey, fontSize: 20,fontStyle: FontStyle.italic))
]));
}
}

516
pubspec.lock Normal file
View File

@@ -0,0 +1,516 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
charts_common:
dependency: transitive
description:
name: charts_common
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0"
charts_flutter:
dependency: "direct main"
description:
name: charts_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
device_info_plus:
dependency: "direct main"
description:
name: device_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
device_info_plus_linux:
dependency: transitive
description:
name: device_info_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
device_info_plus_macos:
dependency: transitive
description:
name: device_info_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.2"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0+1"
device_info_plus_web:
dependency: transitive
description:
name: device_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
device_info_plus_windows:
dependency: transitive
description:
name: device_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_colorpicker:
dependency: "direct main"
description:
name: flutter_colorpicker
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
flutter_datetime_picker:
dependency: "direct main"
description:
name: flutter_datetime_picker
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.1"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
http:
dependency: "direct main"
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.4"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
intl:
dependency: "direct main"
description:
name: intl
url: "https://pub.dartlang.org"
source: hosted
version: "0.17.0"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
path_provider:
dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.4"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
shared_preferences_ios:
dependency: transitive
description:
name: shared_preferences_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.10"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
sn_progress_dialog:
dependency: "direct main"
description:
name: sn_progress_dialog
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
sqflite:
dependency: "direct main"
description:
name: sqflite
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
synchronized:
dependency: transitive
description:
name: synchronized
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.8"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
uuid:
dependency: "direct main"
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.5"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
wakelock:
dependency: "direct main"
description:
name: wakelock
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.1+1"
wakelock_macos:
dependency: transitive
description:
name: wakelock_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.0"
wakelock_platform_interface:
dependency: transitive
description:
name: wakelock_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
wakelock_web:
dependency: transitive
description:
name: wakelock_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.0"
wakelock_windows:
dependency: transitive
description:
name: wakelock_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.10"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+1"
sdks:
dart: ">=2.16.0 <3.0.0"
flutter: ">=2.8.0"

97
pubspec.yaml Normal file
View File

@@ -0,0 +1,97 @@
name: tasktracker
description: A new Flutter project.
# The following line prevents the package from being accidentally published to
# 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.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# 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.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.16.0 <3.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
cupertino_icons: ^1.0.2
uuid: ^3.0.5
wakelock: ^0.6.1+1
charts_flutter: ^0.12.0
flutter_datetime_picker: ^1.5.1
sqflite: ^2.0.2
intl: ^0.17.0
flutter_colorpicker: ^1.0.3
path_provider: ^2.0.9
shared_preferences: ^2.0.13
http: ^0.13.4
device_info_plus: ^3.2.1
sn_progress_dialog: ^1.0.3
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
# firebase_core: ^1.12.0
# firebase_analytics: ^9.1.0
# firebase_auth: ^3.3.7
# google_sign_in: ^5.2.3
# 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.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- images/
# An image asset can refer to one or more resolution-specific "variants", see
# 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
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
fonts:
- family: Noto-Sans
fonts:
- asset: fonts/NotoSans-Regular.ttf
- asset: fonts/NotoSans-Italic.ttf
- asset: fonts/NotoSans-Bold.ttf
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages

30
test/widget_test.dart Normal file
View File

@@ -0,0 +1,30 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tasktracker/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}