Showing preview only (393K chars total). Download the full file or copy to clipboard to get everything.
Repository: Mazahir26/koduko
Branch: master
Commit: 867245938a0a
Files: 132
Total size: 358.4 KB
Directory structure:
gitextract__iqieike/
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .metadata
├── CODE_OF_CONDUCT.md
├── LICENSE.md
├── README.md
├── analysis_options.yaml
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── com/
│ │ │ │ └── example/
│ │ │ │ └── koduko/
│ │ │ │ └── MainActivity.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21/
│ │ │ │ └── launch_background.xml
│ │ │ ├── values/
│ │ │ │ └── styles.xml
│ │ │ └── values-night/
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ └── settings.gradle
├── ios/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ └── Runner.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ ├── IDEWorkspaceChecks.plist
│ └── WorkspaceSettings.xcsettings
├── lib/
│ ├── components/
│ │ ├── card.dart
│ │ ├── create_routine_bottom_sheet.dart
│ │ ├── create_task_bottom_sheet.dart
│ │ ├── daily_activity.dart
│ │ ├── header.dart
│ │ ├── most_productive_hour.dart
│ │ ├── name_page_bottom_sheet.dart
│ │ ├── productive_day.dart
│ │ ├── routine_chart.dart
│ │ ├── routine_tile.dart
│ │ ├── task_tile.dart
│ │ ├── time_spent_today.dart
│ │ └── weekly_chart.dart
│ ├── main.dart
│ ├── models/
│ │ ├── routine.dart
│ │ ├── routine.g.dart
│ │ ├── task.dart
│ │ ├── task.g.dart
│ │ ├── task_event.dart
│ │ └── task_event.g.dart
│ ├── screens/
│ │ ├── about.dart
│ │ ├── app.dart
│ │ ├── archive_routines.dart
│ │ ├── home.dart
│ │ ├── onboarding.dart
│ │ ├── routines.dart
│ │ ├── settings.dart
│ │ ├── start_routine.dart
│ │ ├── stats.dart
│ │ └── tasks.dart
│ ├── services/
│ │ ├── notification_service.dart
│ │ ├── routines_provider.dart
│ │ ├── tasks_provider.dart
│ │ └── theme_provider.dart
│ └── utils/
│ ├── colors_util.dart
│ ├── date_time_extension.dart
│ ├── duration_to_string.dart
│ ├── greetings.dart
│ ├── parse_duration.dart
│ └── time_of_day_util.dart
├── linux/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter/
│ │ ├── CMakeLists.txt
│ │ ├── generated_plugin_registrant.cc
│ │ ├── generated_plugin_registrant.h
│ │ └── generated_plugins.cmake
│ ├── main.cc
│ ├── my_application.cc
│ └── my_application.h
├── macos/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── Flutter-Debug.xcconfig
│ │ ├── Flutter-Release.xcconfig
│ │ └── GeneratedPluginRegistrant.swift
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ ├── Configs/
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ └── Release.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ └── Runner.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── pubspec.yaml
├── test/
│ └── widget_test.dart
├── web/
│ ├── index.html
│ └── manifest.json
└── windows/
├── .gitignore
├── CMakeLists.txt
├── flutter/
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
└── runner/
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .gitignore
================================================
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
*.jks
# 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
================================================
FILE: .metadata
================================================
# 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.
version:
revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
- platform: android
create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
- platform: ios
create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
- platform: linux
create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
- platform: macos
create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
- platform: web
create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
- platform: windows
create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: LICENSE.md
================================================
Copyright 2021 Mazahir
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# Koduko
Yet another Habit tracker made with flutter.
## ❓ About
It's an open source and free app where you can manage your daily or weekly habits.
## 📢 Getting Started
You can install the latest APK from the [Releases tab](https://github.com/Mazahir26/koduko/releases/latest). You can also download the latest APK from [IzzyOnDroid repo](https://apt.izzysoft.de/fdroid/index/apk/com.example.koduko) within a F-Droid client.
Alternatively you can build the app yourself. See below for further information.
## 🔨 Build
- Clone the repo using `git clone https://github.com/Mazahir26/koduko.git`
- Install all the dependencies `flutter pub get`
- To test it out locally you can check this [guide](https://docs.flutter.dev/development/tools/vs-code)
- To build the apk follow this [guide](https://docs.flutter.dev/deployment/android)
## 👀 Preview
<img src="github_assets/image1.png " alt="ScreenShort 1" width="300"/><img src="github_assets/image2.png " alt="ScreenShort 2" width="300"/><img src="github_assets/image3.png " alt="ScreenShort 3" width="300"/>
## ⛩️ Features
- Notification Support,
- Material 3 Design,
- No ads,
- Insightful stats,
- And much more..
## 🐞 Found a Bug
If you found any bugs, please open an issue
or [contact me](http://mazahir26.github.io/)
_The app has only been tested on Android._
## 📝 License
This project is licensed under the [MIT License](LICENSE.md).
## ❤️ Thank You
Thanks for checking out my project, I would love to hear feedback, you can [contact](http://mazahir26.github.io/) me via Mail or Telegram.
[](https://www.buymeacoffee.com/mazahir)
================================================
FILE: analysis_options.yaml
================================================
# 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
# require_trailing_commas: true
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
================================================
FILE: android/.gitignore
================================================
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
================================================
FILE: android/app/build.gradle
================================================
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def keyStoreProperties= new Properties()
def keyStorePropertiesFile = rootProject.file('key.properties')
if (keyStorePropertiesFile.exists()) {
keyStorePropertiesFile.withReader('UTF-8') {reader ->
keyStoreProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
android {
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.koduko"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
signingConfigs {
release {
storeFile file(keyStoreProperties['storeFile'])
storePassword keyStoreProperties['storePassword']
keyAlias keyStoreProperties['keyAlias']
keyPassword keyStoreProperties['keyPassword']
v1SigningEnabled true
v2SigningEnabled true
enableV3Signing true
enableV4Signing true
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
// 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
// shrinkResources false
// }
// }
}
flutter {
source '../..'
}
dependencies {
}
================================================
FILE: android/app/src/debug/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.koduko">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
================================================
FILE: android/app/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.koduko">
<application
android:label="koduko"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<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>
================================================
FILE: android/app/src/main/kotlin/com/example/koduko/MainActivity.kt
================================================
package com.example.koduko
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
================================================
FILE: android/app/src/main/res/drawable/launch_background.xml
================================================
<?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>
================================================
FILE: android/app/src/main/res/drawable-v21/launch_background.xml
================================================
<?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>
================================================
FILE: android/app/src/main/res/values/styles.xml
================================================
<?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
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
================================================
FILE: android/app/src/main/res/values-night/styles.xml
================================================
<?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
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
================================================
FILE: android/app/src/profile/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.koduko">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
================================================
FILE: android/build.gradle
================================================
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
================================================
FILE: android/gradle/wrapper/gradle-wrapper.properties
================================================
#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-7.4-all.zip
================================================
FILE: android/gradle.properties
================================================
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
================================================
FILE: android/settings.gradle
================================================
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.2.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.20" apply false
}
include ":app"
================================================
FILE: ios/.gitignore
================================================
**/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
================================================
FILE: ios/Flutter/AppFrameworkInfo.plist
================================================
<?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>
================================================
FILE: ios/Flutter/Debug.xcconfig
================================================
#include "Generated.xcconfig"
================================================
FILE: ios/Flutter/Release.xcconfig
================================================
#include "Generated.xcconfig"
================================================
FILE: ios/Runner/AppDelegate.swift
================================================
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
================================================
FILE: ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images": [
{
"filename": "AppIcon@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "60x60"
},
{
"filename": "AppIcon@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "60x60"
},
{
"filename": "AppIcon~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "76x76"
},
{
"filename": "AppIcon@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "76x76"
},
{
"filename": "AppIcon-83.5@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "83.5x83.5"
},
{
"filename": "AppIcon-40@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "40x40"
},
{
"filename": "AppIcon-40@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "40x40"
},
{
"filename": "AppIcon-40~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "40x40"
},
{
"filename": "AppIcon-40@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "40x40"
},
{
"filename": "AppIcon-20@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "20x20"
},
{
"filename": "AppIcon-20@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "20x20"
},
{
"filename": "AppIcon-20~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "20x20"
},
{
"filename": "AppIcon-20@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "20x20"
},
{
"filename": "AppIcon-29.png",
"idiom": "iphone",
"scale": "1x",
"size": "29x29"
},
{
"filename": "AppIcon-29@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "29x29"
},
{
"filename": "AppIcon-29@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "29x29"
},
{
"filename": "AppIcon-29~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "29x29"
},
{
"filename": "AppIcon-29@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "29x29"
},
{
"filename": "AppIcon-60@2x~car.png",
"idiom": "car",
"scale": "2x",
"size": "60x60"
},
{
"filename": "AppIcon-60@3x~car.png",
"idiom": "car",
"scale": "3x",
"size": "60x60"
},
{
"filename": "AppIcon~ios-marketing.png",
"idiom": "ios-marketing",
"scale": "1x",
"size": "1024x1024"
}
],
"info": {
"author": "iconkitchen",
"version": 1
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
================================================
{
"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"
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
================================================
# 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.
================================================
FILE: ios/Runner/Base.lproj/LaunchScreen.storyboard
================================================
<?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>
================================================
FILE: ios/Runner/Base.lproj/Main.storyboard
================================================
<?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>
================================================
FILE: ios/Runner/Info.plist
================================================
<?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>Koduko</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>koduko</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/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
================================================
FILE: ios/Runner/Runner-Bridging-Header.h
================================================
#import "GeneratedPluginRegistrant.h"
================================================
FILE: ios/Runner.xcodeproj/project.pbxproj
================================================
// !$*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.example.koduko;
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.example.koduko;
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.example.koduko;
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 */;
}
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?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>
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
<?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>
================================================
FILE: ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
================================================
<?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>
================================================
FILE: ios/Runner.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?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>
================================================
FILE: ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
<?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>
================================================
FILE: lib/components/card.dart
================================================
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:koduko/utils/duration_to_string.dart';
class TaskCard extends StatelessWidget {
final String name;
final AnimationController? controller;
final Color color;
final double index;
final void Function(DismissDirection, BuildContext) onDismissed;
final bool isPlaying;
final AnimationController buttonController;
final void Function(TapUpDetails details) onTap;
final bool isCompleted;
final bool isSkipped;
late final Tween<double> tween;
late final Color textColor;
final bool isSwipeDisabled;
TaskCard(
{super.key,
required this.name,
required this.controller,
required this.color,
required this.index,
required this.onDismissed,
required this.isPlaying,
required this.buttonController,
required this.onTap,
required this.isCompleted,
required this.isSkipped,
required this.isSwipeDisabled}) {
if (controller != null) {
if (isCompleted) {
tween = Tween(
begin: 0,
end: 400,
);
} else if (isSkipped) {
tween = Tween(
begin: 0,
end: -400,
);
} else {
tween = Tween(begin: 0, end: 0);
}
} else {
tween = Tween(begin: 0, end: 0);
}
textColor =
color.computeLuminance() > 0.5 ? Colors.grey[800]! : Colors.white;
}
String get timerString {
if (controller == null) {
return "0:00";
}
Duration duration =
controller!.duration! - (controller!.duration! * controller!.value);
return durationToString(duration);
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ConstrainedBox(
constraints: const BoxConstraints(
minHeight: 300,
),
child: TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 300),
tween: tween,
onEnd: () {
if (isSkipped) {
onDismissed(DismissDirection.endToStart, context);
} else if (isCompleted) {
onDismissed(DismissDirection.startToEnd, context);
}
},
builder: (context, double value, child) => Transform.translate(
offset: Offset(value, 0),
child: child,
),
child: AnimatedRotation(
duration: const Duration(milliseconds: 100),
curve: Curves.easeInCirc,
turns: index < 6 ? index / 200 : 5 / 200,
child: AnimatedPadding(
duration: const Duration(milliseconds: 100),
curve: Curves.easeInCirc,
padding: EdgeInsets.only(
left: index < 6 ? index * 10 : 5 * 10,
bottom: index < 6 ? index * 10 : 5 * 10),
child: Dismissible(
key: UniqueKey(),
confirmDismiss: (direction) {
if (direction == DismissDirection.endToStart &&
isSwipeDisabled) {
return Future((() => false));
}
return Future((() => true));
},
onDismissed: ((direction) => onDismissed(direction, context)),
child: Stack(
alignment: AlignmentDirectional.bottomEnd,
children: [
Container(
height: 300,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color:
Theme.of(context).shadowColor.withOpacity(0.4),
blurRadius: 4.0,
spreadRadius: 0.2,
)
],
),
),
Container(
height: 300,
decoration: BoxDecoration(
color: color.withOpacity(0.4),
borderRadius: BorderRadius.circular(20),
),
),
controller == null
? Container(
height: 40,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(20),
),
)
: AnimatedBuilder(
animation: controller!,
builder: (context, child) {
return Container(
height: controller!.value * 260 + 40,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.only(
bottomLeft: const Radius.circular(20),
bottomRight: const Radius.circular(20),
topLeft: Radius.circular(
controller!.value * 15 + 5,
),
topRight: Radius.circular(
controller!.value * 15 + 5,
),
),
),
);
},
),
// Display's the remaining time of the Task
Positioned(
bottom: 15,
left: 10,
child: controller == null
? Text(
"0:00",
style: TextStyle(
color: textColor,
fontSize: 26,
fontWeight: FontWeight.w500),
)
: AnimatedBuilder(
animation: controller!,
builder: ((context, child) => Text(
timerString,
style: TextStyle(
color: textColor,
fontSize: 26,
fontWeight: FontWeight.w500,
),
))),
),
// The Play-Pause Button on the Card
GestureDetector(
onTapUp: onTap,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: AnimatedIcon(
icon: AnimatedIcons.play_pause,
progress: buttonController,
color: textColor,
size: 45,
),
),
),
// The Name of the Task
Positioned.fill(
child: Align(
child: Text(
name,
style: GoogleFonts.lato(
fontWeight: FontWeight.bold,
textStyle: Theme.of(context)
.textTheme
.apply(displayColor: textColor)
.displaySmall,
),
),
))
],
),
),
),
),
),
),
);
}
}
================================================
FILE: lib/components/create_routine_bottom_sheet.dart
================================================
import 'package:flutter/material.dart';
import 'package:koduko/components/name_page_bottom_sheet.dart';
import 'package:koduko/models/routine.dart';
import 'package:koduko/models/task.dart';
import 'package:koduko/screens/tasks.dart';
import 'package:koduko/services/tasks_provider.dart';
import 'package:koduko/utils/duration_to_string.dart';
import 'package:koduko/utils/parse_duration.dart';
import 'package:koduko/utils/time_of_day_util.dart';
import 'package:provider/provider.dart';
enum RepeatType {
daily,
onlyOn,
}
class CreateRoutineBottomSheet extends StatefulWidget {
const CreateRoutineBottomSheet({
super.key,
this.editRoutine,
});
final Routine? editRoutine;
@override
State<CreateRoutineBottomSheet> createState() =>
_CreateRoutineBottomSheetState();
}
class _CreateRoutineBottomSheetState extends State<CreateRoutineBottomSheet> {
late final PageController _pageController;
late final TextEditingController _nameController;
final List<Task> selectedTask = [];
Map<String, bool> selectedDays = {
"Monday": true,
"Tuesday": true,
"Wednesday": true,
"Thursday": true,
"Friday": true,
"Saturday": true,
"Sunday": true,
};
int pageIndex = 0;
bool pageComplected = false;
bool notifications = true;
TimeOfDay? time =
TimeOfDay(hour: TimeOfDay.now().hour + 1, minute: TimeOfDay.now().minute);
@override
void initState() {
_pageController = PageController();
_nameController = TextEditingController();
if (widget.editRoutine != null) {
_nameController.text = widget.editRoutine!.name;
selectedDays = selectedDays.map((key, value) =>
MapEntry(key, widget.editRoutine!.days.contains(key)));
for (var element in widget.editRoutine!.tasks) {
selectedTask.add(element);
}
if (widget.editRoutine!.time != null) {
time = dateTimeToTimeOfDay(widget.editRoutine!.time!);
} else {
notifications = false;
time = TimeOfDay(
hour: TimeOfDay.now().hour + 1, minute: TimeOfDay.now().minute);
}
pageComplected = true;
}
super.initState();
}
void validateName(String _) {
if (_nameController.text.length > 2) {
if (!pageComplected) {
setState(() {
pageComplected = true;
});
}
} else if (pageComplected) {
setState(() {
pageComplected = false;
});
}
}
void onChangeRepeatType(RepeatType r) {
if (r == RepeatType.daily) {
setState(() {
selectedDays = selectedDays.map((key, value) => MapEntry(key, true));
pageComplected = true;
});
} else {
setState(() {
pageComplected = false;
selectedDays = selectedDays.map((key, value) => MapEntry(key, false));
});
}
}
void onDayChange(String e, bool value) {
setState(() {
selectedDays[e] = value;
if (selectedDays.values.contains(true)) {
pageComplected = true;
} else {
pageComplected = false;
}
});
}
// void onTap(bool selected, int index, BuildContext context) {
// if (selected) {
// if (selectedTask.length == 1) {
// setState(() {
// selectedTask.removeWhere((element) =>
// element.id ==
// Provider.of<TaskModel>(context, listen: false).tasks[index].id);
// pageComplected = false;
// });
// } else {
// setState(() {
// selectedTask.removeWhere((element) =>
// element.id ==
// Provider.of<TaskModel>(context, listen: false).tasks[index].id);
// });
// }
// } else {
// setState(() {
// selectedTask
// .add(Provider.of<TaskModel>(context, listen: false).tasks[index]);
// pageComplected = true;
// });
// }
// }
void onAdd(Task t) {
setState(() {
selectedTask.add(t);
pageComplected = true;
});
}
void onRemove(int index) {
if (selectedTask.length == 1) {
setState(() {
selectedTask.removeAt(index);
pageComplected = false;
});
return;
}
setState(() {
selectedTask.removeAt(index);
});
}
@override
void dispose() {
_pageController.dispose();
_nameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(
top: 10,
right: 10,
left: 10,
bottom: MediaQuery.of(context).viewInsets.bottom + 10),
child: Wrap(
children: [
Center(
child: Column(
children: [
const Icon(
Icons.drag_handle_rounded,
size: 26,
),
Text(
"Create a Routine",
style: Theme.of(context).textTheme.headlineSmall,
),
],
),
),
Padding(
padding: const EdgeInsets.all(15),
child: TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 250),
tween: Tween<double>(
begin: 0.25,
end: pageIndex == 1
? 0.7
: pageIndex == 0
? 0.25
: 0.4),
builder: (context, value, child) => SizedBox(
height: MediaQuery.of(context).size.height * value,
child: child,
),
child: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
children: [
NamePage(
nameController: _nameController,
validateName: validateName,
pageComplected: pageComplected,
hintText: "ex. Gym",
title: "Routine Name",
),
TaskSelectPage(
onChangeOrder: (oldIndex, newIndex) {
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final item = selectedTask.removeAt(oldIndex);
selectedTask.insert(newIndex, item);
});
},
onTapDelete: onRemove,
selectedTask: selectedTask,
onTapAdd: onAdd,
),
RepeatPage(
notification: notifications,
onChangeTime: ((t) => setState(() {
time = t;
})),
onToggleNotification: () => setState(() {
notifications = !notifications;
}),
time: time,
onDayChange: onDayChange,
selectedDays: selectedDays,
onChangeRepeatType: onChangeRepeatType,
)
],
),
),
),
Buttons(
text: pageIndex == 2 ? "Done" : null,
pageIndex: pageIndex,
onPrevious: () {
setState(() {
pageIndex--;
});
if (pageIndex == 0) {
validateName("");
}
if (pageIndex == 1) {
setState(() {
pageComplected = selectedTask.isNotEmpty;
});
}
_pageController.previousPage(
duration: const Duration(milliseconds: 350),
curve: Curves.easeIn,
);
},
onNext: pageComplected
? () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
if (pageIndex == 2) {
List<String> temp = [];
selectedDays.forEach((key, value) {
if (value) {
temp.add(key);
}
});
if (widget.editRoutine != null) {
List<Task> diff = Routine.taskDiff(
widget.editRoutine!.tasks, selectedTask);
if (selectedTask.length >
widget.editRoutine!.tasks.length) {
diff.addAll(widget.editRoutine!.inCompletedTasks);
} else {
diff = Routine.taskDiff(
diff, widget.editRoutine!.inCompletedTasks);
}
return Navigator.pop(
context,
widget.editRoutine!.copyWith(
tasks: selectedTask,
name: _nameController.text,
days: temp,
time: notifications ? time : null,
inCompletedTasks: diff,
isCompleted: diff.isEmpty,
));
} else {
return Navigator.pop(
context,
Routine.create(
name: _nameController.text,
tasks: selectedTask,
days: temp,
time: notifications
? timeOfDayToDateTime(time)
: null,
),
);
}
}
_pageController.nextPage(
duration: const Duration(milliseconds: 350),
curve: Curves.easeIn,
);
if (pageIndex == 0) {
if (selectedTask.isEmpty) {
setState(() {
pageIndex++;
pageComplected = false;
});
return;
}
}
if (pageIndex == 1) {
if (!selectedDays.values.contains(true)) {
setState(() {
pageComplected = false;
pageIndex++;
});
return;
}
}
setState(() {
pageIndex++;
});
}
: null)
],
),
);
}
}
class Buttons extends StatelessWidget {
const Buttons({
super.key,
required this.pageIndex,
required this.onNext,
required this.onPrevious,
required this.text,
});
final int pageIndex;
final void Function()? onNext;
final void Function() onPrevious;
final String? text;
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
flex: 3,
child: pageIndex != 0
? ElevatedButton.icon(
style: ElevatedButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
backgroundColor:
Theme.of(context).colorScheme.secondaryContainer,
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
onPressed: onPrevious,
icon: const Icon(Icons.chevron_left_sharp),
label: Text(
"Back",
style: Theme.of(context).textTheme.bodyLarge,
),
)
: TextButton(
onPressed: (() {
Navigator.pop(context);
}),
child: Text("Cancel",
style: Theme.of(context).textTheme.bodyLarge),
),
),
const Spacer(
flex: 2,
),
Expanded(
flex: 3,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
onPressed: onNext,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
text ?? "Next",
style: Theme.of(context).textTheme.bodyLarge,
),
text == null
? const Icon(Icons.chevron_right_sharp)
: Container()
],
),
),
)
],
);
}
}
class TaskSelectPage extends StatelessWidget {
const TaskSelectPage({
super.key,
required this.selectedTask,
required this.onTapAdd,
required this.onTapDelete,
required this.onChangeOrder,
});
final List<Task> selectedTask;
final void Function(Task task) onTapAdd;
final void Function(int index) onTapDelete;
final void Function(int oldIndex, int newIndex) onChangeOrder;
@override
Widget build(BuildContext context) {
return Consumer<TaskModel>(builder: ((context, value, child) {
if (value.tasks.isEmpty) {
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Looks like you haven't created any tasks",
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
TextButton(
onPressed: () {
Navigator.pushNamed(
context,
TasksScreen.routeName,
);
},
child: const Text(
"Create One",
style: TextStyle(fontSize: 18),
))
],
),
);
}
return ReorderableListView(
header: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Select Tasks',
style: Theme.of(context).textTheme.headlineMedium!.apply(
color: Theme.of(context).colorScheme.onSurface)),
TextButton.icon(
onPressed: (() {
Navigator.pushNamed(
context,
TasksScreen.routeName,
);
}),
icon: const Icon(Icons.edit_rounded),
label: Text(
'Edit Tasks',
style: Theme.of(context).textTheme.titleMedium!.apply(
color: Theme.of(context).colorScheme.primary,
),
),
)
],
),
const SizedBox(height: 35),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Selected Tasks',
style: Theme.of(context).textTheme.titleLarge!),
Text(
'Selected (${selectedTask.length})',
style: Theme.of(context)
.textTheme
.titleMedium!
.apply(color: Theme.of(context).colorScheme.primary),
),
],
),
const SizedBox(height: 10),
],
),
footer: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 15),
Text('Tasks', style: Theme.of(context).textTheme.titleLarge!),
const SizedBox(height: 10),
if (value.tasks.isEmpty)
Column(
children: [
const SizedBox(height: 15),
Center(
child: Text('Looks Empty! ',
style: Theme.of(context).textTheme.titleMedium!),
),
TextButton(
onPressed: () {
Navigator.pushNamed(
context,
TasksScreen.routeName,
);
},
child: const Text("Add a Task?"))
],
)
else
...value.tasks
.asMap()
.map((key, value) => MapEntry(
key,
Card(
key: Key('$key+${value.id}'),
child: ListTile(
trailing: TextButton.icon(
icon: const Icon(Icons.add),
label: const Text("ADD"),
onPressed: () => onTapAdd(value),
),
subtitle: Text(
'Duration : ${durationToString(parseDuration(value.duration))} Min',
style: Theme.of(context)
.textTheme
.bodyMedium!
.apply(
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.8)),
),
title: Text(
value.name,
style: Theme.of(context).textTheme.titleMedium,
)),
)))
.values
],
),
onReorder: onChangeOrder,
buildDefaultDragHandles: false,
children: [
if (selectedTask.isEmpty)
Padding(
key: const Key("empty"),
padding: const EdgeInsets.symmetric(vertical: 25),
child: Center(
child: Text('Select a task and it appears here!',
style: Theme.of(context).textTheme.titleMedium!),
),
),
for (int index = 0; index < selectedTask.length; index++)
Card(
key: Key('$index'),
child: ReorderableDelayedDragStartListener(
index: index,
child: ListTile(
leading: IconButton(
icon: const Icon(Icons.remove),
color: Theme.of(context).colorScheme.error,
onPressed: () => onTapDelete(index),
),
trailing: ReorderableDragStartListener(
index: index,
child: const Icon(Icons.drag_handle_rounded),
),
subtitle: Text(
'Duration : ${durationToString(parseDuration(selectedTask[index].duration))} Min',
style: Theme.of(context).textTheme.bodyMedium!.apply(
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.8)),
),
title: Text(
selectedTask[index].name,
style: Theme.of(context).textTheme.titleMedium,
)),
),
),
],
);
}));
}
}
class RepeatPage extends StatelessWidget {
const RepeatPage({
super.key,
required this.onDayChange,
required this.selectedDays,
required this.onChangeRepeatType,
required this.time,
required this.onChangeTime,
required this.onToggleNotification,
required this.notification,
});
final void Function(String, bool) onDayChange;
final Map<String, bool> selectedDays;
final void Function(RepeatType) onChangeRepeatType;
final TimeOfDay? time;
final void Function(TimeOfDay time) onChangeTime;
final void Function() onToggleNotification;
final bool notification;
@override
Widget build(BuildContext context) {
Future<void> selectTime(BuildContext context) async {
TimeOfDay? pickedTime = await showTimePicker(
context: context,
initialTime: time ?? TimeOfDay.now(),
builder: (context, child) => MediaQuery(
data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: false),
child: child ?? Container(),
),
);
if (pickedTime != null && pickedTime != time) {
onChangeTime(pickedTime);
}
}
return ListView(
children: [
Text(
"Repeat",
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(
height: 15,
),
Wrap(
children: [
ChoiceChip(
label: const Text("Daily"),
pressElevation: 0,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.horizontal(left: Radius.circular(5)),
),
selected: !selectedDays.values.contains(false),
backgroundColor: Theme.of(context).colorScheme.onInverseSurface,
onSelected: (value) => onChangeRepeatType(RepeatType.daily),
selectedColor: Theme.of(context).colorScheme.inversePrimary,
labelStyle: Theme.of(context).textTheme.titleMedium,
),
ChoiceChip(
label: const Text("Only on"),
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.horizontal(right: Radius.circular(5)),
),
pressElevation: 0,
selected: selectedDays.values.contains(false),
backgroundColor: Theme.of(context).colorScheme.onInverseSurface,
onSelected: (value) => onChangeRepeatType(RepeatType.onlyOn),
selectedColor: Theme.of(context).colorScheme.inversePrimary,
labelStyle: Theme.of(context).textTheme.titleMedium,
),
],
),
selectedDays.values.contains(false)
? Wrap(
spacing: 2,
runSpacing: -8,
children: selectedDays.keys
.map(
(e) => Padding(
padding: const EdgeInsets.all(4.0),
child: ChoiceChip(
elevation: 3,
label: Text(e),
selected: selectedDays[e] ?? false,
backgroundColor:
Theme.of(context).colorScheme.onInverseSurface,
onSelected: (value) => onDayChange(e, value),
selectedColor:
Theme.of(context).colorScheme.inversePrimary,
labelStyle: Theme.of(context).textTheme.labelMedium,
),
),
)
.toList())
: Container(),
const SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Notification",
style: Theme.of(context).textTheme.titleLarge,
),
TextButton.icon(
onPressed: onToggleNotification,
icon: notification
? const Icon(Icons.notifications_active_rounded)
: const Icon(Icons.notifications_off_rounded),
label: notification ? const Text("ON") : const Text("OFF"))
],
),
notification
? Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Select Time",
style: Theme.of(context).textTheme.titleMedium,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
onPressed: () => selectTime(context),
child: time == null
? const Text("Select Time")
: Text(
time!.format(context),
),
),
],
),
)
: Container()
],
);
}
}
================================================
FILE: lib/components/create_task_bottom_sheet.dart
================================================
import 'package:duration_picker/duration_picker.dart';
import 'package:flutter/material.dart';
import 'package:koduko/components/name_page_bottom_sheet.dart';
import 'package:koduko/models/task.dart';
import 'package:koduko/utils/duration_to_string.dart';
import 'package:koduko/utils/parse_duration.dart';
class CreateTaskBottomSheet extends StatefulWidget {
const CreateTaskBottomSheet({super.key, this.task});
final Task? task;
@override
State<CreateTaskBottomSheet> createState() => _CreateTaskBottomSheetState();
}
class _CreateTaskBottomSheetState extends State<CreateTaskBottomSheet> {
late final PageController _pageController;
late final TextEditingController _nameController;
static const chipList = <String, Duration>{
"30 sec": Duration(seconds: 30),
"1 min": Duration(minutes: 1),
"2 mins": Duration(minutes: 2),
"5 mins": Duration(minutes: 5),
"10 mins": Duration(minutes: 10),
"15 mins": Duration(minutes: 15),
"20 mins": Duration(minutes: 20),
"25 mins": Duration(minutes: 25),
"30 mins": Duration(minutes: 30),
"Custom": Duration(minutes: 5),
};
static const colorList = [
Colors.blue,
Colors.amber,
Colors.brown,
Colors.yellow,
Colors.teal,
Colors.purple,
Colors.red,
];
Duration customTime = const Duration(minutes: 5);
String? _value;
int? _selectedColor;
int pageIndex = 0;
bool pageComplected = false;
@override
void initState() {
_pageController = PageController();
_nameController = TextEditingController();
if (widget.task != null) {
_nameController.text = widget.task!.name;
_value = chipList.keys.firstWhere((element) =>
chipList[element] == parseDuration(widget.task!.duration));
_selectedColor = colorList
.indexWhere((element) => element.value == widget.task!.color);
pageComplected = true;
}
super.initState();
}
void validateName(String _) {
if (_nameController.text.length > 2) {
if (!pageComplected) {
setState(() {
pageComplected = true;
});
}
} else if (pageComplected) {
setState(() {
pageComplected = false;
});
}
}
void validateDuration() {
if (_value == null) {
setState(() {
pageComplected = false;
});
} else {
setState(() {
pageComplected = true;
});
}
}
void validateColor() {
if (_selectedColor == null) {
setState(() {
pageComplected = false;
});
} else {
setState(() {
pageComplected = true;
});
}
}
void onChangeChip(bool selected, int index, BuildContext context) async {
if (chipList.keys.toList()[index] == 'Custom') {
final r = await showDurationPicker(
context: context,
initialTime: _value != null
? _value == 'Custom'
? customTime
: chipList[_value] ?? customTime
: customTime,
baseUnit: BaseUnit.second,
lowerBound: const Duration(seconds: 15),
upperBound: const Duration(hours: 1),
);
if (r == null) {
return;
}
setState(() {
customTime = r;
_value = 'Custom';
});
validateDuration();
return;
}
setState(() {
_value = selected ? chipList.keys.toList()[index] : null;
});
validateDuration();
}
// Future<bool> onCustomDurationSelect(BuildContext context) async {
// final result = await Picker(
// adapter: NumberPickerAdapter(data: <NumberPickerColumn>[
// const NumberPickerColumn(begin: 0, end: 30, suffix: Text(' minutes')),
// const NumberPickerColumn(begin: 5, end: 60, suffix: Text(' seconds')),
// ]),
// backgroundColor: Theme.of(context).colorScheme.surface,
// onBuilderItem: (context, text, child, selected, col, index) {
// String t = text == null
// ? ''
// : col == 0
// ? '$text min'
// : '$text sec';
// return Center(
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// children: [
// Text(
// t,
// style: selected
// ? Theme.of(context)
// .textTheme
// .titleLarge!
// .apply(color: Theme.of(context).colorScheme.primary)
// : Theme.of(context).textTheme.titleMedium,
// )
// ],
// ),
// );
// },
// looping: true,
// magnification: 1.1,
// itemExtent: 50,
// hideHeader: true,
// confirmText: 'Select',
// title: const Text('Select duration'),
// onConfirm: (Picker picker, List<int> value) {
// Duration duration = Duration(
// minutes: picker.getSelectedValues()[0],
// seconds: picker.getSelectedValues()[1]);
// setState(() {
// customTime = duration;
// });
// validateDuration();
// },
// ).showDialog(context);
// if (result == null) {
// return false;
// } else {
// return true;
// }
// }
void onChangeColor(int index) {
setState(() {
_selectedColor = index;
});
validateColor();
}
@override
void dispose() {
_pageController.dispose();
_nameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(
top: 10,
right: 10,
left: 10,
bottom: MediaQuery.of(context).viewInsets.bottom + 10),
child: Wrap(
children: [
Center(
child: Column(
children: [
const Icon(
Icons.drag_handle_rounded,
size: 26,
),
Text(
"Create a Task",
style: Theme.of(context).textTheme.headlineSmall,
),
],
),
),
Padding(
padding: const EdgeInsets.all(15),
child: SizedBox(
height: MediaQuery.of(context).size.height / 4,
child: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
children: [
NamePage(
nameController: _nameController,
validateName: validateName,
pageComplected: pageComplected,
hintText: "ex. push up",
title: "Task Name",
),
DurationPage(
customDuration: customTime,
onChange: onChangeChip,
chipList: chipList,
value: _value,
),
ColorPage(
onChange: onChangeColor,
colorList: colorList,
selectedColor: _selectedColor,
)
],
),
),
),
Buttons(
text: pageIndex == 2 ? "Done" : null,
pageIndex: pageIndex,
onPrevious: () {
setState(() {
pageIndex--;
});
if (pageIndex == 0) {
validateName("");
}
if (pageIndex == 1) {
validateDuration();
}
_pageController.previousPage(
duration: const Duration(milliseconds: 350),
curve: Curves.easeIn,
);
},
onNext: pageComplected
? () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
setState(() {
pageIndex++;
});
if (pageIndex == 1) {
validateDuration();
}
if (pageIndex == 2) {
validateColor();
}
if (pageIndex == 3) {
final dur = _value! == 'Custom'
? customTime
: chipList[_value]!;
Navigator.pop(
context,
Task.fromDuration(
duration: dur,
name: _nameController.text,
color: colorList[_selectedColor!]));
}
_pageController.nextPage(
duration: const Duration(milliseconds: 350),
curve: Curves.easeIn,
);
}
: null)
],
),
);
}
}
class Buttons extends StatelessWidget {
const Buttons({
super.key,
required this.pageIndex,
required this.onNext,
required this.onPrevious,
required this.text,
});
final int pageIndex;
final void Function()? onNext;
final void Function() onPrevious;
final String? text;
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
flex: 3,
child: pageIndex != 0
? ElevatedButton.icon(
style: ElevatedButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
backgroundColor:
Theme.of(context).colorScheme.secondaryContainer,
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
onPressed: onPrevious,
icon: const Icon(Icons.chevron_left_sharp),
label: Text(
"Back",
style: Theme.of(context).textTheme.bodyLarge,
),
)
: TextButton(
onPressed: (() {
Navigator.pop(context);
}),
child: Text("Cancel",
style: Theme.of(context).textTheme.bodyLarge),
),
),
const Spacer(
flex: 2,
),
Expanded(
flex: 3,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
onPressed: onNext,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
text ?? "Next",
style: Theme.of(context).textTheme.bodyLarge,
),
text == null
? const Icon(Icons.chevron_right_sharp)
: Container()
],
),
),
)
],
);
}
}
class DurationPage extends StatelessWidget {
const DurationPage(
{super.key,
required this.onChange,
required this.chipList,
required this.value,
required this.customDuration});
final void Function(bool, int, BuildContext) onChange;
final Map<String, Duration> chipList;
final String? value;
final Duration customDuration;
@override
Widget build(BuildContext context) {
return ListView(
children: [
Text(
"Select a Duration",
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(
height: 15,
),
Wrap(
spacing: 6,
children: List<Widget>.generate(
chipList.length,
(index) => ChoiceChip(
label: Text(
value == 'Custom' && chipList.keys.toList()[index] == 'Custom'
? '${durationToString(customDuration)} min'
: chipList.keys.toList()[index]),
selected: value == chipList.keys.toList()[index],
selectedColor:
Theme.of(context).colorScheme.primary.withOpacity(0.7),
backgroundColor:
Theme.of(context).colorScheme.primary.withOpacity(0.15),
labelStyle: Theme.of(context).textTheme.labelLarge!.apply(
color: value == chipList.keys.toList()[index]
? Theme.of(context).colorScheme.onSecondary
: Theme.of(context).colorScheme.onSurface),
onSelected: (bool selected) => onChange(selected, index, context),
),
),
),
],
);
}
}
class ColorPage extends StatelessWidget {
const ColorPage(
{super.key,
required this.onChange,
required this.colorList,
required this.selectedColor});
final void Function(int) onChange;
final List<Color> colorList;
final int? selectedColor;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Pick a Color",
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(
height: 15,
),
Wrap(
spacing: 5,
children: List<Widget>.generate(
colorList.length,
(index) => GestureDetector(
onTap: () => onChange(index),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.all(3),
decoration: BoxDecoration(
border: Border.all(
color: selectedColor == index
? Colors.blueAccent
: Theme.of(context).colorScheme.surface,
width: 3,
),
shape: BoxShape.circle,
),
child: Container(
height: selectedColor == index ? 25 : 20,
width: selectedColor == index ? 25 : 20,
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.grey,
offset: Offset(0.0, 1.0), //(x,y)
blurRadius: 6.0,
),
],
color: colorList[index],
shape: BoxShape.circle,
),
),
),
)),
),
],
);
}
}
================================================
FILE: lib/components/daily_activity.dart
================================================
import 'package:flutter/material.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'package:provider/provider.dart';
class TodayProgress extends StatelessWidget {
const TodayProgress({
super.key,
required this.textTheme,
});
final TextTheme textTheme;
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 10),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Consumer<RoutineModel>(builder: ((context, value, child) {
var inT = value.totalNoOfCompletedTasksToday();
var t = value.totalNoOfTasksToday();
double per;
if (t == 0) {
per = 0;
} else {
per = inT / t;
}
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${value.totalNoOfCompletedTasksToday()}/${value.totalNoOfTasksToday()}',
style: textTheme.headlineLarge,
),
Text(
"Today's Progress",
style: textTheme.titleMedium,
)
],
),
Stack(
alignment: AlignmentDirectional.center,
children: [
CircularPercentIndicator(
percent: per,
backgroundColor:
Theme.of(context).colorScheme.surfaceContainerHighest,
backgroundWidth: 15,
progressColor: Theme.of(context).colorScheme.inversePrimary,
animation: true,
circularStrokeCap: CircularStrokeCap.round,
radius: 40,
lineWidth: 8,
),
Text(
'${(per * 100).toInt()}%',
style: textTheme.titleSmall!.apply(fontWeightDelta: 1),
)
],
)
],
);
})),
),
);
}
}
================================================
FILE: lib/components/header.dart
================================================
import 'package:flutter/material.dart';
class ScreenHeader extends StatelessWidget {
const ScreenHeader({super.key, required this.text, required this.tag});
final String text;
final String tag;
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
flex: 1,
child: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(
Icons.arrow_back_ios,
size: 30,
),
),
),
Expanded(
flex: 10,
child: Hero(
tag: tag,
child: Text(
text,
style: Theme.of(context)
.textTheme
.headlineLarge!
.apply(color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
),
),
),
],
);
}
}
================================================
FILE: lib/components/most_productive_hour.dart
================================================
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:koduko/utils/time_of_day_util.dart';
import 'package:provider/provider.dart';
class ProductiveHour extends StatelessWidget {
const ProductiveHour({super.key, required this.textTheme});
final TextTheme textTheme;
@override
Widget build(BuildContext context) {
return Card(
child: Selector<RoutineModel, int>(
selector: (p0, p1) => p1.getMostProductiveHour(),
builder: (context, value, child) => Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
const SizedBox(height: 15),
Text(
"Most Productive Hour",
style: textTheme.titleSmall,
),
const SizedBox(height: 10),
Text(
DateFormat.j().format(
timeOfDayToDateTime(TimeOfDay(hour: value, minute: 0)) ??
DateTime.now()),
style: textTheme.headlineLarge,
),
const SizedBox(height: 15),
],
),
),
));
}
}
================================================
FILE: lib/components/name_page_bottom_sheet.dart
================================================
import 'package:flutter/material.dart';
class NamePage extends StatelessWidget {
const NamePage(
{super.key,
required this.nameController,
required this.validateName,
required this.pageComplected,
required this.hintText,
required this.title});
final TextEditingController nameController;
final void Function(String) validateName;
final bool pageComplected;
final String hintText;
final String title;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(
height: 25,
),
TextField(
controller: nameController,
autofocus: true,
maxLength: 20,
onChanged: validateName,
decoration: InputDecoration(
suffixIcon: pageComplected ? const Icon(Icons.check) : null,
filled: true,
hintText: hintText,
errorText:
nameController.text.length > 2 || nameController.text.isEmpty
? null
: "Invalid Name",
),
)
],
);
}
}
================================================
FILE: lib/components/productive_day.dart
================================================
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:provider/provider.dart';
class ProductiveDay extends StatelessWidget {
const ProductiveDay({super.key, required this.textTheme});
final TextTheme textTheme;
@override
Widget build(BuildContext context) {
return Card(
child: Selector<RoutineModel, DateTime?>(
selector: (p0, p1) => p1.getMostProductiveDay(),
builder: (context, value, child) => Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
const SizedBox(height: 15),
Text(
"Most Productive Day",
style: textTheme.titleSmall,
),
const SizedBox(height: 10),
Text(
value == null ? 'NaN' : DateFormat('EEEE').format(value),
style: textTheme.headlineLarge,
),
const SizedBox(height: 15),
],
),
),
));
}
}
================================================
FILE: lib/components/routine_chart.dart
================================================
import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:koduko/models/routine.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:provider/provider.dart';
class RoutineChart extends StatelessWidget {
const RoutineChart({super.key, required this.routine});
// final List<Color> gradientColors = [
// const Color(0xff6f7bf7),
// const Color(0xff9bf8f4),
// ];
final Routine routine;
@override
Widget build(BuildContext context) {
return Consumer<RoutineModel>(builder: (context, value, child) {
double maxX =
value.getRoutineStartMaxDays(routine.id).toDouble().clamp(0, 7);
double maxY = value.getRoutineStats(routine.id).isNotEmpty
? value.getRoutineStats(routine.id).reduce(max).toDouble()
: 10;
Color c = Theme.of(context).brightness == Brightness.light
? Colors.black12
: Colors.grey[800]!;
final showChart = maxX >= 1 ? true : false;
if (!showChart) {
return Padding(
padding: const EdgeInsets.all(15),
child: Text(
"${routine.name.trim()}'s activity will show up here. ",
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.center,
),
);
}
return Column(
children: [
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"${routine.name.trim()}'s Activity",
style: Theme.of(context).textTheme.titleLarge,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
),
child: SizedBox(
height: 200,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: LineChart(
LineChartData(
titlesData: FlTitlesData(
show: true,
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 30,
interval: 1,
getTitlesWidget: ((v, meta) => bottomTitleWidgets(
v, c, meta, value.getStartDate(routine.id))),
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
reservedSize: 30,
interval: 1,
getTitlesWidget: ((v, meta) =>
leftTitleWidgets(v, c, meta)),
),
),
),
gridData: FlGridData(
show: true,
drawVerticalLine: true,
horizontalInterval: 1,
verticalInterval: 1,
getDrawingHorizontalLine: (value) {
return FlLine(
color: c,
strokeWidth: 1,
);
},
getDrawingVerticalLine: (value) {
return FlLine(
color: c,
strokeWidth: 1,
);
},
),
borderData: FlBorderData(
show: true, border: Border.all(color: c, width: 1)),
minX: 0,
maxX: maxX,
minY: -0.2,
maxY: maxY + 1,
lineBarsData: [
LineChartBarData(
spots: value
.getRoutineStats(routine.id)
.asMap()
.map((key, value) => MapEntry(
key, FlSpot(key.toDouble(), value.toDouble())))
.values
.toList(),
isCurved: true,
curveSmoothness: 0.5,
barWidth: 3,
color: Theme.of(context).colorScheme.primary,
dotData: const FlDotData(
show: true,
),
belowBarData: BarAreaData(
show: true,
color: Theme.of(context)
.colorScheme
.primary
.withOpacity(0.4),
),
),
],
),
),
),
),
),
],
);
});
}
}
Widget bottomTitleWidgets(
double value, Color c, TitleMeta meta, DateTime start) {
final style = TextStyle(
color: c,
fontWeight: FontWeight.bold,
fontSize: 12,
);
return SideTitleWidget(
axisSide: meta.axisSide,
space: 8.0,
child: Text(
DateFormat('dd/MM').format(start.add(Duration(days: value.toInt()))),
style: style),
);
}
Widget leftTitleWidgets(double value, Color c, TitleMeta meta) {
final style = TextStyle(
color: c,
fontWeight: FontWeight.bold,
fontSize: 12,
);
if (value < 0) {
return Container();
}
return Text(
value.toInt().toString(),
style: style,
textAlign: TextAlign.center,
);
}
================================================
FILE: lib/components/routine_tile.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:koduko/components/create_routine_bottom_sheet.dart';
import 'package:koduko/components/routine_chart.dart';
import 'package:koduko/models/routine.dart';
import 'package:koduko/screens/start_routine.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:provider/provider.dart';
class RoutineTile extends StatefulWidget {
const RoutineTile({
super.key,
required this.routine,
this.isToday = false,
required this.onEdit,
});
final Routine routine;
final bool isToday;
final void Function(Routine) onEdit;
@override
State<RoutineTile> createState() => _RoutineTileState();
}
class _RoutineTileState extends State<RoutineTile> {
void onLongPress(BuildContext context) async {
Routine? r = await showModalBottomSheet<Routine>(
isScrollControlled: true,
isDismissible: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(10),
bottom: Radius.zero,
),
),
context: context,
builder: ((context) => CreateRoutineBottomSheet(
editRoutine: widget.routine,
)));
if (r != null) {
widget.onEdit(r);
}
}
void onExpanded(bool value) {
setState(() {
isExpanded = value;
});
}
void onPress(BuildContext context) {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => RoutineScreen(
routine: widget.routine.id,
))));
}
bool isExpanded = false;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(2),
child: Slidable(
enabled: !isExpanded,
closeOnScroll: true,
key: Key(widget.routine.id),
startActionPane: ActionPane(
motion: const ScrollMotion(),
dismissible: DismissiblePane(
closeOnCancel: true,
onDismissed: () {
Provider.of<RoutineModel>(context, listen: false)
.addToArchive(widget.routine.id);
}),
children: [
Action(
onPress: ((context) {
Provider.of<RoutineModel>(context, listen: false)
.addToArchive(widget.routine.id);
}),
color: Colors.brown[300]!,
icon: Icons.archive_rounded,
label: 'Archive',
),
],
),
endActionPane: ActionPane(
motion: const ScrollMotion(),
children: [
Action(
onPress: ((context) {
Provider.of<RoutineModel>(context, listen: false)
.toggleMarkAsCompleted(widget.routine.id);
}),
color: Colors.blue[300]!,
icon: Icons.checklist_rounded,
label: widget.routine.isCompleted
? 'Mark as Incomplete'
: 'Mark as Completed',
),
],
),
child: Card(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: CustomTile(
isOpen: isExpanded,
onStateChange: onExpanded,
isToday: widget.isToday,
routine: widget.routine,
onPress: onPress,
onEdit: onLongPress,
onDelete: ((context) {
showDialog(
context: context,
builder: ((context) => AlertOnDelete(
onCancel: () {
Navigator.pop(context);
},
onDelete: (() {
Provider.of<RoutineModel>(context, listen: false)
.delete(widget.routine.id);
Navigator.pop(context);
}),
)),
);
}),
))),
),
);
}
}
class AlertOnDelete extends StatelessWidget {
const AlertOnDelete({
super.key,
required this.onCancel,
required this.onDelete,
});
final void Function() onCancel;
final void Function() onDelete;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text("Delete routine?"),
content: const Text(
"This routine will be deleted. This will remove all the history of this routine as well."),
actions: [
TextButton(
onPressed: onCancel,
child: const Text("CANCEL"),
),
TextButton(
style: TextButton.styleFrom(
foregroundColor: Theme.of(context).colorScheme.error),
onPressed: onDelete,
child: const Text("DELETE"),
)
],
);
}
}
class Action extends StatelessWidget {
const Action(
{super.key,
required this.onPress,
required this.color,
required this.icon,
required this.label});
final Function(BuildContext context) onPress;
final Color color;
final IconData icon;
final String label;
@override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: TextButton.icon(
onPressed: (() {
onPress(context);
Slidable.of(context)?.close();
}),
icon: Icon(
icon,
color: color,
),
label: Text(
label,
style: Theme.of(context).textTheme.titleMedium!.apply(color: color),
),
)),
),
);
}
}
class CustomTile extends StatelessWidget {
const CustomTile({
super.key,
required this.isToday,
required this.routine,
required this.onPress,
required this.onDelete,
required this.onEdit,
required this.onStateChange,
required this.isOpen,
});
final bool isToday;
final Routine routine;
final Function(BuildContext context) onPress;
final Function(BuildContext context) onDelete;
final Function(BuildContext context) onEdit;
final Function(bool value) onStateChange;
final bool isOpen;
// bool isOpen = false;
@override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
dividerColor: Colors.transparent,
splashFactory: NoSplash.splashFactory,
highlightColor: Colors.transparent,
),
child: ExpansionTile(
onExpansionChanged: (value) {
Slidable.of(context)?.close();
onStateChange(value);
},
title: Hero(
tag: routine.name,
child: Text(
routine.name,
style: Theme.of(context).textTheme.titleLarge,
),
),
subtitle: isToday
? Padding(
padding: const EdgeInsets.symmetric(vertical: 3),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (routine.inCompletedTasks.isEmpty)
const Text("Completed")
else
AnimatedCrossFade(
firstChild: Text(
'Completed ${routine.tasks.length - routine.inCompletedTasks.length} out of ${routine.tasks.length}'),
secondChild: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
"${routine.getTimeLeft().inMinutes} mins left"),
),
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Text(
'Completed ${routine.tasks.length - routine.inCompletedTasks.length} / ${routine.tasks.length}',
style: const TextStyle(
fontSize: 12,
),
),
),
)
],
),
crossFadeState: isOpen
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 300),
),
const SizedBox(height: 5),
LinearPercentIndicator(
animateFromLastPercent: true,
animation: true,
percent: routine.getPercentage().clamp(0, 1),
barRadius: const Radius.circular(10),
lineHeight: 3,
progressColor:
Theme.of(context).colorScheme.inversePrimary,
padding: EdgeInsets.zero,
),
],
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(routine.getDays()),
Text("${routine.getTotalTime().inMinutes} mins")
],
),
trailing: IconButton(
padding: EdgeInsets.zero,
onPressed: () {
onPress(context);
},
icon: isToday
? Icon(
routine.isCompleted
? Icons.replay_rounded
: Icons.play_arrow_rounded,
size: 30,
)
: const Icon(
Icons.play_arrow_rounded,
size: 30,
),
),
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Total duration ${routine.getTotalTime().inMinutes} mins")),
),
RoutineChart(routine: routine),
Theme(
data: Theme.of(context),
child: Row(
children: [
Expanded(
child: TextButton.icon(
onPressed: () => onDelete(context),
icon: Icon(
Icons.delete,
color: Colors.red[300],
),
label: Text(
'Delete',
style: Theme.of(context)
.textTheme
.bodyMedium!
.apply(color: Colors.red[300]),
),
),
),
Expanded(
child: TextButton.icon(
onPressed: () => onEdit(context),
icon: Icon(
Icons.edit,
color: Colors.blue[300],
),
label: Text(
'Edit',
style: Theme.of(context)
.textTheme
.bodyMedium!
.apply(color: Colors.blue[300]),
),
),
),
],
),
)
],
),
);
}
}
================================================
FILE: lib/components/task_tile.dart
================================================
import 'package:flutter/material.dart';
import 'package:koduko/components/create_task_bottom_sheet.dart';
import 'package:koduko/models/task.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:koduko/services/tasks_provider.dart';
import 'package:koduko/utils/duration_to_string.dart';
import 'package:koduko/utils/parse_duration.dart';
import 'package:provider/provider.dart';
class TaskTile extends StatelessWidget {
const TaskTile({super.key, required this.task, required this.onEdit});
final Task task;
final void Function(Task) onEdit;
@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
trailing: SizedBox(
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () async {
Task? t = await showModalBottomSheet<Task>(
isScrollControlled: true,
isDismissible: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(10),
bottom: Radius.zero,
),
),
context: context,
builder: ((context) => CreateTaskBottomSheet(
task: task,
)));
if (t != null) {
onEdit(task.copyWith(
color: t.color, duration: t.duration, name: t.name));
}
},
icon: const Icon(Icons.edit)),
IconButton(
onPressed: () async {
showDialog(
context: context,
builder: ((context) => AlertDialog(
title: const Text("Delete task?"),
content: const Text(
"This Task will be removed from all the routines. if the routine has only this task, then routine will also be deleted."),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("CANCEL"),
),
TextButton(
style: TextButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.error),
onPressed: () {
Provider.of<TaskModel>(context,
listen: false)
.delete(task.id);
Provider.of<RoutineModel>(context,
listen: false)
.removeTask(task);
Navigator.pop(context);
},
child: const Text("DELETE"),
)
],
)));
},
icon: Icon(
Icons.delete,
color: Colors.red[300],
))
],
),
),
subtitle: Text(
'Duration : ${durationToString(parseDuration(task.duration))} Min'),
title: Text(
task.name,
style: Theme.of(context).textTheme.bodyMedium,
),
),
);
}
}
================================================
FILE: lib/components/time_spent_today.dart
================================================
import 'package:flutter/material.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:provider/provider.dart';
class TimeSpentToday extends StatelessWidget {
const TimeSpentToday({super.key, required this.textTheme});
final TextTheme textTheme;
@override
Widget build(BuildContext context) {
return Card(
child: Selector<RoutineModel, int>(
selector: (p0, p1) => p1.getTimeSpentToday(),
builder: (context, value, child) => Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
const SizedBox(height: 15),
Text(
"Time Spent Today",
style: textTheme.titleSmall,
),
const SizedBox(height: 10),
Text(
"$value mins",
style: textTheme.headlineLarge,
),
const SizedBox(height: 15),
],
),
),
));
}
}
================================================
FILE: lib/components/weekly_chart.dart
================================================
import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:provider/provider.dart';
import 'package:collection/collection.dart';
class WeeklyChart extends StatefulWidget {
const WeeklyChart({
super.key,
required this.textTheme,
});
final TextTheme textTheme;
@override
State<WeeklyChart> createState() => _WeeklyChartState();
}
class _WeeklyChartState extends State<WeeklyChart> {
int index = -1;
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 10),
child: Padding(
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Weekly Activity',
style: widget.textTheme.headlineSmall!
.apply(fontWeightDelta: 1)),
Consumer<RoutineModel>(
builder: ((context, value, child) => Text(
'You have completed ${value.getWeeklyStats().sum} ${value.getWeeklyStats().sum > 1 ? "tasks" : "task"} this week.',
style: widget.textTheme.bodyMedium)),
),
const SizedBox(height: 15),
SizedBox(
height: 160,
child: Consumer<RoutineModel>(
builder: ((context, value, child) {
var barGroupData = value
.getWeeklyStats()
.asMap()
.map((key, val) => MapEntry(
key,
BarChartGroupData(
x: key,
barRods: [
BarChartRodData(
width: 15,
backDrawRodData: BackgroundBarChartRodData(
color: Theme.of(context)
.colorScheme
.surfaceContainerHighest,
show: true,
toY: value
.getWeeklyStats()
.reduce(max)
.toDouble() ==
0
? 10
: value
.getWeeklyStats()
.reduce(max)
.toDouble(),
),
toY: val.toDouble(),
color: key == index
? Theme.of(context)
.colorScheme
.primary
.withOpacity(0.5)
: Theme.of(context)
.colorScheme
.inversePrimary,
),
],
)))
.values
.toList();
return BarChart(
swapAnimationDuration:
const Duration(milliseconds: 250), // Optional
swapAnimationCurve: Curves.bounceOut,
BarChartData(
barTouchData: BarTouchData(
touchTooltipData: barToolTipData(context),
touchCallback:
(FlTouchEvent event, barTouchResponse) {
setState(() {
if (!event.isInterestedForInteractions ||
barTouchResponse == null ||
barTouchResponse.spot == null) {
index = -1;
return;
}
index = barTouchResponse
.spot!.touchedBarGroupIndex;
});
},
),
borderData: FlBorderData(show: false),
gridData: const FlGridData(show: false),
alignment: BarChartAlignment.spaceAround,
titlesData: FlTitlesData(
show: true,
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 40,
getTitlesWidget: ((value, meta) => getTitles(
value,
meta,
Theme.of(context).colorScheme.onSurface,
Theme.of(context)
.colorScheme
.inversePrimary)),
),
),
leftTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
),
barGroups: barGroupData,
));
}),
)),
],
),
));
}
}
Widget getTitles(double value, TitleMeta meta, Color color, Color backColor) {
var style = TextStyle(
color: color,
);
String text;
switch (value.toInt()) {
case 0:
text = 'Mon';
break;
case 1:
text = 'Tue';
break;
case 2:
text = 'Wed';
break;
case 3:
text = 'Thu';
break;
case 4:
text = 'Fri';
break;
case 5:
text = 'Sat';
break;
case 6:
text = 'Sun';
break;
default:
text = '';
break;
}
return SideTitleWidget(
axisSide: meta.axisSide,
space: 4.0,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
margin: const EdgeInsets.only(top: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: DateFormat("EEE").format(DateTime.now()) == text
? backColor.withOpacity(0.5)
: null),
child: Text(text, style: style)),
);
}
BarTouchTooltipData barToolTipData(BuildContext context) {
return BarTouchTooltipData(
getTooltipItem: (group, groupIndex, rod, rodIndex) {
String weekDay;
switch (group.x.toInt()) {
case 0:
weekDay = 'Monday';
break;
case 1:
weekDay = 'Tuesday';
break;
case 2:
weekDay = 'Wednesday';
break;
case 3:
weekDay = 'Thursday';
break;
case 4:
weekDay = 'Friday';
break;
case 5:
weekDay = 'Saturday';
break;
case 6:
weekDay = 'Sunday';
break;
default:
throw Error();
}
return BarTooltipItem(
'$weekDay\n',
Theme.of(context).textTheme.labelLarge!,
children: <TextSpan>[
TextSpan(
text: '${rod.toY}',
style: Theme.of(context).textTheme.labelMedium!),
],
);
},
);
}
================================================
FILE: lib/main.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:koduko/models/routine.dart';
import 'package:koduko/models/task.dart';
import 'package:koduko/models/task_event.dart';
import 'package:koduko/screens/about.dart';
import 'package:koduko/screens/app.dart';
import 'package:koduko/screens/archive_routines.dart';
import 'package:koduko/screens/onboarding.dart';
import 'package:koduko/screens/stats.dart';
import 'package:koduko/screens/tasks.dart';
import 'package:koduko/services/notification_service.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:koduko/services/tasks_provider.dart';
import 'package:koduko/services/theme_provider.dart';
import 'package:provider/provider.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
void main() async {
await Hive.initFlutter();
Hive.registerAdapter(TaskAdapter());
Hive.registerAdapter(RoutineAdapter());
Hive.registerAdapter(TaskEventAdapter());
WidgetsFlutterBinding.ensureInitialized();
await NotificationService().initialize();
_configureLocalTimeZone();
runApp(const MyApp());
}
Future<void> _configureLocalTimeZone() async {
tz.initializeTimeZones();
final String timeZoneName = await FlutterNativeTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timeZoneName));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: Future.wait([
Hive.openBox<Routine>("Routines"),
Hive.openBox<Task>("Tasks"),
Hive.openBox<bool>("Theme"),
]),
builder: (context, snapshot) {
if (snapshot.hasError) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Text(
"Oops! Try again later",
style: Theme.of(context).textTheme.displayMedium,
),
),
),
);
} else if (snapshot.hasData) {
final box = Hive.box<bool>('Theme');
String initRoute = '/';
if (box.isOpen) {
initRoute =
(box.get('isNewUser') ?? true) ? OnBoarding.routeName : '/';
}
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => RoutineModel(),
),
ChangeNotifierProvider(
create: (context) => TaskModel(),
),
ChangeNotifierProvider(
create: ((context) => ThemeModel()),
),
],
child: Consumer<ThemeModel>(
builder: (context, value, child) => MaterialApp(
debugShowCheckedModeBanner: false,
title: 'KudoKo',
themeMode: value.getTheme,
theme: ThemeData.light(useMaterial3: true).copyWith(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.purple,
brightness: Brightness.light,
),
),
darkTheme: ThemeData.dark(useMaterial3: true).copyWith(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.purple,
brightness: Brightness.dark,
),
),
initialRoute: initRoute,
routes: {
TasksScreen.routeName: (context) => const TasksScreen(),
App.routeName: (context) => const App(),
AboutScreen.routeName: (context) => const AboutScreen(),
Statistics.routeName: ((context) => const Statistics()),
ArchiveRoutinesScreen.routeName: ((context) =>
const ArchiveRoutinesScreen()),
OnBoarding.routeName: (((context) => const OnBoarding()))
}),
),
);
}
return const MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
height: 60,
width: 60,
child: CircularProgressIndicator(
strokeWidth: 6,
),
),
)),
);
},
);
}
}
================================================
FILE: lib/models/routine.dart
================================================
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:intl/intl.dart';
import 'package:koduko/models/task.dart';
import 'package:koduko/models/task_event.dart';
import 'package:koduko/utils/date_time_extension.dart';
import 'package:koduko/utils/parse_duration.dart';
import 'package:koduko/utils/time_of_day_util.dart';
import 'package:uuid/uuid.dart';
part 'routine.g.dart';
@HiveType(typeId: 2)
class Routine {
@HiveField(0)
late final String id;
@HiveField(1)
String name;
@HiveField(2)
List<Task> tasks;
@HiveField(3)
late List<Task> inCompletedTasks;
@HiveField(4)
late List<TaskEvent> history;
@HiveField(5, defaultValue: true)
late bool isCompleted;
@HiveField(6)
List<String> days;
@HiveField(7, defaultValue: null)
DateTime? time;
@HiveField(8, defaultValue: false)
late bool isArchive;
Routine({
required this.name,
required this.tasks,
required this.inCompletedTasks,
required this.history,
required this.id,
required this.days,
required this.isCompleted,
required this.time,
required this.isArchive,
bool isSkip = false,
}) {
if (isSkip) {
return;
}
if (inCompletedTasks.isNotEmpty || isCompleted) {
if (history.isNotEmpty) {
bool isNewDay = true;
for (var element in history) {
if (element.time.isSameDate(DateTime.now())) {
isNewDay = false;
break;
}
}
if (isNewDay) {
isCompleted = false;
inCompletedTasks = [];
}
}
}
if (inCompletedTasks.isEmpty && !isCompleted) {
inCompletedTasks = tasks;
}
}
Routine.create({
required this.name,
required this.tasks,
required this.days,
required this.time,
// List<Task>? inCompletedTasks,
}) {
id = const Uuid().v4();
isCompleted = false;
history = [];
tasks = tasks;
inCompletedTasks = tasks;
isArchive = false;
}
Routine copyWith({
List<Task>? tasks,
List<Task>? inCompletedTasks,
List<TaskEvent>? history,
String? id,
String? name,
List<String>? days,
bool? isCompleted,
TimeOfDay? time,
bool isSkip = false,
bool? isArchive,
}) {
return Routine(
name: name ?? this.name,
tasks: tasks ?? this.tasks,
inCompletedTasks: inCompletedTasks ?? this.inCompletedTasks,
history: history ?? this.history,
id: id ?? this.id,
days: days ?? this.days,
isCompleted: isCompleted ?? this.isCompleted,
time: timeOfDayToDateTime(time) ?? this.time,
isSkip: isSkip,
isArchive: isArchive ?? this.isArchive);
}
Routine skipTask() {
List<Task> r = List.from(inCompletedTasks);
Task t = r.removeAt(0);
r.add(t);
final g = copyWith(inCompletedTasks: r, isSkip: true);
return g;
}
Routine completeTask() {
List<Task> r = List.from(inCompletedTasks);
var t = r.removeAt(0);
List<TaskEvent> h = List.from(history);
h.add(
TaskEvent.create(taskName: t.name, taskId: t.id, time: DateTime.now()));
h.sort((a, b) => b.time.compareTo(a.time));
return copyWith(
inCompletedTasks: r, isCompleted: r.isEmpty ? true : false, history: h);
}
Routine replay() {
return copyWith(isCompleted: false);
}
int getCompletedTasks(DateTime d) {
var count = 0;
if (history.isEmpty) {
return count;
} else {
for (var element in history) {
if (element.time.isSameDate(d)) {
count++;
}
}
}
return count;
}
Duration getTotalTime() {
Duration d = Duration.zero;
for (var t in tasks) {
d = parseDuration(t.duration) + d;
}
return d;
}
Duration getTimeSpentToday() {
Duration d = getTotalTime() - getTimeLeft();
return d;
}
Duration getTimeLeft() {
Duration d = Duration.zero;
for (var t in inCompletedTasks) {
d = d + parseDuration(t.duration);
}
return d;
}
Routine addToArchive() {
return copyWith(isArchive: true);
}
Routine removeFromArchive() {
return copyWith(isArchive: false);
}
Routine? removeHistory(String id) {
List<TaskEvent> h = List.from(history);
final index = h.indexWhere((element) => element.id == id);
if (index > -1) {
h.removeAt(index);
return copyWith(history: h);
}
return null;
}
Routine clearHistory() {
return copyWith(history: [], isCompleted: false);
}
Routine markAsCompleted() {
List<TaskEvent> h = List.from(history);
for (var i = 0; i < inCompletedTasks.length; i++) {
final task = inCompletedTasks[i];
h.add(TaskEvent.create(
taskName: task.name,
taskId: task.id,
time: DateTime.now().add(Duration(seconds: i)),
));
}
h.sort((a, b) => b.time.compareTo(a.time));
return copyWith(isCompleted: true, inCompletedTasks: [], history: h);
}
Routine markAsInCompleted() {
List<TaskEvent> h = List.from(history);
for (var task in tasks) {
final i = h.indexWhere((element) => element.taskId == task.id);
if (i > -1) {
h.removeAt(i);
}
}
h.sort((a, b) => b.time.compareTo(a.time));
return copyWith(isCompleted: false, inCompletedTasks: tasks, history: h);
}
Routine? taskExists(Task t) {
int index = tasks.indexWhere((element) => element.id.compareTo(t.id) == 0);
if (index > -1) {
List<Task> ts = List.from(tasks);
ts.removeAt(index);
return copyWith(tasks: ts);
}
return null;
}
Routine? editTasks(Task t) {
if (tasks.isNotEmpty) {
List<Task> tep = [];
List<Task> temp = tasks.map((e) => e.id == t.id ? t : e).toList();
if (inCompletedTasks.isNotEmpty) {
tep = inCompletedTasks.map((e) => e.id == t.id ? t : e).toList();
}
return copyWith(tasks: temp, inCompletedTasks: tep);
}
return null;
}
String getDays() {
return days.length == 7
? "Daily"
: days.map((e) => e.substring(0, 3)).join(", ");
}
static List<Task> taskDiff(List<Task> first, List<Task> second) {
var a = [...first];
var b = [...second];
if (a.length > b.length) {
for (int i = 0; i < b.length; i++) {
int index = a.indexWhere((t) => t.id == b[i].id);
if (index > -1) {
a.removeAt(index);
}
}
return a;
} else {
for (int i = 0; i < a.length; i++) {
int index = b.indexWhere((t) => t.id == a[i].id);
if (index > -1) {
b.removeAt(index);
}
}
return b;
}
}
bool isToday() {
return days.contains(DateFormat("EEEE").format(DateTime.now()));
}
double getPercentage() {
return (tasks.length - inCompletedTasks.length) == 0
? 0
: ((tasks.length - inCompletedTasks.length) / tasks.length);
}
String getPercentageString() {
return '${(getPercentage() * 100).toInt()}%';
}
}
================================================
FILE: lib/models/routine.g.dart
================================================
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'routine.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class RoutineAdapter extends TypeAdapter<Routine> {
@override
final int typeId = 2;
@override
Routine read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return Routine(
name: fields[1] as String,
tasks: (fields[2] as List).cast<Task>(),
inCompletedTasks: (fields[3] as List).cast<Task>(),
history: (fields[4] as List).cast<TaskEvent>(),
id: fields[0] as String,
days: (fields[6] as List).cast<String>(),
isCompleted: fields[5] == null ? true : fields[5] as bool,
time: fields[7] as DateTime?,
isArchive: fields[8] == null ? false : fields[8] as bool,
);
}
@override
void write(BinaryWriter writer, Routine obj) {
writer
..writeByte(9)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.name)
..writeByte(2)
..write(obj.tasks)
..writeByte(3)
..write(obj.inCompletedTasks)
..writeByte(4)
..write(obj.history)
..writeByte(5)
..write(obj.isCompleted)
..writeByte(6)
..write(obj.days)
..writeByte(7)
..write(obj.time)
..writeByte(8)
..write(obj.isArchive);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is RoutineAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
================================================
FILE: lib/models/task.dart
================================================
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:uuid/uuid.dart';
part 'task.g.dart';
@HiveType(typeId: 1)
class Task {
@HiveField(0)
late String id;
@HiveField(1)
String name;
@HiveField(2)
late String duration;
@HiveField(3)
late int color;
Task(
{required this.duration,
required this.name,
required this.color,
required this.id});
Task copyWith({
String? duration,
String? name,
int? color,
String? id,
}) {
return Task(
duration: duration ?? this.duration,
name: name ?? this.name,
color: color ?? this.color,
id: id ?? this.id);
}
Task.fromDuration(
{required Duration duration, required this.name, required Color color}) {
this.duration = duration.toString();
this.color = color.value;
id = const Uuid().v4();
}
@override
String toString() {
super.toString();
return '{id: $id ,name: $name, color: $color, duration: $duration}';
}
}
================================================
FILE: lib/models/task.g.dart
================================================
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'task.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class TaskAdapter extends TypeAdapter<Task> {
@override
final int typeId = 1;
@override
Task read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return Task(
duration: fields[2] as String,
name: fields[1] as String,
color: fields[3] as int,
id: fields[0] as String,
);
}
@override
void write(BinaryWriter writer, Task obj) {
writer
..writeByte(4)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.name)
..writeByte(2)
..write(obj.duration)
..writeByte(3)
..write(obj.color);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is TaskAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
================================================
FILE: lib/models/task_event.dart
================================================
import 'package:hive_flutter/adapters.dart';
import 'package:uuid/uuid.dart';
part 'task_event.g.dart';
@HiveType(typeId: 3)
class TaskEvent {
@HiveField(0)
late final String id;
@HiveField(1)
final String taskName;
@HiveField(2)
final DateTime time;
@HiveField(3)
final String taskId;
TaskEvent({
required this.id,
required this.taskName,
required this.time,
required this.taskId,
});
@override
String toString() {
return '[Id : $id, Name: $taskName, Time: $time, TaskId: $taskId]';
}
TaskEvent.create({
required this.taskName,
required this.taskId,
required this.time,
}) {
id = const Uuid().v4();
}
}
================================================
FILE: lib/models/task_event.g.dart
================================================
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'task_event.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class TaskEventAdapter extends TypeAdapter<TaskEvent> {
@override
final int typeId = 3;
@override
TaskEvent read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return TaskEvent(
id: fields[0] as String,
taskName: fields[1] as String,
time: fields[2] as DateTime,
taskId: fields[3] as String,
);
}
@override
void write(BinaryWriter writer, TaskEvent obj) {
writer
..writeByte(4)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.taskName)
..writeByte(2)
..write(obj.time)
..writeByte(3)
..write(obj.taskId);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is TaskEventAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
================================================
FILE: lib/screens/about.dart
================================================
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:koduko/components/header.dart';
import 'package:url_launcher/url_launcher.dart';
class AboutScreen extends StatelessWidget {
const AboutScreen({super.key});
static const routeName = "/about";
@override
Widget build(BuildContext context) {
Future<void> openUrl(url) async {
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
throw 'Could not launch $url';
}
}
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 25),
const ScreenHeader(
text: "About",
tag: "About",
),
const SizedBox(height: 25),
Padding(
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: TextSpan(
text:
"Koduko is an open source habit tracker app that helps users develop and maintain positive daily habits. Users can set personalized goals and track their progress towards achieving them, as well as receive reminders to stay on track. You can find the source code and releases ",
style: Theme.of(context).textTheme.bodyLarge,
children: [
TextSpan(
text: "here",
recognizer: TapGestureRecognizer()
..onTap = () => openUrl(Uri.parse(
'https://github.com/Mazahir26/koduko')),
style: Theme.of(context)
.textTheme
.bodyLarge!
.copyWith(
color:
Theme.of(context).colorScheme.primary,
),
)
]),
),
const SizedBox(height: 15),
Text(
'Developer Contact',
style: Theme.of(context)
.textTheme
.headlineMedium!
.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
Text(
"For any questions or suggestions regarding Koduko's functionality or code, You can reach me out via telegram or github",
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(
onPressed: () {
openUrl(
Uri.parse('https://github.com/Mazahir26'));
},
child: const Text("GitHub")),
TextButton(
onPressed: () {
openUrl(Uri.parse('https://t.me/mazahir26'));
},
child: const Text("Telegram"))
],
),
const SizedBox(height: 30),
Center(
child: Text(
"Thank You ❤️",
style: Theme.of(context)
.textTheme
.headlineMedium!
.copyWith(fontWeight: FontWeight.bold),
),
),
],
),
)
],
),
),
),
);
}
}
================================================
FILE: lib/screens/app.dart
================================================
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:koduko/screens/home.dart';
import 'package:koduko/screens/routines.dart';
import 'package:koduko/screens/settings.dart';
import 'package:koduko/screens/start_routine.dart';
import 'package:koduko/screens/tasks.dart';
import 'package:koduko/services/notification_service.dart';
class App extends StatefulWidget {
const App({super.key});
static const routeName = "/";
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
int _selectedIndex = 0;
late final NotificationService service;
late final StreamSubscription<String?> stream;
NotificationAppLaunchDetails? notificationAppLaunchDetails;
late final PageController _pageController;
getDeviceLaunch() async {
notificationAppLaunchDetails = await service.getDeviceLaunchInfo();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
if ((notificationAppLaunchDetails!
.notificationResponse?.payload?.isNotEmpty ??
false)) {
onNotificationListener(
notificationAppLaunchDetails!.notificationResponse?.payload);
}
}
}
void _onItemTapped(int index) {
setState(() {
_pageController.animateToPage(
index,
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOutCirc,
);
_selectedIndex = index;
});
}
@override
void initState() {
service = NotificationService();
getDeviceLaunch();
_pageController = PageController();
stream = service.onNotificationClick.stream.listen(onNotificationListener);
super.initState();
}
@override
void dispose() {
stream.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final List<Widget> widgetOptions = <Widget>[
HomeScreen(
onTapChange: () => _onItemTapped(1),
),
const RoutinesScreen(),
const TasksScreen(isBottomNavWidget: true),
const SettingsScreen(),
];
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor:
Theme.of(context).brightness == Brightness.dark
? Colors.black
: Colors.white,
statusBarIconBrightness: Theme.of(context).brightness == Brightness.dark
? Brightness.light
: Brightness.dark,
systemNavigationBarIconBrightness:
Theme.of(context).brightness == Brightness.dark
? Brightness.light
: Brightness.dark,
),
child: Scaffold(
bottomNavigationBar: NavigationBar(
onDestinationSelected: _onItemTapped,
labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
selectedIndex: _selectedIndex,
destinations: const <Widget>[
NavigationDestination(
selectedIcon: Icon(Icons.home_rounded),
icon: Icon(Icons.home_outlined),
label: 'Home',
),
NavigationDestination(
selectedIcon: Icon(Icons.task_alt_rounded),
icon: Icon(Icons.task_alt_outlined),
label: 'Routines',
),
NavigationDestination(
selectedIcon: Icon(Icons.list_rounded),
icon: Icon(Icons.list_outlined),
label: 'Tasks',
),
NavigationDestination(
selectedIcon: Icon(Icons.settings_rounded),
icon: Icon(Icons.settings_outlined),
label: 'Settings',
),
],
),
body: SafeArea(
child: PageView(
controller: _pageController,
onPageChanged: (value) => setState(() {
_selectedIndex = value;
}),
children: widgetOptions,
),
),
),
);
}
void onNotificationListener(String? payload) {
if (payload != null && payload.isNotEmpty) {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => RoutineScreen(
routine: payload,
))));
}
}
}
================================================
FILE: lib/screens/archive_routines.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:koduko/components/header.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:provider/provider.dart';
class ArchiveRoutinesScreen extends StatelessWidget {
const ArchiveRoutinesScreen({super.key});
static const routeName = "/archive";
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Consumer<RoutineModel>(
builder: (context, value, child) => value.archiveRoutines().isEmpty
? Padding(
padding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
child ?? Container(),
Expanded(
flex: 10,
child: Center(
child: Text(
"Archived routines will show up here!",
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
.apply(
displayColor:
Theme.of(context).colorScheme.onSurface)
.headlineMedium,
),
),
),
],
),
)
: ListView.builder(
itemCount: value.archiveRoutines().length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 20, horizontal: 10),
child: child ?? Container(),
);
}
index -= 1;
return Card(
margin: const EdgeInsets.all(10),
child: ListTile(
title: Text(
value.archiveRoutines()[index].name,
style: Theme.of(context).textTheme.titleLarge,
),
subtitle: const Text("Archived"),
trailing: SizedBox(
width: 100,
child: Row(
children: [
IconButton(
color: Colors.brown[300],
onPressed: () {
Provider.of<RoutineModel>(context,
listen: false)
.removeFromArchive(
value.archiveRoutines()[index].id);
},
icon: const Icon(Icons.unarchive_rounded),
),
IconButton(
color: Colors.red[300],
onPressed: () {},
icon: const Icon(Icons.delete),
)
],
),
),
),
);
}),
child: const ScreenHeader(text: 'Archived', tag: 'Archived'),
),
),
);
}
}
class Action extends StatelessWidget {
const Action(
{super.key,
required this.onPress,
required this.color,
required this.icon,
required this.label});
final Function(BuildContext context) onPress;
final Color color;
final IconData icon;
final String label;
@override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: TextButton.icon(
onPressed: (() {
onPress(context);
Slidable.of(context)?.close();
}),
icon: Icon(
icon,
color: color,
),
label: Text(
label,
style: Theme.of(context).textTheme.titleMedium!.apply(color: color),
),
)),
),
);
}
}
================================================
FILE: lib/screens/home.dart
================================================
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:koduko/components/weekly_chart.dart';
import 'package:koduko/models/routine.dart';
import 'package:koduko/screens/start_routine.dart';
import 'package:koduko/screens/stats.dart';
import 'package:koduko/services/routines_provider.dart';
import 'package:koduko/utils/greetings.dart';
import 'package:percent_indicator/percent_indicator.dart';
import 'package:provider/provider.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key, required this.onTapChange});
final void Function() onTapChange;
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context)
.textTheme
.apply(displayColor: Theme.of(context).colorScheme.onSurface);
return ListView(
padding: const EdgeInsets.all(15),
children: [
const SizedBox(height: 20),
Header(textTheme: textTheme),
const SizedBox(height: 20),
Hero(
tag: 'WeeklyChart',
child: WeeklyChart(textTheme: textTheme),
),
Align(
alignment: Alignment.centerRight,
child: TextButton.icon(
onPressed: () => Navigator.pushNamed(context, Statistics.routeName),
icon: const Text("More Stats"),
label: const Icon(Icons.chevron_right_rounded),
),
),
Text("Today's Routines",
style: GoogleFonts.lato(
fontWeight: FontWeight.bold,
textStyle: textTheme.headlineMedium,
)),
Consumer<RoutineModel>(
builder: (context, value, child) {
List<Routine> todayRoutines = value.todaysRoutines();
final Duration totalTime = value.todaysRoutines().fold(
Duration.zero,
(previousValue, element) =>
previousValue + element.getTimeLeft());
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${totalTime.inMinutes} mins left to reach your goal today ",
style: GoogleFonts.lato(
fontWeight: FontWeight.w400,
textStyle: Theme.of(context)
.textTheme
.apply(
displayColor:
Theme.of(context).colorScheme.onSurface)
.bodyLarge,
),
),
const SizedBox(height: 10),
Column(
children: todayRoutines.isEmpty
? [
const SizedBox(
height: 50,
),
Center(
child: Text(
"You seem free today!",
style: Theme.of(context).textTheme.headlineSmall,
),
),
Center(
child: TextButton(
style: TextButton.styleFrom(
textStyle:
Theme.of(context).textTheme.titleMedium),
onPressed: onTapChange,
child: const Text(
"Change that?",
),
),
)
]
: todayRoutines
.asMap()
.map((key, value) => MapEntry(
key,
Row(
children: [
Expanded(
flex: 1,
child: Text(
'${key + 1}',
style: GoogleFonts.lato(
fontWeight: FontWeight.bold,
textStyle: textTheme.headlineLarge,
),
),
),
Expanded(
flex: 10,
child: Card(
margin: const EdgeInsets.symmetric(
vertical: 5,
),
child: ListTile(
title: Text(
value.name,
style: Theme.of(context)
.textTheme
.titleLarge,
),
subtitle: Padding(
padding: const EdgeInsets.symmetric(
vertical: 3),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
value.inCompletedTasks.isEmpty
? const Text("Completed")
: Text(
'Completed ${value.tasks.length - value.inCompletedTasks.length} out of ${value.tasks.length}'),
const SizedBox(height: 5),
LinearPercentIndicator(
animateFromLastPercent: true,
animation: true,
percent: value
.getPercentage()
.clamp(0, 1),
barRadius:
const Radius.circular(10),
lineHeight: 3,
progressColor:
Theme.of(context)
.colorScheme
.inversePrimary,
padding: EdgeInsets.zero,
),
],
),
),
trailing: IconButton(
padding: EdgeInsets.zero,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) =>
RoutineScreen(
routine: value.id,
))));
},
icon: Icon(
value.isCompleted
? Icons.replay_rounded
: Icons.play_arrow_rounded,
size: 30,
))),
),
),
],
)))
.values
.toList(),
),
],
);
},
)
],
);
}
}
class Header extends StatelessWidget {
const Header({
super.key,
required this.textTheme,
});
final TextTheme textTheme;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Good ${greeting()} 👋',
style: GoogleFonts.lato(
fontWeight: FontWeight.bold,
textStyle: textTheme.headlineLarge,
),
),
Text(
DateFormat.MMMMEEEEd().format(DateTime.now()),
style: GoogleFonts.lato(
fontWeight: FontWeight.w400,
textStyle: Theme.of(context).textTheme.titleLarge!.apply(
color:
Theme.of(context).colorScheme.onSurface.withOpacity(0.5)),
),
),
],
);
}
}
================================================
FILE: lib/screens/onboarding.dart
================================================
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hive_flutter/adapters.dart';
class OnBoarding extends StatefulWidget {
const OnBoarding({super.key});
static const routeName = "/onBoarding";
@override
State<OnBoarding> createState() => _OnBoardingState();
}
class _OnBoardingState extends State<OnBoarding> {
int _index = 0;
late final PageController _pageController;
final okColors = [
const Color.fromRGBO(251, 187, 91, 1),
const Color.fromRGBO(44, 155, 243, 1),
const Color.fromRGBO(67, 60, 85, 1),
];
@override
void initState() {
_pageController = PageController();
super.initState();
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TweenAnimationBuilder<Color?>(
tween: ColorTween(
begin: const Color.fromRGBO(251, 187, 91, 1), end: okColors[_index]),
duration: const Duration(milliseconds: 250),
builder: (context, value, child) => Scaffold(
backgroundColor: value,
body: SafeArea(
child: Container(
color: value,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
flex: 10,
child: PageView(
controller: _pageController,
onPageChanged: (value) => setState(() {
_index = value;
}),
children: [
Page(
color: value,
title: "Koduko",
imagePath: 'assets/onboarding/person.png',
des:
"Hey There! Yes, this is an habit tracker don't let the name fool you. It will help you manage your daily or weekly habits with ease.",
),
Page(
color: value,
title: "You ask features?",
imagePath: 'assets/onboarding/gymTime.png',
des:
"It has a lot of them. You add a routine which can contain multiple tasks, Select a time and you are done. It will remind you at the specified time. Also there are statistics ",
),
Page(
color: value,
title: "Ready?",
imagePath: 'assets/onboarding/watch.png',
des: "We hope you are! \n Have fun.",
),
],
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Buttons(
onSkip: () {
setState(() {
_index = 2;
});
_pageController.animateToPage(2,
curve: Curves.easeIn,
duration: const Duration(milliseconds: 250));
},
pageIndex: _index,
onNext: () {
if (_index == 2) {
final box = Hive.box<bool>('Theme');
if (box.isOpen) {
box.put('isNewUser', false);
}
Navigator.pushReplacementNamed(context, '/');
}
if (_index > 1) {
return;
}
setState(() {
_index++;
});
_pageController.nextPage(
duration: const Duration(milliseconds: 250),
curve: Curves.easeIn,
);
},
onPrevious: () {
if (_index <= 0) {
return;
}
setState(() {
_index--;
});
_pageController.previousPage(
duration: const Duration(milliseconds: 250),
curve: Curves.easeIn,
);
},
text: _index == 2 ? 'Start' : null,
color: value,
),
)),
const SizedBox(height: 10)
],
),
),
),
),
);
}
}
class Page extends StatelessWidget {
const Page({
super.key,
required this.imagePath,
required this.title,
required this.des,
required this.color,
});
final String imagePath;
final String title;
final String des;
final Color? color;
@override
Widget build(BuildContext context) {
return Column(
children: [
Image(image: AssetImage(imagePath)),
Text(
title,
style: GoogleFonts.catamaran(
fontWeight: FontWeight.bold,
textStyle: Theme.of(context).textTheme.headlineLarge!.apply(
color: (color?.computeLuminance() ?? 0.1) > 0.5
? Colors.black
: Colors.white)),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
des,
style: GoogleFonts.raleway(
textStyle: Theme.of(context).textTh
gitextract__iqieike/
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .metadata
├── CODE_OF_CONDUCT.md
├── LICENSE.md
├── README.md
├── analysis_options.yaml
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── com/
│ │ │ │ └── example/
│ │ │ │ └── koduko/
│ │ │ │ └── MainActivity.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21/
│ │ │ │ └── launch_background.xml
│ │ │ ├── values/
│ │ │ │ └── styles.xml
│ │ │ └── values-night/
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ └── settings.gradle
├── ios/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ └── Runner.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ ├── IDEWorkspaceChecks.plist
│ └── WorkspaceSettings.xcsettings
├── lib/
│ ├── components/
│ │ ├── card.dart
│ │ ├── create_routine_bottom_sheet.dart
│ │ ├── create_task_bottom_sheet.dart
│ │ ├── daily_activity.dart
│ │ ├── header.dart
│ │ ├── most_productive_hour.dart
│ │ ├── name_page_bottom_sheet.dart
│ │ ├── productive_day.dart
│ │ ├── routine_chart.dart
│ │ ├── routine_tile.dart
│ │ ├── task_tile.dart
│ │ ├── time_spent_today.dart
│ │ └── weekly_chart.dart
│ ├── main.dart
│ ├── models/
│ │ ├── routine.dart
│ │ ├── routine.g.dart
│ │ ├── task.dart
│ │ ├── task.g.dart
│ │ ├── task_event.dart
│ │ └── task_event.g.dart
│ ├── screens/
│ │ ├── about.dart
│ │ ├── app.dart
│ │ ├── archive_routines.dart
│ │ ├── home.dart
│ │ ├── onboarding.dart
│ │ ├── routines.dart
│ │ ├── settings.dart
│ │ ├── start_routine.dart
│ │ ├── stats.dart
│ │ └── tasks.dart
│ ├── services/
│ │ ├── notification_service.dart
│ │ ├── routines_provider.dart
│ │ ├── tasks_provider.dart
│ │ └── theme_provider.dart
│ └── utils/
│ ├── colors_util.dart
│ ├── date_time_extension.dart
│ ├── duration_to_string.dart
│ ├── greetings.dart
│ ├── parse_duration.dart
│ └── time_of_day_util.dart
├── linux/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter/
│ │ ├── CMakeLists.txt
│ │ ├── generated_plugin_registrant.cc
│ │ ├── generated_plugin_registrant.h
│ │ └── generated_plugins.cmake
│ ├── main.cc
│ ├── my_application.cc
│ └── my_application.h
├── macos/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── Flutter-Debug.xcconfig
│ │ ├── Flutter-Release.xcconfig
│ │ └── GeneratedPluginRegistrant.swift
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ ├── Configs/
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ └── Release.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ └── Runner.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── pubspec.yaml
├── test/
│ └── widget_test.dart
├── web/
│ ├── index.html
│ └── manifest.json
└── windows/
├── .gitignore
├── CMakeLists.txt
├── flutter/
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
└── runner/
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
SYMBOL INDEX (259 symbols across 51 files)
FILE: lib/components/card.dart
class TaskCard (line 5) | class TaskCard extends StatelessWidget {
method build (line 66) | Widget build(BuildContext context)
FILE: lib/components/create_routine_bottom_sheet.dart
type RepeatType (line 12) | enum RepeatType {
class CreateRoutineBottomSheet (line 17) | class CreateRoutineBottomSheet extends StatefulWidget {
method createState (line 25) | State<CreateRoutineBottomSheet> createState()
class _CreateRoutineBottomSheetState (line 29) | class _CreateRoutineBottomSheetState extends State<CreateRoutineBottomSh...
method initState (line 49) | void initState()
method validateName (line 73) | void validateName(String _)
method onChangeRepeatType (line 87) | void onChangeRepeatType(RepeatType r)
method onDayChange (line 101) | void onDayChange(String e, bool value)
method onAdd (line 136) | void onAdd(Task t)
method onRemove (line 143) | void onRemove(int index)
method dispose (line 157) | void dispose()
method build (line 164) | Widget build(BuildContext context)
class Buttons (line 347) | class Buttons extends StatelessWidget {
method build (line 362) | Widget build(BuildContext context)
class TaskSelectPage (line 421) | class TaskSelectPage extends StatelessWidget {
method build (line 434) | Widget build(BuildContext context)
class RepeatPage (line 611) | class RepeatPage extends StatelessWidget {
method build (line 631) | Widget build(BuildContext context)
method selectTime (line 632) | Future<void> selectTime(BuildContext context)
FILE: lib/components/create_task_bottom_sheet.dart
class CreateTaskBottomSheet (line 8) | class CreateTaskBottomSheet extends StatefulWidget {
method createState (line 12) | State<CreateTaskBottomSheet> createState()
class _CreateTaskBottomSheetState (line 15) | class _CreateTaskBottomSheetState extends State<CreateTaskBottomSheet> {
method initState (line 47) | void initState()
method validateName (line 61) | void validateName(String _)
method validateDuration (line 75) | void validateDuration()
method validateColor (line 87) | void validateColor()
method onChangeChip (line 99) | void onChangeChip(bool selected, int index, BuildContext context)
method onChangeColor (line 182) | void onChangeColor(int index)
method dispose (line 190) | void dispose()
method build (line 197) | Widget build(BuildContext context)
class Buttons (line 307) | class Buttons extends StatelessWidget {
method build (line 322) | Widget build(BuildContext context)
class DurationPage (line 381) | class DurationPage extends StatelessWidget {
method build (line 395) | Widget build(BuildContext context)
class ColorPage (line 432) | class ColorPage extends StatelessWidget {
method build (line 442) | Widget build(BuildContext context)
FILE: lib/components/daily_activity.dart
class TodayProgress (line 6) | class TodayProgress extends StatelessWidget {
method build (line 15) | Widget build(BuildContext context)
FILE: lib/components/header.dart
class ScreenHeader (line 3) | class ScreenHeader extends StatelessWidget {
method build (line 8) | Widget build(BuildContext context)
FILE: lib/components/most_productive_hour.dart
class ProductiveHour (line 7) | class ProductiveHour extends StatelessWidget {
method build (line 12) | Widget build(BuildContext context)
FILE: lib/components/name_page_bottom_sheet.dart
class NamePage (line 3) | class NamePage extends StatelessWidget {
method build (line 18) | Widget build(BuildContext context)
FILE: lib/components/productive_day.dart
class ProductiveDay (line 6) | class ProductiveDay extends StatelessWidget {
method build (line 11) | Widget build(BuildContext context)
FILE: lib/components/routine_chart.dart
class RoutineChart (line 10) | class RoutineChart extends StatelessWidget {
method build (line 19) | Widget build(BuildContext context)
function bottomTitleWidgets (line 152) | Widget bottomTitleWidgets(
function leftTitleWidgets (line 169) | Widget leftTitleWidgets(double value, Color c, TitleMeta meta)
FILE: lib/components/routine_tile.dart
class RoutineTile (line 11) | class RoutineTile extends StatefulWidget {
method createState (line 23) | State<RoutineTile> createState()
class _RoutineTileState (line 26) | class _RoutineTileState extends State<RoutineTile> {
method onLongPress (line 27) | void onLongPress(BuildContext context)
method onExpanded (line 46) | void onExpanded(bool value)
method onPress (line 52) | void onPress(BuildContext context)
method build (line 64) | Widget build(BuildContext context)
class AlertOnDelete (line 138) | class AlertOnDelete extends StatelessWidget {
method build (line 148) | Widget build(BuildContext context)
class Action (line 169) | class Action extends StatelessWidget {
method build (line 182) | Widget build(BuildContext context)
class CustomTile (line 206) | class CustomTile extends StatelessWidget {
method build (line 228) | Widget build(BuildContext context)
FILE: lib/components/task_tile.dart
class TaskTile (line 10) | class TaskTile extends StatelessWidget {
method build (line 15) | Widget build(BuildContext context)
FILE: lib/components/time_spent_today.dart
class TimeSpentToday (line 5) | class TimeSpentToday extends StatelessWidget {
method build (line 10) | Widget build(BuildContext context)
FILE: lib/components/weekly_chart.dart
class WeeklyChart (line 9) | class WeeklyChart extends StatefulWidget {
method createState (line 17) | State<WeeklyChart> createState()
class _WeeklyChartState (line 20) | class _WeeklyChartState extends State<WeeklyChart> {
method build (line 23) | Widget build(BuildContext context)
function getTitles (line 143) | Widget getTitles(double value, TitleMeta meta, Color color, Color backCo...
function barToolTipData (line 189) | BarTouchTooltipData barToolTipData(BuildContext context)
FILE: lib/main.dart
function main (line 21) | void main()
function _configureLocalTimeZone (line 33) | Future<void> _configureLocalTimeZone()
class MyApp (line 39) | class MyApp extends StatelessWidget {
method build (line 43) | Widget build(BuildContext context)
FILE: lib/models/routine.dart
class Routine (line 13) | @HiveType(typeId: 2)
method copyWith (line 92) | Routine copyWith({
method skipTask (line 117) | Routine skipTask()
method completeTask (line 126) | Routine completeTask()
method replay (line 137) | Routine replay()
method getCompletedTasks (line 141) | int getCompletedTasks(DateTime d)
method getTotalTime (line 155) | Duration getTotalTime()
method getTimeSpentToday (line 163) | Duration getTimeSpentToday()
method getTimeLeft (line 168) | Duration getTimeLeft()
method addToArchive (line 176) | Routine addToArchive()
method removeFromArchive (line 180) | Routine removeFromArchive()
method removeHistory (line 184) | Routine? removeHistory(String id)
method clearHistory (line 194) | Routine clearHistory()
method markAsCompleted (line 198) | Routine markAsCompleted()
method markAsInCompleted (line 213) | Routine markAsInCompleted()
method taskExists (line 225) | Routine? taskExists(Task t)
method editTasks (line 235) | Routine? editTasks(Task t)
method getDays (line 248) | String getDays()
method taskDiff (line 254) | List<Task> taskDiff(List<Task> first, List<Task> second)
method isToday (line 276) | bool isToday()
method getPercentage (line 280) | double getPercentage()
method getPercentageString (line 286) | String getPercentageString()
FILE: lib/models/routine.g.dart
class RoutineAdapter (line 9) | class RoutineAdapter extends TypeAdapter<Routine> {
method read (line 14) | Routine read(BinaryReader reader)
method write (line 33) | void write(BinaryWriter writer, Routine obj)
FILE: lib/models/task.dart
class Task (line 6) | @HiveType(typeId: 1)
method copyWith (line 26) | Task copyWith({
method toString (line 46) | String toString()
FILE: lib/models/task.g.dart
class TaskAdapter (line 9) | class TaskAdapter extends TypeAdapter<Task> {
method read (line 14) | Task read(BinaryReader reader)
method write (line 28) | void write(BinaryWriter writer, Task obj)
FILE: lib/models/task_event.dart
class TaskEvent (line 6) | @HiveType(typeId: 3)
method toString (line 28) | String toString()
FILE: lib/models/task_event.g.dart
class TaskEventAdapter (line 9) | class TaskEventAdapter extends TypeAdapter<TaskEvent> {
method read (line 14) | TaskEvent read(BinaryReader reader)
method write (line 28) | void write(BinaryWriter writer, TaskEvent obj)
FILE: lib/screens/about.dart
class AboutScreen (line 6) | class AboutScreen extends StatelessWidget {
method build (line 11) | Widget build(BuildContext context)
method openUrl (line 12) | Future<void> openUrl(url)
FILE: lib/screens/app.dart
class App (line 13) | class App extends StatefulWidget {
method createState (line 18) | State<App> createState()
class _AppState (line 21) | class _AppState extends State<App> {
method _onItemTapped (line 40) | void _onItemTapped(int index)
method initState (line 52) | void initState()
method dispose (line 61) | void dispose()
method build (line 67) | Widget build(BuildContext context)
method onNotificationListener (line 132) | void onNotificationListener(String? payload)
FILE: lib/screens/archive_routines.dart
class ArchiveRoutinesScreen (line 7) | class ArchiveRoutinesScreen extends StatelessWidget {
method build (line 12) | Widget build(BuildContext context)
class Action (line 93) | class Action extends StatelessWidget {
method build (line 106) | Widget build(BuildContext context)
FILE: lib/screens/home.dart
class HomeScreen (line 13) | class HomeScreen extends StatelessWidget {
method build (line 17) | Widget build(BuildContext context)
class Header (line 183) | class Header extends StatelessWidget {
method build (line 192) | Widget build(BuildContext context)
FILE: lib/screens/onboarding.dart
class OnBoarding (line 5) | class OnBoarding extends StatefulWidget {
method createState (line 10) | State<OnBoarding> createState()
class _OnBoardingState (line 13) | class _OnBoardingState extends State<OnBoarding> {
method initState (line 24) | void initState()
method dispose (line 30) | void dispose()
method build (line 37) | Widget build(BuildContext context)
class Page (line 140) | class Page extends StatelessWidget {
method build (line 154) | Widget build(BuildContext context)
class Buttons (line 185) | class Buttons extends StatelessWidget {
method build (line 204) | Widget build(BuildContext context)
FILE: lib/screens/routines.dart
class RoutinesScreen (line 10) | class RoutinesScreen extends StatelessWidget {
method build (line 14) | Widget build(BuildContext context)
method addRoutine (line 15) | void addRoutine(Routine r)
method editRoutine (line 19) | void editRoutine(Routine r)
FILE: lib/screens/settings.dart
class SettingsScreen (line 10) | class SettingsScreen extends StatelessWidget {
method build (line 13) | Widget build(BuildContext context)
FILE: lib/screens/start_routine.dart
class RoutineScreen (line 13) | class RoutineScreen extends StatefulWidget {
method createState (line 18) | State<RoutineScreen> createState()
class RoutineScreenState (line 21) | class RoutineScreenState extends State<RoutineScreen>
method initState (line 33) | void initState()
method onTap (line 94) | void onTap(TapUpDetails? _)
method onDismiss (line 121) | void onDismiss(DismissDirection t, BuildContext context)
method dispose (line 170) | void dispose()
method build (line 179) | Widget build(BuildContext context)
class MyAppBar (line 399) | class MyAppBar extends StatelessWidget {
method build (line 405) | Widget build(BuildContext context)
FILE: lib/screens/stats.dart
class Statistics (line 13) | class Statistics extends StatelessWidget {
method build (line 18) | Widget build(BuildContext context)
method clearHistory (line 19) | void clearHistory()
FILE: lib/screens/tasks.dart
class TasksScreen (line 10) | class TasksScreen extends StatelessWidget {
method build (line 15) | Widget build(BuildContext context)
method addTask (line 16) | void addTask(Task t)
method onEdit (line 20) | void onEdit(Task t)
method onCreateTask (line 25) | void onCreateTask()
FILE: lib/services/notification_service.dart
class NotificationService (line 7) | class NotificationService {
method showNotification (line 22) | Future<void> showNotification({
method scheduleDaily (line 42) | Future<void> scheduleDaily({
method scheduleWeekly (line 68) | Future<void> scheduleWeekly({
method scheduledNotification (line 123) | Future<void> scheduledNotification(
method getDeviceLaunchInfo (line 139) | Future<NotificationAppLaunchDetails?> getDeviceLaunchInfo()
method cancelNotification (line 144) | Future<void> cancelNotification(String id)
method cancelNotificationWithId (line 148) | Future<void> cancelNotificationWithId(int id)
method cancelAllNotifications (line 152) | Future<void> cancelAllNotifications()
method _dailyAt (line 156) | tz.TZDateTime _dailyAt(TimeOfDay time)
method _scheduleWeekly (line 166) | tz.TZDateTime _scheduleWeekly(
method initialize (line 180) | Future<void> initialize()
method onSelectNotification (line 188) | void onSelectNotification(NotificationResponse? response)
FILE: lib/services/routines_provider.dart
class RoutineModel (line 15) | class RoutineModel extends ChangeNotifier {
method _init (line 23) | void _init()
method add (line 39) | void add(Routine routine)
method edit (line 59) | void edit(Routine routine)
method getHistory (line 83) | List<TaskEvent> getHistory({int clamp = 0})
method getMostProductiveHour (line 95) | int getMostProductiveHour()
method getTimeSpentToday (line 110) | int getTimeSpentToday()
method getMostProductiveDay (line 119) | DateTime? getMostProductiveDay()
method skipTask (line 141) | void skipTask(String id)
method getRoutine (line 152) | Routine? getRoutine(String id)
method getWeeklyStats (line 161) | List<int> getWeeklyStats()
method getRoutineStartMaxDays (line 177) | int getRoutineStartMaxDays(String id)
method getRoutineStats (line 188) | List<int> getRoutineStats(String id)
method getStartDate (line 211) | DateTime getStartDate(String id)
method removeHistory (line 222) | void removeHistory(String tid)
method clearHistory (line 233) | void clearHistory()
method getRoutineDayFrequencyStats (line 244) | List<int> getRoutineDayFrequencyStats(String id)
method totalNoOfTasksToday (line 261) | int totalNoOfTasksToday()
method totalNoOfCompletedTasksToday (line 275) | int totalNoOfCompletedTasksToday()
method completeTask (line 289) | void completeTask(String id)
method replay (line 300) | void replay(String id)
method editTask (line 311) | void editTask(Task t)
method toggleMarkAsCompleted (line 324) | void toggleMarkAsCompleted(String id)
method removeTask (line 340) | void removeTask(Task t)
method delete (line 363) | void delete(String id)
method todaysRoutines (line 374) | List<Routine> todaysRoutines()
method allRoutines (line 385) | List<Routine> allRoutines()
method archiveRoutines (line 396) | List<Routine> archiveRoutines()
method addToArchive (line 400) | void addToArchive(String id)
method removeFromArchive (line 412) | void removeFromArchive(String id)
method toggleNotifications (line 437) | void toggleNotifications()
method enableAllNotifications (line 452) | void enableAllNotifications()
method scheduleWeekly (line 473) | void scheduleWeekly(Routine r)
method cancelAllNotifications (line 485) | void cancelAllNotifications()
FILE: lib/services/tasks_provider.dart
class TaskModel (line 7) | class TaskModel extends ChangeNotifier {
method _init (line 17) | void _init()
method add (line 25) | void add(Task task)
method edit (line 31) | void edit(Task task)
method delete (line 41) | void delete(String id)
FILE: lib/services/theme_provider.dart
class ThemeModel (line 4) | class ThemeModel with ChangeNotifier {
method isDark (line 15) | bool isDark()
FILE: lib/utils/colors_util.dart
function darken (line 3) | Color darken(Color color, [double amount = .1])
function lighten (line 12) | Color lighten(Color color, [double amount = .1])
FILE: lib/utils/date_time_extension.dart
function isSameDate (line 2) | bool isSameDate(DateTime other)
FILE: lib/utils/duration_to_string.dart
function durationToString (line 1) | String durationToString(Duration duration)
FILE: lib/utils/greetings.dart
function greeting (line 1) | String greeting()
FILE: lib/utils/parse_duration.dart
function parseDuration (line 1) | Duration parseDuration(String s)
FILE: lib/utils/time_of_day_util.dart
function timeOfDayToDateTime (line 3) | DateTime? timeOfDayToDateTime(TimeOfDay? t)
function dateTimeToTimeOfDay (line 11) | TimeOfDay dateTimeToTimeOfDay(DateTime t)
FILE: linux/flutter/generated_plugin_registrant.cc
function fl_register_plugins (line 12) | void fl_register_plugins(FlPluginRegistry* registry) {
FILE: linux/main.cc
function main (line 3) | int main(int argc, char** argv) {
FILE: linux/my_application.cc
type _MyApplication (line 10) | struct _MyApplication {
function my_application_activate (line 18) | static void my_application_activate(GApplication* application) {
function gboolean (line 66) | static gboolean my_application_local_command_line(GApplication* applicat...
function my_application_dispose (line 85) | static void my_application_dispose(GObject* object) {
function my_application_class_init (line 91) | static void my_application_class_init(MyApplicationClass* klass) {
function my_application_init (line 97) | static void my_application_init(MyApplication* self) {}
function MyApplication (line 99) | MyApplication* my_application_new() {
FILE: test/widget_test.dart
function main (line 13) | void main()
FILE: windows/flutter/generated_plugin_registrant.cc
function RegisterPlugins (line 12) | void RegisterPlugins(flutter::PluginRegistry* registry) {
FILE: windows/runner/flutter_window.cpp
function LRESULT (line 40) | LRESULT
FILE: windows/runner/flutter_window.h
function class (line 12) | class FlutterWindow : public Win32Window {
FILE: windows/runner/main.cpp
function wWinMain (line 8) | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FILE: windows/runner/utils.cpp
function CreateAndAttachConsole (line 10) | void CreateAndAttachConsole() {
function GetCommandLineArguments (line 24) | std::vector<std::string> GetCommandLineArguments() {
function Utf8FromUtf16 (line 44) | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
FILE: windows/runner/win32_window.cpp
function Scale (line 18) | int Scale(int source, double scale_factor) {
function EnableFullDpiSupportIfAvailable (line 24) | void EnableFullDpiSupportIfAvailable(HWND hwnd) {
class WindowClassRegistrar (line 41) | class WindowClassRegistrar {
method WindowClassRegistrar (line 46) | static WindowClassRegistrar* GetInstance() {
method WindowClassRegistrar (line 62) | WindowClassRegistrar() = default;
function wchar_t (line 71) | const wchar_t* WindowClassRegistrar::GetWindowClass() {
function LRESULT (line 133) | LRESULT CALLBACK Win32Window::WndProc(HWND const window,
function LRESULT (line 152) | LRESULT
function Win32Window (line 208) | Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
function RECT (line 224) | RECT Win32Window::GetClientArea() {
function HWND (line 230) | HWND Win32Window::GetHandle() {
FILE: windows/runner/win32_window.h
type Size (line 21) | struct Size {
Condensed preview — 132 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (393K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 664,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 595,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
},
{
"path": ".gitignore",
"chars": 758,
"preview": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\nmigrate_working_dir/\n\n# IntelliJ re"
},
{
"path": ".metadata",
"chars": 1668,
"preview": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrade"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5202,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "LICENSE.md",
"chars": 1060,
"preview": "Copyright 2021 Mazahir\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of thi"
},
{
"path": "README.md",
"chars": 1705,
"preview": "# Koduko\n\nYet another Habit tracker made with flutter.\n\n\n## ❓ About\n\nIt's an open source and free app where you can mana"
},
{
"path": "analysis_options.yaml",
"chars": 1488,
"preview": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n#"
},
{
"path": "android/.gitignore",
"chars": 285,
"preview": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n\n# Remembe"
},
{
"path": "android/app/build.gradle",
"chars": 2711,
"preview": "plugins {\n id \"com.android.application\"\n id \"kotlin-android\"\n id \"dev.flutter.flutter-gradle-plugin\"\n}\n\ndef loc"
},
{
"path": "android/app/src/debug/AndroidManifest.xml",
"chars": 411,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.example.koduko\">\n <!-- The INTE"
},
{
"path": "android/app/src/main/AndroidManifest.xml",
"chars": 1667,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.example.koduko\">\n <application\n "
},
{
"path": "android/app/src/main/kotlin/com/example/koduko/MainActivity.kt",
"chars": 123,
"preview": "package com.example.koduko\n\nimport io.flutter.embedding.android.FlutterActivity\n\nclass MainActivity: FlutterActivity() {"
},
{
"path": "android/app/src/main/res/drawable/launch_background.xml",
"chars": 434,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
},
{
"path": "android/app/src/main/res/drawable-v21/launch_background.xml",
"chars": 438,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
},
{
"path": "android/app/src/main/res/values/styles.xml",
"chars": 996,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <!-- Theme applied to the Android Window while the process is sta"
},
{
"path": "android/app/src/main/res/values-night/styles.xml",
"chars": 995,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <!-- Theme applied to the Android Window while the process is sta"
},
{
"path": "android/app/src/profile/AndroidManifest.xml",
"chars": 411,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.example.koduko\">\n <!-- The INTE"
},
{
"path": "android/build.gradle",
"chars": 300,
"preview": "allprojects {\nrepositories {\n google()\n jcenter()\n}\n}\n\nrootProject.buildDir = '../build'\nsubprojects {\n project"
},
{
"path": "android/gradle/wrapper/gradle-wrapper.properties",
"chars": 231,
"preview": "#Fri Jun 23 08:50:38 CEST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER"
},
{
"path": "android/gradle.properties",
"chars": 82,
"preview": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
},
{
"path": "android/settings.gradle",
"chars": 726,
"preview": "pluginManagement {\n def flutterSdkPath = {\n def properties = new Properties()\n file(\"local.properties\")"
},
{
"path": "ios/.gitignore",
"chars": 569,
"preview": "**/dgph\n*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/De"
},
{
"path": "ios/Flutter/AppFrameworkInfo.plist",
"chars": 773,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Flutter/Debug.xcconfig",
"chars": 30,
"preview": "#include \"Generated.xcconfig\"\n"
},
{
"path": "ios/Flutter/Release.xcconfig",
"chars": 30,
"preview": "#include \"Generated.xcconfig\"\n"
},
{
"path": "ios/Runner/AppDelegate.swift",
"chars": 537,
"preview": "import UIKit\nimport Flutter\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n override func applicatio"
},
{
"path": "ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 2630,
"preview": "{\n \"images\": [\n {\n \"filename\": \"AppIcon@2x.png\",\n \"idiom\": \"iphone\",\n \"scale\": \"2x\",\n \"size\": \"6"
},
{
"path": "ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
"chars": 391,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"LaunchImage.png\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
"chars": 336,
"preview": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in"
},
{
"path": "ios/Runner/Base.lproj/LaunchScreen.storyboard",
"chars": 2377,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "ios/Runner/Base.lproj/Main.storyboard",
"chars": 1605,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "ios/Runner/Info.plist",
"chars": 1640,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner/Runner-Bridging-Header.h",
"chars": 38,
"preview": "#import \"GeneratedPluginRegistrant.h\"\n"
},
{
"path": "ios/Runner.xcodeproj/project.pbxproj",
"chars": 18522,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:\">\n </FileRef"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"chars": 3185,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1300\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ios/Runner.xcworkspace/contents.xcworkspacedata",
"chars": 152,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "lib/components/card.dart",
"chars": 8103,
"preview": "import 'package:flutter/material.dart';\nimport 'package:google_fonts/google_fonts.dart';\nimport 'package:koduko/utils/du"
},
{
"path": "lib/components/create_routine_bottom_sheet.dart",
"chars": 25866,
"preview": "import 'package:flutter/material.dart';\nimport 'package:koduko/components/name_page_bottom_sheet.dart';\nimport 'package:"
},
{
"path": "lib/components/create_task_bottom_sheet.dart",
"chars": 15318,
"preview": "import 'package:duration_picker/duration_picker.dart';\nimport 'package:flutter/material.dart';\nimport 'package:koduko/co"
},
{
"path": "lib/components/daily_activity.dart",
"chars": 2323,
"preview": "import 'package:flutter/material.dart';\nimport 'package:koduko/services/routines_provider.dart';\nimport 'package:percent"
},
{
"path": "lib/components/header.dart",
"chars": 970,
"preview": "import 'package:flutter/material.dart';\n\nclass ScreenHeader extends StatelessWidget {\n const ScreenHeader({super.key, r"
},
{
"path": "lib/components/most_productive_hour.dart",
"chars": 1184,
"preview": "import 'package:flutter/material.dart';\nimport 'package:intl/intl.dart';\nimport 'package:koduko/services/routines_provid"
},
{
"path": "lib/components/name_page_bottom_sheet.dart",
"chars": 1322,
"preview": "import 'package:flutter/material.dart';\n\nclass NamePage extends StatelessWidget {\n const NamePage(\n {super.key,\n "
},
{
"path": "lib/components/productive_day.dart",
"chars": 1053,
"preview": "import 'package:flutter/material.dart';\nimport 'package:intl/intl.dart';\nimport 'package:koduko/services/routines_provid"
},
{
"path": "lib/components/routine_chart.dart",
"chars": 6172,
"preview": "import 'dart:math';\n\nimport 'package:fl_chart/fl_chart.dart';\nimport 'package:flutter/material.dart';\nimport 'package:in"
},
{
"path": "lib/components/routine_tile.dart",
"chars": 11961,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_slidable/flutter_slidable.dart';\nimport 'package:koduko/"
},
{
"path": "lib/components/task_tile.dart",
"chars": 3924,
"preview": "import 'package:flutter/material.dart';\nimport 'package:koduko/components/create_task_bottom_sheet.dart';\nimport 'packag"
},
{
"path": "lib/components/time_spent_today.dart",
"chars": 967,
"preview": "import 'package:flutter/material.dart';\nimport 'package:koduko/services/routines_provider.dart';\nimport 'package:provide"
},
{
"path": "lib/components/weekly_chart.dart",
"chars": 8450,
"preview": "import 'dart:math';\nimport 'package:fl_chart/fl_chart.dart';\nimport 'package:flutter/material.dart';\nimport 'package:int"
},
{
"path": "lib/main.dart",
"chars": 4560,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_native_timezone/flutter_native_timezone.dart';\nimport 'p"
},
{
"path": "lib/models/routine.dart",
"chars": 7011,
"preview": "import 'package:flutter/material.dart';\nimport 'package:hive/hive.dart';\nimport 'package:intl/intl.dart';\nimport 'packag"
},
{
"path": "lib/models/routine.g.dart",
"chars": 1796,
"preview": "// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'routine.dart';\n\n// *************************************************"
},
{
"path": "lib/models/task.dart",
"chars": 1023,
"preview": "import 'package:flutter/material.dart';\nimport 'package:hive/hive.dart';\nimport 'package:uuid/uuid.dart';\npart 'task.g.d"
},
{
"path": "lib/models/task.g.dart",
"chars": 1223,
"preview": "// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'task.dart';\n\n// ****************************************************"
},
{
"path": "lib/models/task_event.dart",
"chars": 680,
"preview": "import 'package:hive_flutter/adapters.dart';\nimport 'package:uuid/uuid.dart';\n\npart 'task_event.g.dart';\n\n@HiveType(type"
},
{
"path": "lib/models/task_event.g.dart",
"chars": 1266,
"preview": "// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'task_event.dart';\n\n// **********************************************"
},
{
"path": "lib/screens/about.dart",
"chars": 4303,
"preview": "import 'package:flutter/gestures.dart';\nimport 'package:flutter/material.dart';\nimport 'package:koduko/components/header"
},
{
"path": "lib/screens/app.dart",
"chars": 4370,
"preview": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:fl"
},
{
"path": "lib/screens/archive_routines.dart",
"chars": 4587,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_slidable/flutter_slidable.dart';\nimport 'package:koduko/"
},
{
"path": "lib/screens/home.dart",
"chars": 9479,
"preview": "import 'package:flutter/material.dart';\nimport 'package:google_fonts/google_fonts.dart';\nimport 'package:intl/intl.dart'"
},
{
"path": "lib/screens/onboarding.dart",
"chars": 9646,
"preview": "import 'package:flutter/material.dart';\nimport 'package:google_fonts/google_fonts.dart';\nimport 'package:hive_flutter/ad"
},
{
"path": "lib/screens/routines.dart",
"chars": 8187,
"preview": "import 'package:flutter/material.dart';\nimport 'package:google_fonts/google_fonts.dart';\nimport 'package:intl/intl.dart'"
},
{
"path": "lib/screens/settings.dart",
"chars": 7478,
"preview": "import 'package:flutter/material.dart';\nimport 'package:google_fonts/google_fonts.dart';\nimport 'package:koduko/screens/"
},
{
"path": "lib/screens/start_routine.dart",
"chars": 16521,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:google_fonts/google_font"
},
{
"path": "lib/screens/stats.dart",
"chars": 5242,
"preview": "import 'package:flutter/material.dart';\nimport 'package:intl/intl.dart';\nimport 'package:koduko/components/daily_activit"
},
{
"path": "lib/screens/tasks.dart",
"chars": 4821,
"preview": "import 'package:flutter/material.dart';\nimport 'package:koduko/components/create_task_bottom_sheet.dart';\nimport 'packag"
},
{
"path": "lib/services/notification_service.dart",
"chars": 6029,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_local_notifications/flutter_local_notifications.dart';\ni"
},
{
"path": "lib/services/routines_provider.dart",
"chars": 12534,
"preview": "import 'dart:collection';\nimport 'dart:math';\n\nimport 'package:collection/collection.dart';\nimport 'package:flutter/mate"
},
{
"path": "lib/services/tasks_provider.dart",
"chars": 1153,
"preview": "import 'dart:collection';\n\nimport 'package:flutter/material.dart';\nimport 'package:hive_flutter/adapters.dart';\nimport '"
},
{
"path": "lib/services/theme_provider.dart",
"chars": 1116,
"preview": "import 'package:flutter/material.dart';\nimport 'package:hive/hive.dart';\n\nclass ThemeModel with ChangeNotifier {\n var _"
},
{
"path": "lib/utils/colors_util.dart",
"chars": 525,
"preview": "import 'package:flutter/material.dart';\n\nColor darken(Color color, [double amount = .1]) {\n assert(amount >= 0 && amoun"
},
{
"path": "lib/utils/date_time_extension.dart",
"chars": 157,
"preview": "extension DateOnlyCompare on DateTime {\n bool isSameDate(DateTime other) {\n return year == other.year && month == ot"
},
{
"path": "lib/utils/duration_to_string.dart",
"chars": 137,
"preview": "String durationToString(Duration duration) {\n return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padL"
},
{
"path": "lib/utils/greetings.dart",
"chars": 168,
"preview": "String greeting() {\n var hour = DateTime.now().hour;\n if (hour < 12) {\n return 'Morning';\n }\n if (hour < 17) {\n "
},
{
"path": "lib/utils/parse_duration.dart",
"chars": 425,
"preview": "Duration parseDuration(String s) {\n int hours = 0;\n int minutes = 0;\n int micros;\n List<String> parts = s.split(':')"
},
{
"path": "lib/utils/time_of_day_util.dart",
"chars": 309,
"preview": "import 'package:flutter/material.dart';\n\nDateTime? timeOfDayToDateTime(TimeOfDay? t) {\n if (t == null) {\n return nul"
},
{
"path": "linux/.gitignore",
"chars": 18,
"preview": "flutter/ephemeral\n"
},
{
"path": "linux/CMakeLists.txt",
"chars": 5180,
"preview": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.10)\nproject(runner LANGUAGES CXX)\n\n# The name of the exe"
},
{
"path": "linux/flutter/CMakeLists.txt",
"chars": 2815,
"preview": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.10)\n\nset(EPHEM"
},
{
"path": "linux/flutter/generated_plugin_registrant.cc",
"chars": 695,
"preview": "//\n// Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n#include <dynamic"
},
{
"path": "linux/flutter/generated_plugin_registrant.h",
"chars": 303,
"preview": "//\n// Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUG"
},
{
"path": "linux/flutter/generated_plugins.cmake",
"chars": 776,
"preview": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n dynamic_color\n url_launcher_linux\n)\n\nlist(APPEND "
},
{
"path": "linux/main.cc",
"chars": 180,
"preview": "#include \"my_application.h\"\n\nint main(int argc, char** argv) {\n g_autoptr(MyApplication) app = my_application_new();\n "
},
{
"path": "linux/my_application.cc",
"chars": 3710,
"preview": "#include \"my_application.h\"\n\n#include <flutter_linux/flutter_linux.h>\n#ifdef GDK_WINDOWING_X11\n#include <gdk/gdkx.h>\n#en"
},
{
"path": "linux/my_application.h",
"chars": 388,
"preview": "#ifndef FLUTTER_MY_APPLICATION_H_\n#define FLUTTER_MY_APPLICATION_H_\n\n#include <gtk/gtk.h>\n\nG_DECLARE_FINAL_TYPE(MyApplic"
},
{
"path": "macos/.gitignore",
"chars": 89,
"preview": "# Flutter-related\n**/Flutter/ephemeral/\n**/Pods/\n\n# Xcode-related\n**/dgph\n**/xcuserdata/\n"
},
{
"path": "macos/Flutter/Flutter-Debug.xcconfig",
"chars": 48,
"preview": "#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
},
{
"path": "macos/Flutter/Flutter-Release.xcconfig",
"chars": 48,
"preview": "#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
},
{
"path": "macos/Flutter/GeneratedPluginRegistrant.swift",
"chars": 779,
"preview": "//\n// Generated file. Do not edit.\n//\n\nimport FlutterMacOS\nimport Foundation\n\nimport dynamic_color\nimport flutter_local"
},
{
"path": "macos/Runner/AppDelegate.swift",
"chars": 214,
"preview": "import Cocoa\nimport FlutterMacOS\n\n@NSApplicationMain\nclass AppDelegate: FlutterAppDelegate {\n override func application"
},
{
"path": "macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1291,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"16x16\",\n \"idiom\" : \"mac\",\n \"filename\" : \"app_icon_16.png\",\n \"scale"
},
{
"path": "macos/Runner/Base.lproj/MainMenu.xib",
"chars": 23723,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "macos/Runner/Configs/AppInfo.xcconfig",
"chars": 598,
"preview": "// Application-level settings for the Runner target.\n//\n// This may be replaced with something auto-generated from metad"
},
{
"path": "macos/Runner/Configs/Debug.xcconfig",
"chars": 77,
"preview": "#include \"../../Flutter/Flutter-Debug.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
},
{
"path": "macos/Runner/Configs/Release.xcconfig",
"chars": 79,
"preview": "#include \"../../Flutter/Flutter-Release.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
},
{
"path": "macos/Runner/Configs/Warnings.xcconfig",
"chars": 580,
"preview": "WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverl"
},
{
"path": "macos/Runner/DebugProfile.entitlements",
"chars": 348,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/Runner/Info.plist",
"chars": 1060,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/Runner/MainFlutterWindow.swift",
"chars": 393,
"preview": "import Cocoa\nimport FlutterMacOS\n\nclass MainFlutterWindow: NSWindow {\n override func awakeFromNib() {\n let flutterVi"
},
{
"path": "macos/Runner/Release.entitlements",
"chars": 240,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/Runner.xcodeproj/project.pbxproj",
"chars": 21315,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXAggregateTarget sec"
},
{
"path": "macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"chars": 3185,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1300\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "macos/Runner.xcworkspace/contents.xcworkspacedata",
"chars": 152,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "pubspec.yaml",
"chars": 3944,
"preview": "name: koduko\ndescription: A new Flutter project.\n\n# The following line prevents the package from being accidentally publ"
},
{
"path": "test/widget_test.dart",
"chars": 1057,
"preview": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester"
},
{
"path": "web/index.html",
"chars": 1816,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!--\n If you are serving your web app in a path other than the root, change the\n h"
},
{
"path": "web/manifest.json",
"chars": 908,
"preview": "{\n \"name\": \"koduko\",\n \"short_name\": \"koduko\",\n \"start_url\": \".\",\n \"display\": \"standalone\",\n \"background_c"
},
{
"path": "windows/.gitignore",
"chars": 291,
"preview": "flutter/ephemeral/\n\n# Visual Studio user-specific files.\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Visual Studio bu"
},
{
"path": "windows/CMakeLists.txt",
"chars": 3897,
"preview": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.14)\nproject(koduko LANGUAGES CXX)\n\n# The name of the exe"
},
{
"path": "windows/flutter/CMakeLists.txt",
"chars": 3562,
"preview": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.14)\n\nset(EPHEM"
},
{
"path": "windows/flutter/generated_plugin_registrant.cc",
"chars": 491,
"preview": "//\n// Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n#include <dynamic"
},
{
"path": "windows/flutter/generated_plugin_registrant.h",
"chars": 302,
"preview": "//\n// Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUG"
},
{
"path": "windows/flutter/generated_plugins.cmake",
"chars": 782,
"preview": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n dynamic_color\n url_launcher_windows\n)\n\nlist(APPEN"
},
{
"path": "windows/runner/CMakeLists.txt",
"chars": 1190,
"preview": "cmake_minimum_required(VERSION 3.14)\nproject(runner LANGUAGES CXX)\n\n# Define the application target. To change its name,"
},
{
"path": "windows/runner/Runner.rc",
"chars": 2844,
"preview": "// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n#include \"resource.h\"\n\n#define APSTUDIO_R"
},
{
"path": "windows/runner/flutter_window.cpp",
"chars": 1762,
"preview": "#include \"flutter_window.h\"\n\n#include <optional>\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nFlutterWindow::Flutt"
},
{
"path": "windows/runner/flutter_window.h",
"chars": 928,
"preview": "#ifndef RUNNER_FLUTTER_WINDOW_H_\n#define RUNNER_FLUTTER_WINDOW_H_\n\n#include <flutter/dart_project.h>\n#include <flutter/f"
},
{
"path": "windows/runner/main.cpp",
"chars": 1266,
"preview": "#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n#include <windows.h>\n\n#include \"flutter_w"
},
{
"path": "windows/runner/resource.h",
"chars": 432,
"preview": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by Runner.rc\n//\n#define IDI_APP_ICON "
},
{
"path": "windows/runner/runner.exe.manifest",
"chars": 859,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersi"
},
{
"path": "windows/runner/utils.cpp",
"chars": 1691,
"preview": "#include \"utils.h\"\n\n#include <flutter_windows.h>\n#include <io.h>\n#include <stdio.h>\n#include <windows.h>\n\n#include <iost"
},
{
"path": "windows/runner/utils.h",
"chars": 672,
"preview": "#ifndef RUNNER_UTILS_H_\n#define RUNNER_UTILS_H_\n\n#include <string>\n#include <vector>\n\n// Creates a console for the proce"
},
{
"path": "windows/runner/win32_window.cpp",
"chars": 7024,
"preview": "#include \"win32_window.h\"\n\n#include <flutter_windows.h>\n\n#include \"resource.h\"\n\nnamespace {\n\nconstexpr const wchar_t kWi"
},
{
"path": "windows/runner/win32_window.h",
"chars": 3350,
"preview": "#ifndef RUNNER_WIN32_WINDOW_H_\n#define RUNNER_WIN32_WINDOW_H_\n\n#include <windows.h>\n\n#include <functional>\n#include <mem"
}
]
About this extraction
This page contains the full source code of the Mazahir26/koduko GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 132 files (358.4 KB), approximately 83.8k tokens, and a symbol index with 259 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.