├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .idea
├── libraries
│ ├── Dart_SDK.xml
│ └── KotlinJavaRuntime.xml
├── modules.xml
├── runConfigurations
│ └── main_dart.xml
└── workspace.xml
├── .metadata
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .DS_Store
├── .gitignore
├── app
│ ├── .DS_Store
│ ├── build.gradle
│ └── src
│ │ ├── .DS_Store
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── .DS_Store
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── vtime
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── .DS_Store
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── .DS_Store
│ │ │ ├── ic_launcher.png
│ │ │ └── launch_image.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── .DS_Store
│ │ │ ├── ic_launcher.png
│ │ │ └── launch_image.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── .DS_Store
│ │ │ ├── ic_launcher.png
│ │ │ └── launch_image.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── .DS_Store
│ │ │ ├── ic_launcher.png
│ │ │ └── launch_image.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── .DS_Store
│ │ │ ├── ic_launcher.png
│ │ │ └── launch_image.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── vtime_android.iml
├── assets
├── alarms
│ ├── .DS_Store
│ ├── Crystal.mp3
│ ├── Crystalie.mp3
│ ├── Favour.mp3
│ ├── Guitar.mp3
│ ├── Harmonics.mp3
│ ├── Iris.mp3
│ ├── Marigold.mp3
│ ├── Nonimooley.mp3
│ ├── Points.mp3
│ ├── SMS.mp3
│ └── Violet.mp3
├── i18n
│ ├── en.json
│ ├── ka.json
│ ├── ru.json
│ └── tr.json
└── release
│ └── visual-time.apk
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── 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
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── logo-1024.png
│ │ ├── logo-20.png
│ │ ├── logo-20@2x.png
│ │ ├── logo-20@3x.png
│ │ ├── logo-29.png
│ │ ├── logo-29@2x.png
│ │ ├── logo-29@3x.png
│ │ ├── logo-40.png
│ │ ├── logo-40@2x.png
│ │ ├── logo-40@3x.png
│ │ ├── logo-60@2x.png
│ │ ├── logo-60@3x.png
│ │ ├── logo-76.png
│ │ ├── logo-76@2x.png
│ │ └── logo-83.5@2x.png
│ ├── Contents.json
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── app.dart
├── core
│ ├── cubits
│ │ ├── preference_cubit.dart
│ │ └── preference_state.dart
│ ├── model
│ │ ├── day.dart
│ │ ├── task.dart
│ │ ├── task.g.dart
│ │ └── vt_model.dart
│ ├── services
│ │ └── local_db_service.dart
│ ├── utils
│ │ ├── intl.dart
│ │ ├── logger.dart
│ │ ├── utils.dart
│ │ └── widgets.dart
│ └── vt.dart
├── generated_plugin_registrant.dart
├── main.dart
└── view
│ ├── create.dart
│ ├── dashboard.dart
│ ├── day_view.dart
│ ├── edit.dart
│ ├── live-task
│ └── dashboard.dart
│ ├── set_up.dart
│ ├── settings.dart
│ └── widgets
│ ├── components
│ ├── appbars.dart
│ ├── buttons.dart
│ ├── custom_switchers.dart
│ ├── loadings.dart
│ └── themes.dart
│ ├── day_chart.dart
│ ├── live-task
│ └── clock_count.dart
│ ├── mini_day_card.dart
│ ├── task_card.dart
│ └── utils.dart
├── macos
├── .DS_Store
├── .gitignore
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Runner
│ ├── .DS_Store
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── .DS_Store
│ └── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── logo 1-1024.png
│ │ ├── logo 1-128.png
│ │ ├── logo 1-16.png
│ │ ├── logo 1-256.png
│ │ ├── logo 1-32.png
│ │ ├── logo 1-512.png
│ │ └── logo 1-64.png
│ ├── Base.lproj
│ └── MainMenu.xib
│ ├── Configs
│ ├── AppInfo.xcconfig
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── Warnings.xcconfig
│ ├── DebugProfile.entitlements
│ ├── Info.plist
│ ├── MainFlutterWindow.swift
│ └── Release.entitlements
├── pubspec.yaml
├── test
└── core
│ ├── cubits
│ └── preference_state_test.dart
│ ├── models
│ ├── day_test.dart
│ ├── task_test.dart
│ └── vt_model_test.dart
│ ├── utils
│ ├── intl_test.dart
│ ├── logger_test.dart
│ └── widgets_test.dart
│ └── vt_test.dart
├── vtime.iml
└── web
├── favicon.png
├── icons
├── Icon-192.png
└── Icon-512.png
├── index.html
└── manifest.json
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://www.dartlang.org/guides/libraries/private-files
2 |
3 | # Files and directories created by pub
4 | .dart_tool/
5 | .packages
6 | build/
7 | # If you're building an application, you may want to check-in your pubspec.lock
8 | pubspec.lock
9 | .metadata
10 | .packages
11 | .flutter-plugins
12 | .flutter-plugins-dependencies
13 |
14 | # Directory created by dartdoc
15 | # If you don't generate documentation locally you can remove this line.
16 | doc/api/
17 |
18 | # Avoid committing generated Javascript files:
19 | *.dart.js
20 | *.info.json # Produced by the --dump-info flag.
21 | *.js # When generated by dart2js. Don't specify *.js if your
22 | # project includes source files written in JavaScript.
23 | *.js_
24 | *.js.deps
25 | *.js.map
26 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/libraries/KotlinJavaRuntime.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/main_dart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: b22742018b3edf16c6cadd7b76d9db5e7f9064b5
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Citizen Code of Conduct
2 |
3 | ## 1. Purpose
4 |
5 | A primary goal of Visual Time is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).
6 |
7 | This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior.
8 |
9 | We invite all those who participate in Visual Time to help us create safe and positive experiences for everyone.
10 |
11 | ## 2. Open [Source/Culture/Tech] Citizenship
12 |
13 | A supplemental goal of this Code of Conduct is to increase open [source/culture/tech] citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community.
14 |
15 | Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society.
16 |
17 | If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know.
18 |
19 | ## 3. Expected Behavior
20 |
21 | The following behaviors are expected and requested of all community members:
22 |
23 | * Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community.
24 | * Exercise consideration and respect in your speech and actions.
25 | * Attempt collaboration before conflict.
26 | * Refrain from demeaning, discriminatory, or harassing behavior and speech.
27 | * Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential.
28 | * Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations.
29 |
30 | ## 4. Unacceptable Behavior
31 |
32 | The following behaviors are considered harassment and are unacceptable within our community:
33 |
34 | * Violence, threats of violence or violent language directed against another person.
35 | * Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language.
36 | * Posting or displaying sexually explicit or violent material.
37 | * Posting or threatening to post other people's personally identifying information ("doxing").
38 | * Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability.
39 | * Inappropriate photography or recording.
40 | * Inappropriate physical contact. You should have someone's consent before touching them.
41 | * Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances.
42 | * Deliberate intimidation, stalking or following (online or in person).
43 | * Advocating for, or encouraging, any of the above behavior.
44 | * Sustained disruption of community events, including talks and presentations.
45 |
46 | ## 5. Weapons Policy
47 |
48 | No weapons will be allowed at Visual Time events, community spaces, or in other spaces covered by the scope of this Code of Conduct. Weapons include but are not limited to guns, explosives (including fireworks), and large knives such as those used for hunting or display, as well as any other item used for the purpose of causing injury or harm to others. Anyone seen in possession of one of these items will be asked to leave immediately, and will only be allowed to return without the weapon. Community members are further expected to comply with all state and local laws on this matter.
49 |
50 | ## 6. Consequences of Unacceptable Behavior
51 |
52 | Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated.
53 |
54 | Anyone asked to stop unacceptable behavior is expected to comply immediately.
55 |
56 | If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event).
57 |
58 | ## 7. Reporting Guidelines
59 |
60 | If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. st.bahahd@gmail.com.
61 |
62 |
63 |
64 | Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress.
65 |
66 | ## 8. Addressing Grievances
67 |
68 | If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies.
69 |
70 |
71 |
72 | ## 9. Scope
73 |
74 | We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues--online and in-person--as well as in all one-on-one communications pertaining to community business.
75 |
76 | This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members.
77 |
78 | ## 10. Contact info
79 |
81 |
82 | Gmail: st.bahahd@gmail.com
83 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | First of all, thank you for considering contributing! :tada:
4 |
5 | Here you will find some guidelines on how to contribute. Feel free to propose changes to this document if you think something is missing or needs to be clarified.
6 |
7 | ## Contributing Guides
8 |
9 | First time contributing? You can learn more about contributing to open source projects through GitHub's [wonderful open source guides](https://opensource.guide/how-to-contribute/).
10 |
11 | ### :bug: Reporting a Problem
12 |
13 | Before you open a new issue, check to see if the problem has [already been reported](https://github.com/theiskaa/VTime/issues). If it has and **the issue is still open**, add a comment to the existing issue instead of creating a new one.
14 |
15 | > **Note:** If you find a **closed** issue that seems to address the same thing that you've found, open a new issue and include a link to the original one.
16 |
17 | When you open an issue, try to be as descriptive as possible. Add any relevant screenshots so that the problem can be identified quickly.
18 |
19 | ### :sparkles: Opening a Pull Request
20 |
21 | > A lot of the following information was inspired by [opensource.guide](https://opensource.guide/how-to-contribute/), a great site to learn all about open source software.
22 |
23 | If you've fixed a bug, started working on an enhancement, or done something else, you can [create a pull request](https://github.com/theiskaa/VTime/pulls) to start a conversation about your changes.
24 |
25 | A pull request doesn't necessarily have to include finished work. It may be better to open a PR early on so that you can get feedback on your contribution. Just mention that it's a work in progress and keep adding commits.
26 |
27 | Here's how to contribute and submit your pull request:
28 |
29 | 1. [**Fork the repository**](https://help.github.com/articles/fork-a-repo/) and clone it locally. Add the original repository as a remote and pull in changes every so often so that you stay up to date with the project.
30 | 2. [**Create a branch**](https://guides.github.com/introduction/flow/) from `main` for your changes.
31 | 3. **Add, commit, and push** your changes to your branch.
32 | 4. **Test out your changes.** Make sure that they work as you intended.
33 | 5. [**Open a pull request**](https://github.com/theiskaa/VTime/pulls) to merge your branch into `main`.
34 | - Reference any issues related to your PR (e.g. "Resolves #17").
35 | - Describe your changes in detail and include screenshots if necessary.
36 | 6. :sunglasses: Sit back, relax, and wait for your PR to be reviewed. You might have to tweak your contribution or elaborate on your changes. That's OK, don't be afraid to justify your reasoning and ask questions.
37 |
38 | Thank you for reading through this contributing guide and welcome to the community! :tada:
39 |
40 | > We gonna make something different. :v:
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ismael Shakverdiev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ## Info
18 | An advanced, minimalist, and powerful time management application. Where you can create the task, give it a duration, and select which weekdays you wanna do it.
19 | By doing this you can easily manage a whole week or a concrete day, or a concrete task. The application sets "Today" automatically. You can see your 24 hours as a circle which is divided by tasks. Also, you can see the task's duration by tapping the divided item on the day circle. Application has a light, dark, and one special **S/2** theme, and supports four languages: *"English, Turkish, Russian, and Georgian"*.
20 | Of course, you can start using concrete tasks as a timer, it will make noise when the task is completed. Also, you can enable "remove task after completing" to remove selected task when the timer is completed. And also you can leave working on task half, when you do it, it will update your task by current duration. (E.g: if your previous duration is 15 minute and you left it at 10 minutes, it will update your task by changing the duration 15 to 10).
21 |
22 | ## Overview
23 | ####
24 |
25 | S/2
26 |
27 | Special minimalist theme S/2
28 |
29 |
30 |
31 |
32 |
33 | Default
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | ---
45 |
46 | ## Contributing
47 | For information regarding contributions, please refer to [CONTRIBUTING.md](https://github.com/theiskaa/VTime/blob/main/CONTRIBUTING.md) file.
48 |
49 | ---
50 |
51 | **Inispired from [Kalle Hallden](https://github.com/KalleHallden)'s [time management app](https://github.com/KalleHallden/Time-management-app)**
52 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | analyzer:
4 | exclude: [build/**]
5 | strong-mode:
6 | implicit-casts: true
7 | implicit-dynamic: true
8 | linter:
9 | rules:
10 | camel_case_types: true
11 | cancel_subscriptions: true
12 | close_sinks: true
13 | comment_references: true
14 | control_flow_in_finally: true
15 | prefer_single_quotes: true
16 | prefer_initializing_formals: false
--------------------------------------------------------------------------------
/android/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/.DS_Store
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/android/app/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/.DS_Store
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 30
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | defaultConfig {
36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
37 | applicationId "com.example.vtime"
38 | minSdkVersion 16
39 | targetSdkVersion 30
40 | versionCode flutterVersionCode.toInteger()
41 | versionName flutterVersionName
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
59 | }
60 |
--------------------------------------------------------------------------------
/android/app/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/.DS_Store
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/.DS_Store
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
13 |
17 |
21 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/vtime/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.vtime
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/.DS_Store
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | -
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | -
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-hdpi/.DS_Store
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/launch_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-hdpi/launch_image.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-mdpi/.DS_Store
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/launch_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-mdpi/launch_image.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xhdpi/.DS_Store
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/launch_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xhdpi/launch_image.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xxhdpi/.DS_Store
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/launch_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xxhdpi/launch_image.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xxxhdpi/.DS_Store
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/launch_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/android/app/src/main/res/mipmap-xxxhdpi/launch_image.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.5.10'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/android/vtime_android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/assets/alarms/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/.DS_Store
--------------------------------------------------------------------------------
/assets/alarms/Crystal.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Crystal.mp3
--------------------------------------------------------------------------------
/assets/alarms/Crystalie.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Crystalie.mp3
--------------------------------------------------------------------------------
/assets/alarms/Favour.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Favour.mp3
--------------------------------------------------------------------------------
/assets/alarms/Guitar.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Guitar.mp3
--------------------------------------------------------------------------------
/assets/alarms/Harmonics.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Harmonics.mp3
--------------------------------------------------------------------------------
/assets/alarms/Iris.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Iris.mp3
--------------------------------------------------------------------------------
/assets/alarms/Marigold.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Marigold.mp3
--------------------------------------------------------------------------------
/assets/alarms/Nonimooley.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Nonimooley.mp3
--------------------------------------------------------------------------------
/assets/alarms/Points.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Points.mp3
--------------------------------------------------------------------------------
/assets/alarms/SMS.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/SMS.mp3
--------------------------------------------------------------------------------
/assets/alarms/Violet.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/alarms/Violet.mp3
--------------------------------------------------------------------------------
/assets/i18n/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "app.setup": "Complete app setup",
3 |
4 | "today": "Today",
5 | "monday": "Monday",
6 | "tuesday": "Tuesday",
7 | "wednesday": "Wednesday",
8 | "thursday": "Thursday",
9 | "friday": "Friday",
10 | "saturday": "Saturday",
11 | "sunday": "Sunday",
12 |
13 | "act.create": "Create",
14 | "act.edit": "Edit",
15 | "act.save": "Save",
16 | "act.yes": "Yes",
17 | "act.no": "No",
18 | "act.delete": "Delete",
19 | "act.addTask": "Add task",
20 | "act.clearWeek": "Clear Week",
21 | "clear.week.title": "Are you sure you want to clear your whole week?",
22 | "act.start": "Start",
23 | "act.stop": "Stop",
24 | "act.clearDay": "Clear all",
25 | "clear.day.title": "Are you sure you want to clear current day's tasks?",
26 |
27 | "prefs.settings": "Settings",
28 | "prefs.appearance": "Appearance",
29 | "prefs.appearance.light": "Light",
30 | "prefs.appearance.dark": "Dark",
31 | "prefs.lang": "Language",
32 | "prefs.alarmSound": "Alarm Sound",
33 | "prefs.animations": "Animations",
34 |
35 | "live_work.selected_task": "Selected Task",
36 | "live_work.removeTaskAfterCompleting": "Remove task after completing",
37 | "live_work.runtimeLogoutRequestError": "The task is still ongoing... Are you sure you want to quit?",
38 | "live_work.leaveItHalf": "Leave it half",
39 |
40 | "error.not_found_duration": "Please add duration for your task",
41 | "error.selected_duration_more_than_remaining": "You selected duration which exceeds the remaining time of your selected day",
42 | "error.title_field_validation": "Title can't be empty",
43 |
44 | "task.title.hint": "What are you going to do?",
45 | "task.desc.hint": "Describe your task...",
46 | "task.duration.hint": "How long will the task take?",
47 |
48 | "hour": "hour",
49 | "hours": "hours",
50 | "minute": "minute",
51 | "minutes": "minutes",
52 | "and": "and",
53 | "remaining": "Remaining"
54 | }
--------------------------------------------------------------------------------
/assets/i18n/ka.json:
--------------------------------------------------------------------------------
1 | {
2 | "app.setup": "დაასრულეთ აპპ-ის დაყენება",
3 |
4 | "today": "დღეს",
5 | "monday": "ორშაბათი",
6 | "tuesday": "სამშაბათი",
7 | "wednesday": "ოთხშაბათი",
8 | "thursday": "ხუთშაბათი",
9 | "friday": "პარასკევი",
10 | "saturday": "შაბათი",
11 | "sunday": "კვირა",
12 |
13 | "act.create": "Შექმნა",
14 | "act.edit": "რედაქტირება",
15 | "act.save": "დაიმახსოვრე",
16 | "act.yes": "დიახ",
17 | "act.no": "არა",
18 | "act.delete": "წაშლა",
19 | "act.addTask": "დავალების დამატება",
20 | "act.clearWeek": "გაასუფთავე კვირა",
21 | "clear.week.title": "დარწმუნებული ხართ, რომ გსურთ თქვენი მთელი კვირის წაშლა?",
22 | "act.start": "დაწყება",
23 | "act.stop": "გაუქმება",
24 | "act.clearDay": "გაასუფთავე",
25 | "clear.day.title": "დარწმუნებული ხართ, რომ გსურთ თქვენი მთელი დღის დავალებების წაშლა?",
26 |
27 | "prefs.settings": "პარამეტრები",
28 | "prefs.appearance": "გარეგნობა",
29 | "prefs.appearance.light": "ღია",
30 | "prefs.appearance.dark": "მუქი",
31 | "prefs.lang": "Ენა",
32 | "prefs.alarmSound": "განგაშის ხმა",
33 | "prefs.animations": "ანიმაციები",
34 |
35 | "live_work.selected_task": "ამორჩეული დავალება",
36 | "live_work.removeTaskAfterCompleting": "წაშალე დავალება დამთავრების შემდეგ",
37 | "live_work.runtimeLogoutRequestError": "დავალების პროცესი ჯერ კიდევ მიმდინარეობს ... დარწმუნებული ხართ, რომ გსურთ დამთავრება?",
38 | "live_work.leaveItHalf": "შეაჩერე",
39 |
40 | "error.not_found_duration": "გთხოვთ, დაამატოთ თქვენი დავალების ხანგრძლივობა",
41 | "error.selected_duration_more_than_remaining": "თქვენ შეარჩიეთ ხანგრძლივობა, რომელიც აჭარბებს არჩეული დღის დანარჩენ დროს",
42 | "error.title_field_validation": "სათაური არ შეიძლება იყოს ცარიელი",
43 |
44 | "task.title.hint": "Რის გაკეთებას აპირებ?",
45 | "task.desc.hint": "აღწერეთ თქვენი დავალება...",
46 | "task.duration.hint": "რამდენ ხანს დაიკავებს დავალება?",
47 |
48 | "hour": "სთ.",
49 | "hours": "სთ.",
50 | "minute": "წთ.",
51 | "minutes": "წთ.",
52 | "and": "და",
53 | "remaining": "დარჩენილი დრო"
54 | }
--------------------------------------------------------------------------------
/assets/i18n/ru.json:
--------------------------------------------------------------------------------
1 | {
2 | "app.setup": "Полная настройка приложения",
3 |
4 | "today": "Сегодня",
5 | "monday": "Понедельник",
6 | "tuesday": "Вторник",
7 | "wednesday": "Среда",
8 | "thursday": "Четверг",
9 | "friday": "Пятница",
10 | "saturday": "Суббота",
11 | "sunday": "Воскресенье",
12 |
13 | "act.create": "Создавать",
14 | "act.edit": "Редактировать",
15 | "act.save": "Сохранить",
16 | "act.yes": "Да",
17 | "act.no": "Нет",
18 | "act.delete": "Удалить",
19 | "act.addTask": "Добавить задачу",
20 | "act.clearWeek": "Ясная неделя",
21 | "clear.week.title": "Вы уверены, что хотите очистить всю неделю?",
22 | "act.start": "Начало",
23 | "act.stop": "Стоп",
24 | "act.clearDay": "Очистить все",
25 | "clear.day.title": "Вы уверены, что хотите очистить задачи текущего дня?",
26 |
27 | "prefs.settings": "Настройки",
28 | "prefs.appearance": "Тема",
29 | "prefs.appearance.light": "Светлая",
30 | "prefs.appearance.dark": "Темная",
31 | "prefs.lang": "Язык",
32 | "prefs.alarmSound": "Сигнал Tревоги",
33 | "prefs.animations": "Анимации",
34 |
35 | "live_work.selected_task": "Выбранная задача",
36 | "live_work.removeTaskAfterCompleting": "Удалить задачу после завершения",
37 | "live_work.runtimeLogoutRequestError": "Процесс еще продолжается... Вы уверены, что хотите бросить курить?",
38 | "live_work.leaveItHalf": "Приостановить",
39 |
40 | "error.not_found_duration": "Пожалуйста, укажите продолжительность вашей задачи",
41 | "error.selected_duration_more_than_remaining": "Вы выбрали продолжительность, которая превышает оставшееся время выбранного вами дня",
42 | "error.title_field_validation": "Заголовок не может быть пустым",
43 |
44 | "task.title.hint": "Чем ты планируешь заняться?",
45 | "task.desc.hint": "Опишите вашу задачу...",
46 | "task.duration.hint": "Сколько времени займет задача?",
47 |
48 | "hour": "ч.",
49 | "hours": "ч.",
50 | "minute": "мин.",
51 | "minutes": "мин.",
52 | "and": "и",
53 | "remaining": "Оставшийся"
54 | }
--------------------------------------------------------------------------------
/assets/i18n/tr.json:
--------------------------------------------------------------------------------
1 | {
2 | "app.setup": "Uygulama kurulumunu tamamlayın",
3 |
4 | "today": "Bugün",
5 | "monday": "Pazartesi",
6 | "tuesday": "Salı",
7 | "wednesday": "Çarşamba",
8 | "thursday": "Perşembe",
9 | "friday": "Cuma",
10 | "saturday": "Cumartesi",
11 | "sunday": "Pazar",
12 |
13 | "act.create": "Oluştur",
14 | "act.edit": "Düzenle",
15 | "act.save": " Kayıt et",
16 | "act.yes": "Evet",
17 | "act.no": "Hayır",
18 | "act.delete": "Sil",
19 | "act.addTask": "Görev ekle",
20 | "act.clearWeek": "Haftayı Temizle",
21 | "clear.week.title": "Bütün haftanı temizlemek istediğinden emin misin?",
22 | "act.start": "Başlat",
23 | "act.stop": "Durdur",
24 | "act.clearDay": "Hepsini sil",
25 | "clear.day.title": "Şuanda bulunduğunuz günün görevlerini silmek istediğinizden emin misiniz?",
26 |
27 | "prefs.settings": "Ayarlar",
28 | "prefs.appearance": "Görünüm",
29 | "prefs.appearance.light": "Açık",
30 | "prefs.appearance.dark": "Karanlık",
31 | "prefs.lang": "Dil",
32 | "prefs.alarmSound": "Alarm Sesi",
33 | "prefs.animations": "Animasyonlar",
34 |
35 | "live_work.selected_task": "Seçilen Görev",
36 | "live_work.removeTaskAfterCompleting": "Tamamladıktan sonra görevi kaldır",
37 | "live_work.runtimeLogoutRequestError": "Görev hala devam ediyor... Sonlandırmak istediğinizden emin misiniz?",
38 | "live_work.leaveItHalf": "Yarım bırak",
39 |
40 | "error.not_found_duration": "Lütfen göreviniz için süre ekleyin",
41 | "error.selected_duration_more_than_remaining": "Seçtiğiniz günün kalan süresini aşan bir süre seçtiniz",
42 | "error.title_field_validation": "Başlık boş olamaz",
43 |
44 | "task.title.hint": "Ne yapacaksın?",
45 | "task.desc.hint": "Görevini anlat...",
46 | "task.duration.hint": "Görev ne kadar sürecek?",
47 |
48 | "hour": "saat",
49 | "hours": "saat",
50 | "minute": "dakika",
51 | "minutes": "dakika",
52 | "and": "ve",
53 | "remaining": "Kalan süre"
54 | }
--------------------------------------------------------------------------------
/assets/release/visual-time.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/assets/release/visual-time.apk
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/ephemeral/
22 | Flutter/app.flx
23 | Flutter/app.zip
24 | Flutter/flutter_assets/
25 | Flutter/flutter_export_environment.sh
26 | ServiceDefinitions.json
27 | Runner/GeneratedPluginRegistrant.*
28 |
29 | # Exceptions to above rules.
30 | !default.mode1v3
31 | !default.mode2v3
32 | !default.pbxuser
33 | !default.perspectivev3
34 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - audioplayers (0.0.1):
3 | - Flutter
4 | - Flutter (1.0.0)
5 | - path_provider (0.0.1):
6 | - Flutter
7 |
8 | DEPENDENCIES:
9 | - audioplayers (from `.symlinks/plugins/audioplayers/ios`)
10 | - Flutter (from `Flutter`)
11 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
12 |
13 | EXTERNAL SOURCES:
14 | audioplayers:
15 | :path: ".symlinks/plugins/audioplayers/ios"
16 | Flutter:
17 | :path: Flutter
18 | path_provider:
19 | :path: ".symlinks/plugins/path_provider/ios"
20 |
21 | SPEC CHECKSUMS:
22 | audioplayers: 455322b54050b30ea4b1af7cd9e9d105f74efa8c
23 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
24 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
25 |
26 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
27 |
28 | COCOAPODS: 1.10.1
29 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "logo-20@2x.png",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "logo-20@3x.png",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "logo-29@2x.png",
17 | "idiom" : "iphone",
18 | "scale" : "2x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "logo-29@3x.png",
23 | "idiom" : "iphone",
24 | "scale" : "3x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "logo-40@2x.png",
29 | "idiom" : "iphone",
30 | "scale" : "2x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "filename" : "logo-40@3x.png",
35 | "idiom" : "iphone",
36 | "scale" : "3x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "logo-60@2x.png",
41 | "idiom" : "iphone",
42 | "scale" : "2x",
43 | "size" : "60x60"
44 | },
45 | {
46 | "filename" : "logo-60@3x.png",
47 | "idiom" : "iphone",
48 | "scale" : "3x",
49 | "size" : "60x60"
50 | },
51 | {
52 | "filename" : "logo-20.png",
53 | "idiom" : "ipad",
54 | "scale" : "1x",
55 | "size" : "20x20"
56 | },
57 | {
58 | "filename" : "logo-20@2x.png",
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "20x20"
62 | },
63 | {
64 | "filename" : "logo-29.png",
65 | "idiom" : "ipad",
66 | "scale" : "1x",
67 | "size" : "29x29"
68 | },
69 | {
70 | "filename" : "logo-29@2x.png",
71 | "idiom" : "ipad",
72 | "scale" : "2x",
73 | "size" : "29x29"
74 | },
75 | {
76 | "filename" : "logo-40.png",
77 | "idiom" : "ipad",
78 | "scale" : "1x",
79 | "size" : "40x40"
80 | },
81 | {
82 | "filename" : "logo-40@2x.png",
83 | "idiom" : "ipad",
84 | "scale" : "2x",
85 | "size" : "40x40"
86 | },
87 | {
88 | "filename" : "logo-76.png",
89 | "idiom" : "ipad",
90 | "scale" : "1x",
91 | "size" : "76x76"
92 | },
93 | {
94 | "filename" : "logo-76@2x.png",
95 | "idiom" : "ipad",
96 | "scale" : "2x",
97 | "size" : "76x76"
98 | },
99 | {
100 | "filename" : "logo-83.5@2x.png",
101 | "idiom" : "ipad",
102 | "scale" : "2x",
103 | "size" : "83.5x83.5"
104 | },
105 | {
106 | "filename" : "logo-1024.png",
107 | "idiom" : "ios-marketing",
108 | "scale" : "1x",
109 | "size" : "1024x1024"
110 | }
111 | ],
112 | "info" : {
113 | "author" : "xcode",
114 | "version" : 1
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-1024.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-20.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-29.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-40.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-76.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/AppIcon.appiconset/logo-83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | 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.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | vtime
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 | NSMicrophoneUsageDescription
45 | To play alarm music when app's timer ends
46 | NSAppTransportSecurity
47 |
48 | NSAllowsArbitraryLoads
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/app.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_localizations/flutter_localizations.dart';
9 |
10 | import 'package:flutter_bloc/flutter_bloc.dart';
11 | import 'package:vtime/core/cubits/preference_cubit.dart';
12 | import 'package:vtime/core/cubits/preference_state.dart';
13 | import 'package:vtime/core/services/local_db_service.dart';
14 | import 'package:vtime/view/set_up.dart';
15 |
16 | import 'core/utils/intl.dart';
17 | import 'core/utils/widgets.dart';
18 | import 'view/dashboard.dart';
19 |
20 | class App extends VTStatefulWidget {
21 | App({Key? key}) : super(key: key);
22 |
23 | @override
24 | _AppState createState() => _AppState();
25 | }
26 |
27 | class _AppState extends VTState {
28 | final _dbService = LocalDBService();
29 |
30 | Widget? home;
31 |
32 | @override
33 | void initState() {
34 | super.initState();
35 | home = _dbService.isPreferencesSetted() ? Dashboard() : AppSetup();
36 | }
37 |
38 | @override
39 | Widget build(BuildContext context) {
40 | return BlocProvider(
41 | create: (BuildContext context) => PreferenceCubit()..initApp(),
42 | child: BlocBuilder(
43 | builder: (context, state) {
44 | return MaterialApp(
45 | debugShowCheckedModeBanner: false,
46 | home: home,
47 | theme: state.theme,
48 | locale: Locale(state.langCode ?? vt.intl.locale.languageCode),
49 | localizationsDelegates: [
50 | vt.intl.delegate,
51 | GlobalMaterialLocalizations.delegate,
52 | GlobalWidgetsLocalizations.delegate,
53 | GlobalCupertinoLocalizations.delegate,
54 | ],
55 | supportedLocales: languages.map((language) => Locale(language, '')),
56 | );
57 | },
58 | ),
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/core/cubits/preference_cubit.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_bloc/flutter_bloc.dart';
9 | import 'package:vtime/core/cubits/preference_state.dart';
10 | import 'package:vtime/core/services/local_db_service.dart';
11 | import 'package:vtime/view/widgets/components/themes.dart';
12 |
13 | class PreferenceCubit extends Cubit {
14 | final LocalDBService? localDBService = LocalDBService();
15 |
16 | PreferenceCubit()
17 | : super(
18 | PreferenceState(
19 | theme: null,
20 | themeName: null,
21 | isAnimationsEnabled: true,
22 | selectedAlarmSound: 'Nonimooley',
23 | ),
24 | );
25 |
26 | // It used to initialize preferences of application.
27 | // Just looks at every preference setup and emit them to actual state.
28 | Future initApp() async {
29 | var themeName = await LocalDBService.preferences().get('theme');
30 | var lang = await LocalDBService.preferences().get('lang');
31 | var alarmSound = await LocalDBService.preferences().get('alarmSound');
32 | var value = await LocalDBService.preferences().get('isAnimationsEnabled');
33 |
34 | var themes = {
35 | 'dark': Themes().dark,
36 | 'default': Themes().defaultTheme,
37 | 's/2': Themes().minimalist,
38 | };
39 |
40 | emit(state.copyWith(
41 | theme: themes[themeName] ?? themes['default'],
42 | themeName: themeName,
43 | langCode: lang ?? 'en',
44 | selectedAlarmSound: alarmSound ?? 'Nonimooley',
45 | isAnimationsEnabled: value ?? true,
46 | ));
47 | }
48 |
49 | Future changeTheme(dynamic newTheme) async {
50 | await LocalDBService.preferences().put('theme', newTheme);
51 |
52 | var themes = {
53 | 'dark': Themes().dark,
54 | 's/2': Themes().minimalist,
55 | 'default': Themes().defaultTheme,
56 | };
57 |
58 | emit(state.copyWith(
59 | theme: themes[newTheme] ?? themes['default'],
60 | themeName: newTheme,
61 | ));
62 | }
63 |
64 | Future get currentTheme async {
65 | var themeName = await LocalDBService.preferences().get('theme');
66 |
67 | var themes = {
68 | 'dark': Themes().dark,
69 | 's/2': Themes().minimalist,
70 | 'default': Themes().defaultTheme,
71 | };
72 |
73 | emit(state.copyWith(
74 | theme: themes[themeName] ?? themes['default'],
75 | themeName: themeName,
76 | ));
77 |
78 | return themes[themeName] ?? themes['default'];
79 | }
80 |
81 | // Method to change language and emit new language to cubit state.
82 | Future changeLang(dynamic newLang) async {
83 | await LocalDBService.preferences().put('lang', newLang);
84 |
85 | emit(state.copyWith(langCode: newLang));
86 | }
87 |
88 | Future get currentLang async {
89 | var lang = await LocalDBService.preferences().get('lang');
90 |
91 | emit(state.copyWith(langCode: lang ?? 'en'));
92 |
93 | return lang ?? 'en';
94 | }
95 |
96 | // Method to change alarm sound and emit it to cubit state.
97 | Future changeAlarmSound(String alarmSound) async {
98 | await LocalDBService.preferences().put('alarmSound', alarmSound);
99 |
100 | emit(state.copyWith(selectedAlarmSound: alarmSound));
101 | }
102 |
103 | Future get currentAlarmSound async {
104 | var alarmSound = await LocalDBService.preferences().get('alarmSound');
105 |
106 | emit(state.copyWith(selectedAlarmSound: alarmSound ?? 'Nonimooley'));
107 |
108 | return alarmSound ?? 'Nonimooley';
109 | }
110 |
111 | // Method to make disable/enable animations.
112 | Future changeStateOfAnimations(bool isAnimationsEnabled) async {
113 | await LocalDBService.preferences().put(
114 | 'isAnimationsEnabled',
115 | isAnimationsEnabled,
116 | );
117 |
118 | emit(state.copyWith(isAnimationsEnabled: isAnimationsEnabled));
119 | }
120 |
121 | Future get isAnimationsEnabled async {
122 | var value = await LocalDBService.preferences().get('isAnimationsEnabled');
123 |
124 | emit(state.copyWith(isAnimationsEnabled: value ?? true));
125 |
126 | return value ?? true;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/lib/core/cubits/preference_state.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | class PreferenceState {
10 | final ThemeData? theme;
11 | final String? themeName;
12 | final String? langCode;
13 | final String? selectedAlarmSound;
14 | final bool? isAnimationsEnabled;
15 |
16 | PreferenceState({
17 | this.theme,
18 | this.themeName,
19 | this.langCode,
20 | this.selectedAlarmSound,
21 | this.isAnimationsEnabled,
22 | });
23 |
24 | PreferenceState copyWith({
25 | ThemeData? theme,
26 | String? themeName,
27 | String? langCode,
28 | String? selectedAlarmSound,
29 | bool? isAnimationsEnabled,
30 | }) {
31 | return PreferenceState(
32 | theme: theme ?? this.theme,
33 | themeName: themeName ?? this.themeName,
34 | langCode: langCode ?? this.langCode,
35 | selectedAlarmSound: selectedAlarmSound ?? this.selectedAlarmSound,
36 | isAnimationsEnabled: isAnimationsEnabled ?? this.isAnimationsEnabled,
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/core/model/day.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:vtime/core/model/vt_model.dart';
8 |
9 | class Day extends VTModel {
10 | final String? name;
11 | final String? title;
12 | final int? dayIndex;
13 |
14 | const Day({required this.name, this.title, required this.dayIndex});
15 |
16 | @override
17 | Day copyWith({String? name, String? title, int? dayIndex}) {
18 | return Day(
19 | name: name ?? this.name,
20 | title: title ?? this.title,
21 | dayIndex: dayIndex ?? this.dayIndex,
22 | );
23 | }
24 |
25 | @override
26 | Day.fromJson(Map? json)
27 | : name = json?['name'],
28 | title = json?['title'],
29 | dayIndex = json?['dayIndex'];
30 |
31 | @override
32 | Map toJson() =>
33 | {'name': name, 'title': title, 'dayIndex': dayIndex};
34 | }
35 |
--------------------------------------------------------------------------------
/lib/core/model/task.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:hive/hive.dart';
8 | import 'package:vtime/core/model/vt_model.dart';
9 | import 'package:vtime/view/widgets/utils.dart';
10 |
11 | part 'task.g.dart';
12 |
13 | @HiveType(typeId: 0)
14 | class Task extends HiveObject implements VTModel {
15 | @HiveField(0)
16 | final String? title;
17 |
18 | @HiveField(1)
19 | final String? description;
20 |
21 | @HiveField(2)
22 | final String? uniquekey;
23 |
24 | @HiveField(3)
25 | final int? hours;
26 |
27 | @HiveField(4)
28 | final int? minutes;
29 |
30 | Task({
31 | this.title,
32 | this.description,
33 | this.uniquekey,
34 | this.hours,
35 | this.minutes,
36 | });
37 |
38 | @override
39 | Task copyWith({
40 | String? title,
41 | String? description,
42 | String? uniquekey,
43 | int? hours,
44 | int? minutes,
45 | }) {
46 | return Task(
47 | title: title ?? this.title,
48 | description: description ?? this.description,
49 | uniquekey: uniquekey ?? this.uniquekey,
50 | hours: hours ?? this.hours,
51 | minutes: minutes ?? this.minutes,
52 | );
53 | }
54 |
55 | @override
56 | Task.fromJson(Map? json)
57 | : title = json?['title'],
58 | description = json?['description'],
59 | uniquekey = json?['uniquekey'],
60 | hours = json?['hours'],
61 | minutes = json?['minutes'];
62 |
63 | // Calculates task's total time
64 | double get totalTime => hours! + (minutes! / 100);
65 |
66 | // Makes general duration of task by [hours] and [minutes].
67 | Duration get duration => Duration(hours: hours!, minutes: minutes!);
68 |
69 | // Already built task to fill the day chart.
70 | Task remainingTimeFiller(Duration totalTime) {
71 | return Task(
72 | title: 'Remaining Time {#@!@#!@#8&**%@#%}',
73 | description: '',
74 | uniquekey: '',
75 | hours: totalTime.inHours,
76 | minutes: totalTime.minute,
77 | );
78 | }
79 |
80 | @override
81 | Map toJson() => {
82 | 'title': title,
83 | 'description': description,
84 | 'uniquekey': uniquekey,
85 | 'hours': hours,
86 | 'minutes': minutes,
87 | };
88 | }
89 |
--------------------------------------------------------------------------------
/lib/core/model/task.g.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | part of 'task.dart';
8 |
9 | class TaskAdapter extends TypeAdapter {
10 | @override
11 | final int typeId = 0;
12 |
13 | @override
14 | Task read(BinaryReader reader) {
15 | final numOfFields = reader.readByte();
16 | final fields = {
17 | for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
18 | };
19 | return Task(
20 | title: fields[0] as String?,
21 | description: fields[1] as String?,
22 | uniquekey: fields[2] as String?,
23 | hours: fields[3] as int?,
24 | minutes: fields[4] as int?,
25 | );
26 | }
27 |
28 | @override
29 | void write(BinaryWriter writer, Task obj) {
30 | writer
31 | ..writeByte(5)
32 | ..writeByte(0)
33 | ..write(obj.title)
34 | ..writeByte(1)
35 | ..write(obj.description)
36 | ..writeByte(2)
37 | ..write(obj.uniquekey)
38 | ..writeByte(3)
39 | ..write(obj.hours)
40 | ..writeByte(4)
41 | ..write(obj.minutes);
42 | }
43 |
44 | @override
45 | int get hashCode => typeId.hashCode;
46 |
47 | @override
48 | bool operator ==(Object other) =>
49 | identical(this, other) ||
50 | other is TaskAdapter &&
51 | runtimeType == other.runtimeType &&
52 | typeId == other.typeId;
53 | }
54 |
--------------------------------------------------------------------------------
/lib/core/model/vt_model.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | abstract class VTModel {
8 | // Constructor for setting data.
9 | const VTModel();
10 |
11 | // Set data from jsonDecode.
12 | const VTModel.fromJson(Map json);
13 |
14 | // Get data to json format.
15 | Map toJson();
16 |
17 | // A decorator for concrete model.
18 | dynamic copyWith();
19 | }
20 |
--------------------------------------------------------------------------------
/lib/core/services/local_db_service.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/foundation.dart';
8 | import 'package:hive_flutter/hive_flutter.dart';
9 | import 'package:vtime/core/model/day.dart';
10 | import 'package:vtime/core/model/task.dart';
11 |
12 | /// A utilities class which contains shortcuts for hive db.
13 | class LocalDBService {
14 | static Box preferences() => Hive.box('preferences');
15 |
16 | static Box mondayBox() => Hive.box('monday');
17 | static Box tuesdayBox() => Hive.box('tuesday');
18 | static Box wednesdayBox() => Hive.box('wednesday');
19 | static Box thursdayBox() => Hive.box('thursday');
20 | static Box fridayBox() => Hive.box('friday');
21 | static Box saturdayBox() => Hive.box('saturday');
22 | static Box sundayBox() => Hive.box('sunday');
23 |
24 | // Get right box listenable by day's name.
25 | ValueListenable> rightListenableValue(Day day) {
26 | var values = {
27 | 'Monday': LocalDBService.mondayBox().listenable(),
28 | 'Tuesday': LocalDBService.tuesdayBox().listenable(),
29 | 'Wednesday': LocalDBService.wednesdayBox().listenable(),
30 | 'Thursday': LocalDBService.thursdayBox().listenable(),
31 | 'Friday': LocalDBService.fridayBox().listenable(),
32 | 'Saturday': LocalDBService.saturdayBox().listenable(),
33 | 'Sunday': LocalDBService.sundayBox().listenable(),
34 | };
35 | return values[day.name]!;
36 | }
37 |
38 | // Get right hive box by index.
39 | Box rightBoxByCheckBoxId(int i) {
40 | var values = {
41 | 0: mondayBox(),
42 | 1: tuesdayBox(),
43 | 2: wednesdayBox(),
44 | 3: thursdayBox(),
45 | 4: fridayBox(),
46 | 5: saturdayBox(),
47 | 6: sundayBox(),
48 | };
49 |
50 | return values[i]!;
51 | }
52 |
53 | // Get right task key by checkbox id.
54 | String rightTaskKeyCheckBoxId(int i) {
55 | var values = {
56 | 0: 'Monday',
57 | 1: 'Tuesday',
58 | 2: 'Wednesday',
59 | 3: 'Thursday',
60 | 4: 'Friday',
61 | 5: 'Saturday',
62 | 6: 'Sunday',
63 | };
64 |
65 | return values[i]!;
66 | }
67 |
68 | // Checks if preferences box contains any value, and returns boolean.
69 | bool isPreferencesSetted() => preferences().isNotEmpty;
70 |
71 | // Clears all boxes' (whole weeks') data.
72 | Future clearWeek() async {
73 | for (var i = 0; i < 7; i++) {
74 | await rightBoxByCheckBoxId(i).clear();
75 | }
76 | }
77 |
78 | // Clears concrete day's all tasks.
79 | Future clearDay(int i) async => await rightBoxByCheckBoxId(i).clear();
80 | }
81 |
--------------------------------------------------------------------------------
/lib/core/utils/intl.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'dart:convert';
8 | import 'dart:async' show Future;
9 | import 'package:flutter/material.dart';
10 | import 'package:flutter/services.dart' show rootBundle;
11 |
12 | const languages = ['en', 'tr', 'ru', 'ka'];
13 |
14 | /// Internationalization class
15 | /// which generates language codes by [ISO 639-1].
16 | class Intl {
17 | late Locale locale;
18 |
19 | @visibleForTesting
20 | Map? localizedValues;
21 |
22 | List? supportedLocales;
23 |
24 | IntlDelegate get delegate => const IntlDelegate();
25 |
26 | // Helper method to keep the code in the widgets concise.
27 | // Localizations are accessed using an InheritedWidget "of" syntax.
28 | Intl? of(BuildContext context) => Localizations.of(context, Intl);
29 |
30 | // This variadic method will be called from every widget which,
31 | // needs a localized (formatted) text.
32 | // Example:
33 | /// ```dart
34 | /// "account.hello": "Hello %1, your age is %2"
35 | /// vt.intl.of(context).fmt('account.hello', ['Ismael', '16'])
36 | /// ```
37 | // Output should be: [Hello Ismael, your age is 16].
38 | String fmt(String key, [List? args]) {
39 | if (args == null || args.isEmpty) {
40 | return localizedValues?[key] ?? key;
41 | }
42 |
43 | int _idx;
44 | String formatted = localizedValues![key]!.replaceAllMapped(
45 | RegExp(r'\%[0-9]{1,3}', multiLine: true), (Match match) {
46 | _idx = int.parse(match[0]!.substring(1)) - 1;
47 |
48 | return (args.asMap()[_idx] ?? match[0]).toString();
49 | });
50 |
51 | return formatted;
52 | }
53 |
54 | // This method loads the language JSON file from the "assets/i18n" folder.
55 | // Then decodes getted JSON and returns it as [MapEntry].
56 | Future> load() async {
57 | final jsonString =
58 | await rootBundle.loadString('assets/i18n/${locale.languageCode}.json');
59 | Map jsonMap = json.decode(jsonString);
60 |
61 | // Convert json values to string.
62 | localizedValues = jsonMap.map(
63 | (key, value) => MapEntry(key, value.toString()),
64 | );
65 | return localizedValues!;
66 | }
67 | }
68 |
69 | // LocalizationsDelegate is a factory for a set of localized resources.
70 | // In this case, the localized strings will be gotten in an Intl object.
71 | @immutable
72 | @visibleForTesting
73 | class IntlDelegate extends LocalizationsDelegate {
74 | // This delegate instance won't change. (it doesn't even have fields!).
75 | // It can provide a constant constructor.
76 | const IntlDelegate();
77 |
78 | @override
79 | bool isSupported(Locale locale) => languages.contains(locale.languageCode);
80 |
81 | @override
82 | Future load(Locale locale) async {
83 | final Intl intl = Intl();
84 | intl.locale = locale;
85 | await intl.load();
86 | return intl;
87 | }
88 |
89 | @override
90 | bool shouldReload(IntlDelegate old) => false;
91 | }
92 |
--------------------------------------------------------------------------------
/lib/core/utils/logger.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/foundation.dart';
8 | import 'package:logger/logger.dart';
9 |
10 | class Log {
11 | @visibleForTesting
12 | static final Logger log = Logger(
13 | level: getLevel(),
14 | output: ConsoleOutput(),
15 | printer: PrettyPrinter(
16 | printEmojis: false,
17 | ),
18 | );
19 |
20 | @visibleForTesting
21 | static final Logger logNoStack = Logger(
22 | level: getLevel(),
23 | output: ConsoleOutput(),
24 | printer: PrettyPrinter(
25 | printTime: false,
26 | printEmojis: false,
27 | methodCount: 0,
28 | ),
29 | );
30 |
31 | static String? level;
32 |
33 | /// Log a message at level `verbose`.
34 | static Function get v => logNoStack.v;
35 |
36 | /// Log a message at level `debug`.
37 | static Function get d => logNoStack.d;
38 |
39 | /// Log a message at level `info`.
40 | static Function get i => logNoStack.i;
41 |
42 | /// Log a message at level `warning` with stacktrace.
43 | static Function get w => log.w;
44 |
45 | /// Log a message at level `error` with stacktrace.
46 | static Function get e => log.e;
47 |
48 | /// Log a message at level `critical` with stacktrace.
49 | static Function get c => log.wtf;
50 |
51 | @visibleForTesting
52 | static Level getLevel() {
53 | switch (level) {
54 | case 'verbose':
55 | return Level.verbose;
56 | case 'debug':
57 | return Level.debug;
58 | case 'info':
59 | return Level.info;
60 | case 'warning':
61 | return Level.warning;
62 | case 'error':
63 | return Level.error;
64 | case 'critical':
65 | return Level.wtf;
66 | default:
67 | return Level.verbose;
68 | }
69 | }
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/lib/core/utils/utils.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:vtime/core/model/day.dart';
8 |
9 | import '../vt.dart';
10 |
11 | // Standart week days list by [Day] class.
12 | List weekDays(VT vt, context) {
13 | return [
14 | Day(
15 | title: vt.intl.of(context)?.fmt('monday') ?? 'M',
16 | name: 'Monday',
17 | dayIndex: 0,
18 | ),
19 | Day(
20 | title: vt.intl.of(context)?.fmt('tuesday') ?? 'T',
21 | name: 'Tuesday',
22 | dayIndex: 1,
23 | ),
24 | Day(
25 | title: vt.intl.of(context)?.fmt('wednesday') ?? 'W',
26 | name: 'Wednesday',
27 | dayIndex: 2,
28 | ),
29 | Day(
30 | title: vt.intl.of(context)?.fmt('thursday') ?? 'T',
31 | name: 'Thursday',
32 | dayIndex: 3,
33 | ),
34 | Day(
35 | title: vt.intl.of(context)?.fmt('friday') ?? 'F',
36 | name: 'Friday',
37 | dayIndex: 4,
38 | ),
39 | Day(
40 | title: vt.intl.of(context)?.fmt('saturday') ?? 'S',
41 | name: 'Saturday',
42 | dayIndex: 5,
43 | ),
44 | Day(
45 | title: vt.intl.of(context)?.fmt('sunday') ?? 'S',
46 | name: 'Sunday',
47 | dayIndex: 6,
48 | ),
49 | ];
50 | }
51 |
--------------------------------------------------------------------------------
/lib/core/utils/widgets.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../vt.dart';
10 |
11 | abstract class VTStatelessWidget extends StatelessWidget {
12 | VTStatelessWidget({Key? key}) : super(key: key);
13 | final vt = VT();
14 | }
15 |
16 | abstract class VTStatefulWidget extends StatefulWidget {
17 | VTStatefulWidget({Key? key}) : super(key: key);
18 | final vt = VT();
19 | }
20 |
21 | abstract class VTState extends State {
22 | final vt = VT();
23 | }
24 |
--------------------------------------------------------------------------------
/lib/core/vt.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:vtime/core/services/local_db_service.dart';
8 | import 'package:vtime/core/utils/intl.dart';
9 |
10 | import 'utils/logger.dart';
11 |
12 | class VT {
13 | static final VT _singleton = VT._internal();
14 |
15 | final Map instances = {};
16 |
17 | factory VT() => _singleton;
18 |
19 | VT._internal() {
20 | Log.v('${runtimeType.toString()} instance created');
21 | }
22 |
23 | set intl(Intl intl) => instances['intl'] = intl;
24 | Intl get intl => instances['intl'];
25 |
26 | set localDbService(LocalDBService localDbService) =>
27 | instances['localDbService'] = localDbService;
28 | LocalDBService get localDbService => instances['localDbService'];
29 | }
30 |
--------------------------------------------------------------------------------
/lib/generated_plugin_registrant.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | //
8 | // Generated file. Do not edit.
9 | //
10 |
11 | // ignore_for_file: directives_ordering
12 | // ignore_for_file: lines_longer_than_80_chars
13 |
14 | import 'package:audioplayers/web/audioplayers_web.dart';
15 |
16 | import 'package:flutter_web_plugins/flutter_web_plugins.dart';
17 |
18 | // ignore: public_member_api_docs
19 | void registerPlugins(Registrar registrar) {
20 | AudioplayersPlugin.registerWith(registrar);
21 | registrar.registerMessageHandler();
22 | }
23 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hive_flutter/hive_flutter.dart';
9 | import 'package:vtime/core/services/local_db_service.dart';
10 | import 'package:vtime/core/utils/intl.dart';
11 |
12 | import 'app.dart';
13 | import 'core/model/task.dart';
14 | import 'core/vt.dart';
15 |
16 | void main() async {
17 | await Hive.initFlutter();
18 | Hive.registerAdapter(TaskAdapter());
19 |
20 | await Hive.openBox('preferences');
21 |
22 | await Hive.openBox('monday');
23 | await Hive.openBox('tuesday');
24 | await Hive.openBox('wednesday');
25 | await Hive.openBox('thursday');
26 | await Hive.openBox('friday');
27 | await Hive.openBox('saturday');
28 | await Hive.openBox('sunday');
29 |
30 | final VT vt = VT();
31 |
32 | vt.intl = Intl();
33 | vt.localDbService = LocalDBService();
34 |
35 | vt.intl.locale = const Locale('en');
36 | vt.intl.supportedLocales = languages;
37 |
38 | runApp(App());
39 | }
40 |
--------------------------------------------------------------------------------
/lib/view/dashboard.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:flutter/foundation.dart';
9 | import 'package:flutter/material.dart';
10 | import 'package:vtime/core/model/day.dart';
11 | import 'package:vtime/core/model/task.dart';
12 | import 'package:vtime/core/services/local_db_service.dart';
13 | import 'package:vtime/core/utils/utils.dart';
14 | import 'package:vtime/core/utils/widgets.dart';
15 | import 'package:hive_flutter/hive_flutter.dart';
16 |
17 | import 'day_view.dart';
18 | import 'create.dart';
19 | import 'settings.dart';
20 | import 'widgets/mini_day_card.dart';
21 | import 'widgets/components/appbars.dart';
22 | import 'widgets/day_chart.dart';
23 | import 'widgets/utils.dart';
24 |
25 | class Dashboard extends VTStatefulWidget {
26 | Dashboard({Key? key}) : super(key: key);
27 |
28 | @override
29 | _DashboardState createState() => _DashboardState();
30 | }
31 |
32 | class _DashboardState extends VTState {
33 | final titleTextController = TextEditingController();
34 | final localDbService = LocalDBService();
35 |
36 | late Day today = weekDays(vt, context)[0];
37 | ValueListenable>? todaysBox;
38 |
39 | // Just contains cases appertitate to week days.
40 | // And listens now(WeekDay) and generates right function calling.
41 | void _refreshContent() {
42 | var cases = {
43 | DateTime.monday: () {
44 | today = weekDays(vt, context)[0];
45 | todaysBox = localDbService.rightListenableValue(
46 | weekDays(vt, context)[0],
47 | );
48 | },
49 | DateTime.tuesday: () {
50 | today = weekDays(vt, context)[1];
51 | todaysBox = localDbService.rightListenableValue(
52 | weekDays(vt, context)[1],
53 | );
54 | },
55 | DateTime.wednesday: () {
56 | today = weekDays(vt, context)[2];
57 | todaysBox = localDbService.rightListenableValue(
58 | weekDays(vt, context)[2],
59 | );
60 | },
61 | DateTime.thursday: () {
62 | today = weekDays(vt, context)[3];
63 | todaysBox = localDbService.rightListenableValue(
64 | weekDays(vt, context)[3],
65 | );
66 | },
67 | DateTime.friday: () {
68 | today = weekDays(vt, context)[4];
69 | todaysBox = localDbService.rightListenableValue(
70 | weekDays(vt, context)[4],
71 | );
72 | },
73 | DateTime.saturday: () {
74 | today = weekDays(vt, context)[5];
75 | todaysBox = localDbService.rightListenableValue(
76 | weekDays(vt, context)[5],
77 | );
78 | },
79 | DateTime.sunday: () {
80 | today = weekDays(vt, context)[6];
81 | todaysBox = localDbService.rightListenableValue(
82 | weekDays(vt, context)[6],
83 | );
84 | },
85 | };
86 |
87 | return cases[DateTime.now().weekday]!.call();
88 | }
89 |
90 | @override
91 | Widget build(BuildContext context) {
92 | _refreshContent();
93 | return Scaffold(
94 | appBar: TransparentAppBar(
95 | disableLeading: true,
96 | action: Padding(
97 | padding: const EdgeInsets.only(right: 15),
98 | child: SettingsPopUpMenu(todaysBox: todaysBox!),
99 | ),
100 | titleWidget: GestureDetector(
101 | onTap: () => openNewDay(0, context, day: today, todaysBox: todaysBox),
102 | child: Text(
103 | vt.intl.of(context)!.fmt('today'),
104 | style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 25),
105 | ),
106 | ),
107 | ),
108 | body: SingleChildScrollView(
109 | padding: const EdgeInsets.symmetric(vertical: 30),
110 | child: Column(
111 | mainAxisAlignment: MainAxisAlignment.center,
112 | children: [
113 | ValueListenableBuilder>(
114 | valueListenable: todaysBox!,
115 | builder: (context, box, _) {
116 | final tasks = box.values.toList().cast();
117 | return DayChart(tasks: tasks, isTooltipBehaviorEnabled: true);
118 | },
119 | ),
120 | const SizedBox(height: 30),
121 | ViewUtils.divider,
122 | const SizedBox(height: 50),
123 | WeekView(weeks: weekDays(vt, context)),
124 | ],
125 | ),
126 | ),
127 | );
128 | }
129 | }
130 |
131 | // Method which navigates to DayView with given parameters.
132 | void openNewDay(
133 | int i,
134 | BuildContext context, {
135 | List? weeks,
136 | Day? day,
137 | dynamic todaysBox,
138 | }) {
139 | Navigator.push(
140 | context,
141 | MaterialPageRoute(
142 | builder: (context) => DayView(
143 | day: weeks?[i] ?? day,
144 | dayBox: (weeks != null)
145 | ? LocalDBService().rightListenableValue(weeks[i])
146 | : todaysBox,
147 | ),
148 | ),
149 | );
150 | }
151 |
152 | // A widget which has mini day charts of all week.
153 | class WeekView extends VTStatelessWidget {
154 | final List? weeks;
155 | WeekView({Key? key, this.weeks}) : super(key: key);
156 |
157 | @override
158 | Widget build(BuildContext context) {
159 | return Center(
160 | child: Column(
161 | children: [
162 | Wrap(
163 | children: [
164 | for (var i = 0; i < 4; i++)
165 | MiniDayChart(
166 | title: ViewUtils().rightDayNameGenerator(i, vt, context),
167 | onTap: () => openNewDay(i, context, weeks: weeks),
168 | todaysBox: LocalDBService().rightListenableValue(weeks![i]),
169 | ),
170 | ],
171 | ),
172 | Wrap(
173 | children: [
174 | for (var i = 4; i < 7; i++)
175 | MiniDayChart(
176 | todaysBox: LocalDBService().rightListenableValue(weeks![i]),
177 | title: ViewUtils().rightDayNameGenerator(i, vt, context),
178 | onTap: () => openNewDay(i, context, weeks: weeks),
179 | ),
180 | ],
181 | ),
182 | ],
183 | ),
184 | );
185 | }
186 | }
187 |
188 | class SettingsPopUpMenu extends VTStatelessWidget {
189 | final ValueListenable> todaysBox;
190 | SettingsPopUpMenu({Key? key, required this.todaysBox}) : super(key: key);
191 |
192 | final localDbService = LocalDBService();
193 | final viewUtils = ViewUtils();
194 |
195 | @override
196 | Widget build(BuildContext context) {
197 | return PopupMenuButton(
198 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
199 | child: const Icon(Icons.more_horiz),
200 | onSelected: (val) => onPopUpItemSelected(context, val),
201 | itemBuilder: (_) => [
202 | PopupMenuItem(
203 | value: 0,
204 | child: Column(
205 | children: [
206 | const SizedBox(height: 15),
207 | Row(
208 | mainAxisAlignment: MainAxisAlignment.center,
209 | children: [
210 | const Icon(Icons.settings),
211 | const SizedBox(width: 10),
212 | Text(vt.intl.of(context)!.fmt('prefs.settings')),
213 | ],
214 | ),
215 | const SizedBox(height: 8),
216 | const Divider(),
217 | ],
218 | ),
219 | ),
220 | PopupMenuItem(
221 | value: 1,
222 | child: Row(
223 | children: [
224 | const Icon(CupertinoIcons.clear_circled_solid, color: Colors.red),
225 | const SizedBox(width: 10),
226 | Text(vt.intl.of(context)!.fmt('act.clearWeek')),
227 | ],
228 | ),
229 | ),
230 | PopupMenuItem(
231 | value: 2,
232 | child: Row(
233 | children: [
234 | const Icon(CupertinoIcons.add_circled_solid),
235 | const SizedBox(width: 10),
236 | Text(vt.intl.of(context)!.fmt('act.addTask')),
237 | ],
238 | ),
239 | ),
240 | ],
241 | );
242 | }
243 |
244 | void onPopUpItemSelected(BuildContext context, dynamic seleted) {
245 | var methods = {
246 | 0: () => Navigator.push(
247 | context,
248 | MaterialPageRoute(builder: (context) => Settings()),
249 | ),
250 | 1: () => viewUtils.alert(
251 | context,
252 | vt,
253 | title: vt.intl.of(context)!.fmt('clear.week.title'),
254 | onAct: () {
255 | localDbService.clearWeek();
256 | Navigator.pop(context);
257 | },
258 | ),
259 | 2: () => Navigator.push(
260 | context,
261 | MaterialPageRoute(
262 | builder: (context) => CreateTaskPage(todaysBox: todaysBox),
263 | ),
264 | ),
265 | };
266 |
267 | methods[seleted]!.call();
268 | }
269 | }
270 |
--------------------------------------------------------------------------------
/lib/view/day_view.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter/foundation.dart';
10 | import 'package:hive/hive.dart';
11 | import 'package:vtime/core/model/day.dart';
12 | import 'package:vtime/core/model/task.dart';
13 | import 'package:vtime/core/services/local_db_service.dart';
14 | import 'package:vtime/core/utils/widgets.dart';
15 |
16 | import 'create.dart';
17 | import 'widgets/day_chart.dart';
18 | import 'widgets/task_card.dart';
19 | import 'widgets/components/appbars.dart';
20 | import 'widgets/utils.dart';
21 |
22 | class DayView extends VTStatefulWidget {
23 | final Day day;
24 | final ValueListenable>? dayBox;
25 |
26 | DayView({
27 | Key? key,
28 | required this.day,
29 | required this.dayBox,
30 | }) : super(key: key);
31 |
32 | @override
33 | _DayViewState createState() => _DayViewState();
34 | }
35 |
36 | class _DayViewState extends VTState {
37 | List tasks = [];
38 |
39 | /// Removes element from [oldIndex], and inserts removed element to [newIndex].
40 | /// After the local list reordering, it clears old database elements and fills it by new ones.
41 | void onReorder(int oldIndex, int newIndex, Box box) {
42 | if (oldIndex < newIndex) newIndex -= 1;
43 |
44 | var item = tasks.removeAt(oldIndex);
45 | tasks.insert(newIndex, item);
46 |
47 | setState(() {});
48 |
49 | for (var i = 0; i < tasks.length; i++) {
50 | box.delete(tasks[i].key);
51 |
52 | if (tasks[i].title != remainingTimeFillerTaskCode) box.add(tasks[i]);
53 | }
54 | }
55 |
56 | @override
57 | Widget build(BuildContext context) {
58 | return Scaffold(
59 | appBar: TransparentAppBar(
60 | onLeadingTap: () => Navigator.pop(context),
61 | titleWidget: Text(widget.day.title ?? '404'),
62 | action: Padding(
63 | padding: const EdgeInsets.only(right: 15),
64 | child: SettingsPopUpMenu(todaysBox: widget.dayBox!, day: widget.day),
65 | ),
66 | ),
67 | body: ValueListenableBuilder>(
68 | valueListenable: widget.dayBox!,
69 | builder: (contxt, box, _) {
70 | tasks = box.values.toList().cast();
71 |
72 | return SingleChildScrollView(
73 | child: Column(
74 | children: [
75 | DayChart(tasks: tasks, isTooltipBehaviorEnabled: true),
76 | const SizedBox(height: 15),
77 | const Divider(),
78 | const SizedBox(height: 15),
79 | ReorderableListView(
80 | shrinkWrap: true,
81 | physics: const NeverScrollableScrollPhysics(),
82 | onReorder: (oldI, newI) => onReorder(oldI, newI, box),
83 | children: [
84 | for (var i = 0; i < tasks.length; i++)
85 | TaskCard(
86 | task: tasks[i],
87 | dayBox: box,
88 | onDismissed: () => box.delete(tasks[i].key),
89 | key: UniqueKey(),
90 | ),
91 | ],
92 | ),
93 | ],
94 | ),
95 | );
96 | },
97 | ),
98 | );
99 | }
100 | }
101 |
102 | class SettingsPopUpMenu extends VTStatelessWidget {
103 | final Day? day;
104 | final ValueListenable> todaysBox;
105 |
106 | SettingsPopUpMenu({
107 | Key? key,
108 | required this.todaysBox,
109 | this.day,
110 | }) : super(key: key);
111 |
112 | final localDbService = LocalDBService();
113 | final viewUtils = ViewUtils();
114 |
115 | @override
116 | Widget build(BuildContext context) {
117 | return PopupMenuButton(
118 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
119 | child: const Icon(Icons.more_horiz),
120 | onSelected: (val) => onPopUpItemSelected(context, val),
121 | itemBuilder: (_) => [
122 | PopupMenuItem(
123 | value: 0,
124 | child: Row(
125 | children: [
126 | const Icon(CupertinoIcons.clear_circled_solid, color: Colors.red),
127 | const SizedBox(width: 10),
128 | Text(vt.intl.of(context)!.fmt('act.clearDay')),
129 | ],
130 | ),
131 | ),
132 | PopupMenuItem(
133 | value: 1,
134 | child: Row(
135 | children: [
136 | const Icon(CupertinoIcons.add_circled_solid),
137 | const SizedBox(width: 10),
138 | Text(vt.intl.of(context)!.fmt('act.addTask')),
139 | ],
140 | ),
141 | ),
142 | ],
143 | );
144 | }
145 |
146 | void onPopUpItemSelected(BuildContext context, dynamic seleted) {
147 | var methods = {
148 | 0: () => viewUtils.alert(
149 | context,
150 | vt,
151 | title: vt.intl.of(context)!.fmt('clear.day.title'),
152 | onAct: () {
153 | localDbService.clearDay(day!.dayIndex!);
154 | Navigator.pop(context);
155 | },
156 | ),
157 | 1: () => Navigator.push(
158 | context,
159 | MaterialPageRoute(
160 | builder: (context) => CreateTaskPage(
161 | todaysBox: todaysBox,
162 | selectedDay: day,
163 | ),
164 | ),
165 | ),
166 | };
167 |
168 | methods[seleted]!.call();
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/lib/view/edit.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:hive/hive.dart';
10 | import 'package:vtime/core/model/task.dart';
11 | import 'package:vtime/core/services/local_db_service.dart';
12 | import 'package:vtime/core/utils/widgets.dart';
13 |
14 | import 'widgets/components/appbars.dart';
15 | import 'widgets/components/buttons.dart';
16 | import 'widgets/utils.dart';
17 |
18 | class EditPage extends VTStatefulWidget {
19 | final Task task;
20 | final Box dayBox;
21 |
22 | EditPage({
23 | Key? key,
24 | required this.task,
25 | required this.dayBox,
26 | }) : super(key: key);
27 |
28 | @override
29 | _EditPageState createState() => _EditPageState();
30 | }
31 |
32 | class _EditPageState extends VTState {
33 | final localDbService = LocalDBService();
34 | final viewUtils = ViewUtils();
35 |
36 | final formKey = GlobalKey();
37 | final titleTextController = TextEditingController();
38 | final desTextController = TextEditingController();
39 |
40 | Duration durationOfTask = Duration.zero;
41 |
42 | @override
43 | void initState() {
44 | durationOfTask = widget.task.duration;
45 | titleTextController.text = widget.task.title!;
46 | desTextController.text = widget.task.description!;
47 | super.initState();
48 | }
49 |
50 | @override
51 | Widget build(BuildContext context) {
52 | return Scaffold(
53 | appBar: appBar(context),
54 | bottomNavigationBar: SaveButton(
55 | title: vt.intl.of(context)!.fmt('act.save'),
56 | onTap: saveTask,
57 | ),
58 | body: SingleChildScrollView(
59 | padding: const EdgeInsets.symmetric(vertical: 80, horizontal: 15),
60 | child: Form(
61 | key: formKey,
62 | child: Column(
63 | children: [
64 | TextFormField(
65 | controller: titleTextController,
66 | maxLines: 2,
67 | decoration: ViewUtils().nonBorderInputDecoration(
68 | hint: vt.intl.of(context)!.fmt('task.title.hint'),
69 | ),
70 | validator: (v) {
71 | if (v!.isNotEmpty) return null;
72 | return vt.intl
73 | .of(context)!
74 | .fmt('error.title_field_validation');
75 | },
76 | ),
77 | const SizedBox(width: 15),
78 | const Divider(),
79 | const SizedBox(width: 15),
80 | TextFormField(
81 | controller: desTextController,
82 | minLines: 1,
83 | maxLines: 15,
84 | decoration: ViewUtils().nonBorderInputDecoration(
85 | hint: vt.intl.of(context)!.fmt('task.desc.hint'),
86 | ),
87 | ),
88 | ],
89 | ),
90 | ),
91 | ),
92 | );
93 | }
94 |
95 | TransparentAppBar appBar(BuildContext context) {
96 | return TransparentAppBar(
97 | titleWidget: GestureDetector(
98 | onTap: () => showTimePicker(),
99 | child: Wrap(
100 | crossAxisAlignment: WrapCrossAlignment.center,
101 | children: [
102 | const Icon(CupertinoIcons.clock_fill),
103 | const SizedBox(width: 10),
104 | Text(
105 | durationOfTask.toHumanLang(vt, context),
106 | style: const TextStyle(fontSize: 15),
107 | )
108 | ],
109 | ),
110 | ),
111 | onLeadingTap: () {
112 | ScaffoldMessenger.of(context).removeCurrentSnackBar();
113 | Navigator.pop(context);
114 | },
115 | );
116 | }
117 |
118 | Future showTimePicker() async {
119 | showModalBottomSheet(
120 | context: context,
121 | builder: (builder) {
122 | return SizedBox(
123 | height: MediaQuery.of(context).copyWith().size.height / 3,
124 | child: SizedBox.expand(
125 | child: CupertinoTimerPicker(
126 | mode: CupertinoTimerPickerMode.hm,
127 | minuteInterval: 1,
128 | secondInterval: 1,
129 | initialTimerDuration: durationOfTask,
130 | onTimerDurationChanged: (newTime) {
131 | setState(() => durationOfTask = newTime);
132 | },
133 | ),
134 | ),
135 | );
136 | },
137 | );
138 | }
139 |
140 | saveTask() async {
141 | if (!formKey.currentState!.validate()) return;
142 |
143 | if (durationOfTask == Duration.zero) {
144 | ScaffoldMessenger.of(context).showSnackBar(
145 | SnackBar(
146 | backgroundColor: Colors.red,
147 | content: Text(vt.intl.of(context)!.fmt('error.not_found_duration')),
148 | ),
149 | );
150 | return;
151 | }
152 |
153 | Task editedTask = widget.task.copyWith(
154 | title: titleTextController.text,
155 | description: desTextController.text,
156 | hours: durationOfTask.inHours,
157 | minutes: durationOfTask.minute,
158 | );
159 |
160 | List tasksOfSelectedDay = widget.dayBox.values.toList();
161 | tasksOfSelectedDay.removeWhere((el) => el.title == widget.task.title);
162 | Duration remainingTime = ViewUtils.fullDay -
163 | viewUtils.calculateTotalDuration(tasksOfSelectedDay);
164 |
165 | if (editedTask.duration > remainingTime) {
166 | ScaffoldMessenger.of(context).showSnackBar(
167 | SnackBar(
168 | backgroundColor: Colors.red,
169 | content: Text(
170 | vt.intl
171 | .of(context)!
172 | .fmt('error.selected_duration_more_than_remaining'),
173 | ),
174 | ),
175 | );
176 | return;
177 | }
178 |
179 | await widget.dayBox.put(widget.task.key, editedTask);
180 | ScaffoldMessenger.of(context).removeCurrentSnackBar();
181 | Navigator.pop(context);
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/lib/view/live-task/dashboard.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'dart:async';
8 |
9 | import 'package:audioplayers/audioplayers.dart';
10 | import 'package:flutter/material.dart';
11 | import 'package:flutter_bloc/flutter_bloc.dart';
12 | import 'package:hive_flutter/hive_flutter.dart';
13 | import 'package:vtime/core/cubits/preference_cubit.dart';
14 | import 'package:vtime/core/model/task.dart';
15 | import 'package:vtime/core/utils/widgets.dart';
16 | import 'package:vtime/view/dashboard.dart';
17 | import 'package:vtime/view/widgets/components/appbars.dart';
18 | import 'package:vtime/view/widgets/components/custom_switchers.dart';
19 | import 'package:vtime/view/widgets/live-task/clock_count.dart';
20 | import 'package:vtime/view/widgets/components/themes.dart';
21 | import 'package:vtime/view/widgets/utils.dart';
22 |
23 | class LiveTaskDashboard extends VTStatefulWidget {
24 | final Task? task;
25 | final Box? dayBox;
26 | LiveTaskDashboard({Key? key, this.task, this.dayBox}) : super(key: key);
27 |
28 | @override
29 | LiveTaskDashboardState createState() => LiveTaskDashboardState();
30 | }
31 |
32 | class LiveTaskDashboardState extends VTState {
33 | final viewUtils = ViewUtils();
34 | late bool isAnimationsEnabled;
35 |
36 | static const oneSecond = Duration(seconds: 1);
37 | Timer? timer;
38 | Duration? duration;
39 | String time = '';
40 | Stopwatch watch = Stopwatch();
41 |
42 | bool removeTaskAfterCompletation = false;
43 | AudioCache player = AudioCache(prefix: 'assets/alarms/');
44 |
45 | @override
46 | void initState() {
47 | super.initState();
48 | duration = Duration(
49 | hours: widget.task!.hours!,
50 | minutes: widget.task!.minutes!,
51 | );
52 | time = duration!.toHMS;
53 | isAnimationsEnabled =
54 | BlocProvider.of(context).state.isAnimationsEnabled!;
55 | }
56 |
57 | @override
58 | void dispose() {
59 | if (timer != null) timer!.cancel();
60 | super.dispose();
61 | }
62 |
63 | void startTimer() {
64 | watch.start();
65 | timer = Timer.periodic(oneSecond, (_) {
66 | setState(() {
67 | duration = duration! - oneSecond;
68 | time = duration!.toHMS;
69 | });
70 | if (time == '00:00') onTaskEnd();
71 | });
72 | }
73 |
74 | void stopTimer() {
75 | watch.stop();
76 | timer!.cancel();
77 | setState(() {
78 | duration = Duration(
79 | hours: widget.task!.hours!,
80 | minutes: widget.task!.minutes!,
81 | );
82 | time = duration!.toHMS;
83 | });
84 | }
85 |
86 | void onTaskEnd() async {
87 | stopTimer();
88 | setState(() => time = 'dn');
89 |
90 | // Get's setted alarm sound and plays it.
91 | var val = await BlocProvider.of(context).currentAlarmSound;
92 | player.play('$val.mp3');
93 |
94 | if (removeTaskAfterCompletation) {
95 | await Future.delayed(const Duration(seconds: 2));
96 | widget.dayBox!.delete(widget.task!.key);
97 | Navigator.pushAndRemoveUntil(
98 | context,
99 | MaterialPageRoute(builder: (context) => Dashboard()),
100 | (route) => false,
101 | );
102 | }
103 | }
104 |
105 | @override
106 | Widget build(BuildContext context) {
107 | return WillPopScope(
108 | onWillPop: () async {
109 | navigateBack();
110 | return true;
111 | },
112 | child: Scaffold(
113 | bottomNavigationBar: startButton(),
114 | appBar: TransparentAppBar(onLeadingTap: navigateBack),
115 | body: SingleChildScrollView(
116 | padding: const EdgeInsets.all(10),
117 | child: Center(
118 | child: Column(
119 | mainAxisAlignment: MainAxisAlignment.center,
120 | children: [
121 | const SizedBox(height: 30),
122 | ClockCount(
123 | time: time,
124 | disabled: !watch.isRunning,
125 | isAnimationDisabled: !isAnimationsEnabled,
126 | ),
127 | const SizedBox(height: 40),
128 | ViewUtils.divider,
129 | const SizedBox(height: 20),
130 | SwitcherTile(
131 | title: vt.intl
132 | .of(context)!
133 | .fmt('live_work.removeTaskAfterCompleting'),
134 | switcherValue: removeTaskAfterCompletation,
135 | onChanged: (v) =>
136 | setState(() => removeTaskAfterCompletation = v),
137 | ),
138 | const SizedBox(height: 40),
139 | _SelectedTask(task: widget.task ?? Task()),
140 | ],
141 | ),
142 | ),
143 | ),
144 | ),
145 | );
146 | }
147 |
148 | Widget startButton() {
149 | return Padding(
150 | padding: const EdgeInsets.symmetric(vertical: 30),
151 | child: FractionallySizedBox(
152 | widthFactor: .8,
153 | child: ElevatedButton(
154 | style: ViewUtils().pomodoroButtonStyle(context),
155 | onPressed: watch.isRunning ? stopTimer : startTimer,
156 | child: Text(
157 | watch.isRunning
158 | ? vt.intl.of(context)!.fmt('act.stop')
159 | : vt.intl.of(context)!.fmt('act.start'),
160 | style: TextStyle(color: ViewUtils().pomodoroOrange(context)),
161 | ),
162 | ),
163 | ),
164 | );
165 | }
166 |
167 | void navigateBack() {
168 | if (watch.isRunning) {
169 | viewUtils.alert(
170 | context,
171 | vt,
172 | title: vt.intl.of(context)!.fmt('live_work.runtimeLogoutRequestError'),
173 | onAct: navigateToDashboard,
174 | buttons: [
175 | TextButton(
176 | style: simpleButtonStyle(ViewUtils().pomodoroOrange(context)),
177 | onPressed: leaveItHalf,
178 | child: Text(
179 | vt.intl.of(context)!.fmt('live_work.leaveItHalf'),
180 | style: TextStyle(color: ViewUtils().pomodoroOrange(context)),
181 | ),
182 | ),
183 | ],
184 | );
185 | return;
186 | }
187 |
188 | ScaffoldMessenger.of(context).removeCurrentSnackBar();
189 | navigateToDashboard();
190 | }
191 |
192 | void navigateToDashboard() {
193 | Navigator.pushAndRemoveUntil(
194 | context,
195 | MaterialPageRoute(builder: (context) => Dashboard()),
196 | (route) => false,
197 | );
198 | }
199 |
200 | // Changes selected task's duration by current duration.
201 | // And saves modified task to database.
202 | void leaveItHalf() {
203 | Task currentTask = widget.task!.copyWith(
204 | hours: duration!.inHours,
205 | minutes: duration!.inMinutes,
206 | );
207 | if (duration!.inMinutes < 2) {
208 | widget.dayBox!.delete(widget.task!.key);
209 | } else {
210 | widget.dayBox!.put(widget.task!.key, currentTask);
211 | }
212 | navigateToDashboard();
213 | }
214 | }
215 |
216 | class _SelectedTask extends VTStatelessWidget {
217 | final Task task;
218 | _SelectedTask({Key? key, required this.task}) : super(key: key);
219 |
220 | @override
221 | Widget build(BuildContext context) {
222 | var padding = task.title!.length.toDouble() / 7;
223 |
224 | return Padding(
225 | padding: const EdgeInsets.all(8.0),
226 | child: Column(
227 | children: [
228 | Align(
229 | alignment: Alignment.centerLeft,
230 | child: Text(
231 | vt.intl.of(context)!.fmt('live_work.selected_task') + ':',
232 | style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
233 | ),
234 | ),
235 | const SizedBox(height: 10),
236 | Container(
237 | width: MediaQuery.of(context).size.width - 20,
238 | padding: EdgeInsets.all(padding),
239 | decoration: BoxDecoration(
240 | color: context
241 | .read()
242 | .state
243 | .theme!
244 | .scaffoldBackgroundColor,
245 | border: Border.all(
246 | width: .6,
247 | color: ViewUtils().pomodoroOrange(context),
248 | ),
249 | borderRadius: BorderRadius.circular(20),
250 | boxShadow: [
251 | BoxShadow(
252 | spreadRadius: 1,
253 | offset: const Offset(0, 10),
254 | blurRadius: 15,
255 | color: ViewUtils().pomodoroOrange(context).withOpacity(.2),
256 | )
257 | ],
258 | ),
259 | child: ListTile(
260 | title: Text(task.title!),
261 | subtitle: Text(ViewUtils().generateSubtitle(context, task, vt)),
262 | ),
263 | )
264 | ],
265 | ),
266 | );
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/lib/view/set_up.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_bloc/flutter_bloc.dart';
10 | import 'package:vtime/core/cubits/preference_cubit.dart';
11 | import 'package:vtime/core/utils/widgets.dart';
12 | import 'package:vtime/view/dashboard.dart';
13 |
14 | class AppSetup extends VTStatefulWidget {
15 | AppSetup({Key? key}) : super(key: key);
16 |
17 | @override
18 | _AppSetupState createState() => _AppSetupState();
19 | }
20 |
21 | class _AppSetupState extends VTState {
22 | final langSegments = const {
23 | 0: Text('English'),
24 | 1: Text('Türkçe'),
25 | 2: Text('Русский'),
26 | 3: Text('ქართული')
27 | };
28 |
29 | int themeSegmentedValue = 0;
30 | int langSegmentedValue = 0;
31 |
32 | @override
33 | Widget build(BuildContext context) {
34 | var themeSegments = {
35 | 0: Text(vt.intl.of(context)!.fmt('prefs.appearance.light')),
36 | 1: Text(vt.intl.of(context)!.fmt('prefs.appearance.dark')),
37 | 2: const Text('S/2')
38 | };
39 |
40 | return Scaffold(
41 | appBar: AppBar(title: Text(vt.intl.of(context)!.fmt('app.setup'))),
42 | floatingActionButtonLocation:
43 | FloatingActionButtonLocation.miniCenterFloat,
44 | floatingActionButton: FloatingActionButton(
45 | child: const Icon(Icons.done), onPressed: completeSetup),
46 | body: SingleChildScrollView(
47 | padding: const EdgeInsets.all(20),
48 | child: Center(
49 | child: Column(
50 | mainAxisAlignment: MainAxisAlignment.center,
51 | children: [
52 | const SizedBox(height: 130),
53 | themeSelecting(themeSegments),
54 | const SizedBox(height: 100),
55 | langSelecting(),
56 | const SizedBox(height: 30),
57 | ],
58 | ),
59 | ),
60 | ),
61 | );
62 | }
63 |
64 | Column themeSelecting(themeSegments) {
65 | return Column(
66 | mainAxisAlignment: MainAxisAlignment.center,
67 | children: [
68 | Align(
69 | alignment: Alignment.centerLeft,
70 | child: Text(
71 | vt.intl.of(context)!.fmt('prefs.appearance'),
72 | style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
73 | ),
74 | ),
75 | const SizedBox(height: 15),
76 | SizedBox(
77 | width: 300,
78 | child: CupertinoSlidingSegmentedControl(
79 | padding: const EdgeInsets.all(0),
80 | groupValue: themeSegmentedValue,
81 | children: themeSegments,
82 | onValueChanged: (dynamic i) {
83 | changeTheme(i);
84 | setState(() => themeSegmentedValue = i);
85 | },
86 | ),
87 | ),
88 | ],
89 | );
90 | }
91 |
92 | Column langSelecting() {
93 | return Column(
94 | mainAxisAlignment: MainAxisAlignment.center,
95 | children: [
96 | Align(
97 | alignment: Alignment.centerLeft,
98 | child: Text(
99 | vt.intl.of(context)!.fmt('prefs.lang'),
100 | style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
101 | ),
102 | ),
103 | const SizedBox(height: 15),
104 | SizedBox(
105 | width: 500,
106 | child: CupertinoSlidingSegmentedControl(
107 | padding: const EdgeInsets.all(0),
108 | groupValue: langSegmentedValue,
109 | children: langSegments,
110 | onValueChanged: (dynamic i) {
111 | changeLanguage(i);
112 | setState(() => langSegmentedValue = i);
113 | },
114 | ),
115 | ),
116 | ],
117 | );
118 | }
119 |
120 | void completeSetup() {
121 | changeTheme(themeSegmentedValue);
122 | changeLanguage(langSegmentedValue);
123 |
124 | Navigator.pushAndRemoveUntil(
125 | context,
126 | MaterialPageRoute(builder: (context) => Dashboard()),
127 | (route) => false,
128 | );
129 | }
130 |
131 | void changeLanguage(int i) {
132 | var args = {
133 | 0: () => BlocProvider.of(context).changeLang('en'),
134 | 1: () => BlocProvider.of(context).changeLang('tr'),
135 | 2: () => BlocProvider.of(context).changeLang('ru'),
136 | 3: () => BlocProvider.of(context).changeLang('ka'),
137 | };
138 | args[i]!.call();
139 | }
140 |
141 | void changeTheme(int i) {
142 | final values = {
143 | 0: () {
144 | BlocProvider.of(context).changeTheme('default');
145 | },
146 | 1: () {
147 | BlocProvider.of(context).changeTheme('dark');
148 | },
149 | 2: () {
150 | BlocProvider.of(context).changeTheme('s/2');
151 | }
152 | };
153 |
154 | values[i]!.call();
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/lib/view/widgets/components/appbars.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | class TransparentAppBar extends StatelessWidget with PreferredSizeWidget {
10 | final bool disableLeading;
11 | final Function? onLeadingTap;
12 | final Widget? titleWidget;
13 | final Widget? action;
14 |
15 | const TransparentAppBar({
16 | Key? key,
17 | this.disableLeading = false,
18 | this.onLeadingTap,
19 | this.titleWidget,
20 | this.action,
21 | }) : super(key: key);
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return AppBar(
26 | title: titleWidget,
27 | centerTitle: true,
28 | actions: (action != null) ? [action!] : null,
29 | leading: disableLeading
30 | ? const SizedBox.shrink()
31 | : IconButton(
32 | icon: const Icon(Icons.arrow_back_ios),
33 | onPressed: () => onLeadingTap!(),
34 | ),
35 | );
36 | }
37 |
38 | @override
39 | Size get preferredSize => const Size.fromHeight(55);
40 | }
41 |
--------------------------------------------------------------------------------
/lib/view/widgets/components/buttons.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_bloc/flutter_bloc.dart';
9 | import 'package:vtime/core/cubits/preference_cubit.dart';
10 | import 'package:vtime/core/utils/widgets.dart';
11 |
12 | class SaveButton extends VTStatelessWidget {
13 | final String title;
14 | final Function onTap;
15 |
16 | SaveButton({
17 | Key? key,
18 | required this.title,
19 | required this.onTap,
20 | }) : super(key: key);
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return Transform.translate(
25 | offset: Offset(0, -1 * MediaQuery.of(context).viewInsets.bottom),
26 | child: Padding(
27 | padding: const EdgeInsets.symmetric(vertical: 30),
28 | child: FractionallySizedBox(
29 | widthFactor: .8,
30 | child: ElevatedButton(
31 | onPressed: () => onTap(),
32 | child: Text(
33 | title,
34 | style: BlocProvider.of(context)
35 | .state
36 | .theme!
37 | .textTheme
38 | .button,
39 | ),
40 | ),
41 | ),
42 | ),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/view/widgets/components/custom_switchers.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:vtime/core/utils/widgets.dart';
9 | import 'package:vtime/view/widgets/utils.dart';
10 |
11 | class SwitcherTile extends VTStatelessWidget {
12 | final String title;
13 | final bool switcherValue;
14 | final Function(bool) onChanged;
15 | final Color? switcherColor;
16 | final double spaceAround;
17 | final MainAxisAlignment mainAxisAlignment;
18 | final TextStyle titleStyle;
19 |
20 | SwitcherTile({
21 | Key? key,
22 | required this.title,
23 | required this.switcherValue,
24 | required this.onChanged,
25 | this.switcherColor,
26 | this.spaceAround = 10,
27 | this.mainAxisAlignment = MainAxisAlignment.center,
28 | this.titleStyle = const TextStyle(fontWeight: FontWeight.bold),
29 | }) : super(key: key);
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return Row(
34 | mainAxisAlignment: mainAxisAlignment,
35 | children: [
36 | Align(
37 | alignment: Alignment.centerLeft,
38 | child: Text(title, style: titleStyle),
39 | ),
40 | SizedBox(width: spaceAround),
41 | CupertinoSwitch(
42 | activeColor: switcherColor ?? ViewUtils().pomodoroOrange(context),
43 | value: switcherValue,
44 | onChanged: onChanged,
45 | ),
46 | ],
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/view/widgets/components/loadings.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | class DoubleBounce extends StatefulWidget {
10 | final Color? color;
11 | final double? size;
12 | final IndexedWidgetBuilder? itemBuilder;
13 | final Duration duration;
14 | final AnimationController? controller;
15 | final Widget? child;
16 | final bool disabled;
17 | final bool isAnimationsDisabled;
18 |
19 | const DoubleBounce({
20 | Key? key,
21 | this.color = Colors.white,
22 | this.size = 50.0,
23 | this.itemBuilder,
24 | this.duration = const Duration(seconds: 2),
25 | this.controller,
26 | this.child = const SizedBox(),
27 | this.disabled = false,
28 | this.isAnimationsDisabled = false,
29 | }) : assert(size != null),
30 | assert(
31 | !(itemBuilder is IndexedWidgetBuilder && color is Color) &&
32 | !(itemBuilder == null && color == null),
33 | 'You should specify either an itemBuilder or a color',
34 | ),
35 | super(key: key);
36 |
37 | @override
38 | _DoubleBounceState createState() => _DoubleBounceState();
39 | }
40 |
41 | class _DoubleBounceState extends State
42 | with SingleTickerProviderStateMixin {
43 | late AnimationController _controller;
44 | late Animation _animation;
45 |
46 | @override
47 | void initState() {
48 | super.initState();
49 |
50 | _controller = (widget.controller ??
51 | AnimationController(
52 | vsync: this,
53 | duration: widget.duration,
54 | ))
55 | ..addListener(() => setState(() {}))
56 | ..repeat(reverse: true);
57 |
58 | _animation = Tween(begin: -1.0, end: 1.0).animate(
59 | CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
60 | );
61 | }
62 |
63 | @override
64 | void dispose() {
65 | _controller.dispose();
66 | super.dispose();
67 | }
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | return Center(
72 | child: Stack(
73 | children: [
74 | widget.isAnimationsDisabled ? const SizedBox.shrink() : animation(),
75 | Align(
76 | alignment: Alignment.center,
77 | child: widget.child ?? const SizedBox.shrink(),
78 | ),
79 | ],
80 | ),
81 | );
82 | }
83 |
84 | Widget animation() {
85 | return AnimatedOpacity(
86 | opacity: (widget.disabled) ? 0 : 1,
87 | duration: widget.duration,
88 | child: Align(
89 | alignment: Alignment.center,
90 | child: Stack(
91 | children: List.generate(
92 | 2,
93 | (index) => Transform.scale(
94 | scale: (1.0 - index - _animation.value.abs()).abs(),
95 | child: SizedBox.fromSize(
96 | size: Size.square(widget.size!),
97 | child: _itemBuilder(index),
98 | ),
99 | ),
100 | ),
101 | ),
102 | ),
103 | );
104 | }
105 |
106 | Widget _itemBuilder(int index) {
107 | if (widget.itemBuilder != null) {
108 | return widget.itemBuilder!(context, index);
109 | }
110 |
111 | return Container(
112 | decoration: BoxDecoration(
113 | shape: BoxShape.circle,
114 | color: widget.color!.withOpacity(0.6),
115 | ),
116 | );
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/lib/view/widgets/components/themes.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | ButtonStyle simpleButtonStyle(Color color) {
10 | return ButtonStyle(
11 | textStyle: MaterialStateProperty.all(TextStyle(color: color)),
12 | overlayColor: MaterialStateProperty.all(color.withOpacity(.2)),
13 | );
14 | }
15 |
16 | class Themes {
17 | final defaultTheme = ThemeData(
18 | brightness: Brightness.light,
19 | primaryColor: Colors.black,
20 | accentColor: Colors.black,
21 | primarySwatch: Colors.grey,
22 | hoverColor: Colors.grey.shade300,
23 | elevatedButtonTheme: ElevatedButtonThemeData(
24 | style: ButtonStyle(
25 | textStyle:
26 | MaterialStateProperty.all(const TextStyle(color: Colors.white)),
27 | backgroundColor: MaterialStateProperty.all(const Color(0xFF000000)),
28 | ),
29 | ),
30 | iconTheme: const IconThemeData(color: Colors.black),
31 | textSelectionTheme: TextSelectionThemeData(
32 | cursorColor: Colors.black,
33 | selectionColor: const Color(0xFF000000).withOpacity(.3),
34 | selectionHandleColor: const Color(0xFF000000).withOpacity(.3),
35 | ),
36 | textButtonTheme: TextButtonThemeData(
37 | style: ButtonStyle(
38 | textStyle: MaterialStateProperty.all(
39 | const TextStyle(color: Colors.white),
40 | ),
41 | overlayColor: MaterialStateProperty.all(
42 | const Color(0xFF000000).withOpacity(.3),
43 | ),
44 | ),
45 | ),
46 | bottomSheetTheme: const BottomSheetThemeData(
47 | shape: RoundedRectangleBorder(
48 | borderRadius: BorderRadius.only(
49 | topLeft: Radius.circular(30),
50 | topRight: Radius.circular(30),
51 | ),
52 | ),
53 | backgroundColor: Colors.white,
54 | ),
55 | textTheme: const TextTheme(
56 | headline1: TextStyle(color: Colors.black, fontWeight: FontWeight.w800),
57 | headline2: TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
58 | headline3: TextStyle(color: Colors.black, fontWeight: FontWeight.w600),
59 | headline4: TextStyle(color: Colors.black),
60 | headline5: TextStyle(color: Colors.black),
61 | headline6: TextStyle(color: Colors.black),
62 | button: TextStyle(color: Colors.white),
63 | ),
64 | primaryTextTheme: const TextTheme(
65 | headline6: TextStyle(color: Colors.black),
66 | ),
67 | buttonColor: const Color(0xffFF6347),
68 | appBarTheme: const AppBarTheme(
69 | elevation: 0,
70 | backgroundColor: Colors.transparent,
71 | centerTitle: true,
72 | iconTheme: IconThemeData(color: Colors.black),
73 | actionsIconTheme: IconThemeData(color: Colors.black),
74 | ),
75 | );
76 |
77 | final dark = ThemeData(
78 | scaffoldBackgroundColor: const Color(0xFF141414),
79 | brightness: Brightness.dark,
80 | primaryColor: Colors.white,
81 | accentColor: Colors.white,
82 | primarySwatch: Colors.grey,
83 | hoverColor: Colors.grey.shade900,
84 | elevatedButtonTheme: ElevatedButtonThemeData(
85 | style: ButtonStyle(
86 | textStyle:
87 | MaterialStateProperty.all(const TextStyle(color: Colors.black)),
88 | backgroundColor: MaterialStateProperty.all(const Color(0xFFFFFFFF)),
89 | ),
90 | ),
91 | iconTheme: const IconThemeData(color: Colors.black),
92 | textSelectionTheme: TextSelectionThemeData(
93 | cursorColor: Colors.white,
94 | selectionColor: const Color(0xFFFFFFFF).withOpacity(.3),
95 | selectionHandleColor: const Color(0xFFFFFFFF).withOpacity(.3),
96 | ),
97 | checkboxTheme: CheckboxThemeData(
98 | fillColor: MaterialStateProperty.all(Colors.white),
99 | checkColor: MaterialStateProperty.all(Colors.black),
100 | ),
101 | textButtonTheme: TextButtonThemeData(
102 | style: ButtonStyle(
103 | textStyle: MaterialStateProperty.all(
104 | const TextStyle(color: Colors.white),
105 | ),
106 | overlayColor: MaterialStateProperty.all(
107 | const Color(0xFF000000).withOpacity(.3),
108 | ),
109 | ),
110 | ),
111 | bottomSheetTheme: BottomSheetThemeData(
112 | shape: const RoundedRectangleBorder(
113 | borderRadius: BorderRadius.only(
114 | topLeft: Radius.circular(30),
115 | topRight: Radius.circular(30),
116 | ),
117 | ),
118 | backgroundColor: Colors.grey.shade900,
119 | ),
120 | textTheme: const TextTheme(
121 | headline1: TextStyle(color: Colors.white, fontWeight: FontWeight.w800),
122 | headline2: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
123 | headline3: TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
124 | headline4: TextStyle(color: Colors.white),
125 | headline5: TextStyle(color: Colors.white),
126 | headline6: TextStyle(color: Colors.white),
127 | button: TextStyle(color: Colors.black),
128 | ),
129 | primaryTextTheme: const TextTheme(
130 | headline6: TextStyle(color: Colors.white),
131 | ),
132 | buttonColor: const Color(0xffFF6347),
133 | appBarTheme: const AppBarTheme(
134 | elevation: 0,
135 | backgroundColor: Colors.transparent,
136 | centerTitle: true,
137 | iconTheme: IconThemeData(color: Colors.white),
138 | actionsIconTheme: IconThemeData(color: Colors.white),
139 | ),
140 | );
141 |
142 | // A special edition theme. Which was deisgned first when app idea had come.
143 | // See for additional information about minimalist theme - https://github.com/theiskaa/Visual-Time/issues/32
144 | final minimalist = ThemeData(
145 | brightness: Brightness.light,
146 | primaryColor: Colors.black,
147 | accentColor: Colors.black,
148 | primarySwatch: Colors.grey,
149 | hoverColor: Colors.grey.shade300,
150 | elevatedButtonTheme: ElevatedButtonThemeData(
151 | style: ButtonStyle(
152 | textStyle:
153 | MaterialStateProperty.all(const TextStyle(color: Colors.white)),
154 | backgroundColor: MaterialStateProperty.all(const Color(0xFF000000)),
155 | ),
156 | ),
157 | iconTheme: const IconThemeData(color: Colors.black),
158 | textSelectionTheme: TextSelectionThemeData(
159 | cursorColor: Colors.black,
160 | selectionColor: const Color(0xFF000000).withOpacity(.3),
161 | selectionHandleColor: const Color(0xFF000000).withOpacity(.3),
162 | ),
163 | textButtonTheme: TextButtonThemeData(
164 | style: ButtonStyle(
165 | textStyle: MaterialStateProperty.all(
166 | const TextStyle(color: Colors.white),
167 | ),
168 | overlayColor: MaterialStateProperty.all(
169 | const Color(0xFF000000).withOpacity(.3),
170 | ),
171 | ),
172 | ),
173 | bottomSheetTheme: const BottomSheetThemeData(
174 | shape: RoundedRectangleBorder(
175 | borderRadius: BorderRadius.only(
176 | topLeft: Radius.circular(30),
177 | topRight: Radius.circular(30),
178 | ),
179 | ),
180 | backgroundColor: Colors.white,
181 | ),
182 | textTheme: const TextTheme(
183 | headline1: TextStyle(color: Colors.black, fontWeight: FontWeight.w800),
184 | headline2: TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
185 | headline3: TextStyle(color: Colors.black, fontWeight: FontWeight.w600),
186 | headline4: TextStyle(color: Colors.black),
187 | headline5: TextStyle(color: Colors.black),
188 | headline6: TextStyle(color: Colors.black),
189 | button: TextStyle(color: Colors.white),
190 | ),
191 | primaryTextTheme: const TextTheme(
192 | headline6: TextStyle(color: Colors.black),
193 | ),
194 | buttonColor: Colors.black,
195 | appBarTheme: const AppBarTheme(
196 | elevation: 0,
197 | backgroundColor: Colors.transparent,
198 | centerTitle: true,
199 | iconTheme: IconThemeData(color: Colors.black),
200 | actionsIconTheme: IconThemeData(color: Colors.black),
201 | ),
202 | );
203 | }
204 |
205 | class DayChartColorPalettes {
206 | final darkPalette = [
207 | Colors.grey.shade900,
208 | Colors.red,
209 | Colors.purple.shade400,
210 | const Color.fromRGBO(246, 114, 128, 1),
211 | const Color.fromRGBO(248, 177, 149, 1),
212 | const Color.fromRGBO(116, 180, 155, 1),
213 | const Color.fromRGBO(0, 168, 181, 1),
214 | const Color.fromRGBO(73, 76, 162, 1),
215 | const Color.fromRGBO(255, 205, 96, 1),
216 | const Color.fromRGBO(255, 240, 219, 1),
217 | const Color.fromRGBO(238, 238, 238, 1)
218 | ];
219 |
220 | final lightPalette = [
221 | Colors.grey.shade300,
222 | Colors.red.shade400,
223 | const Color.fromRGBO(192, 108, 132, 1),
224 | const Color.fromRGBO(246, 114, 128, 1),
225 | const Color.fromRGBO(248, 177, 149, 1),
226 | const Color.fromRGBO(116, 180, 155, 1),
227 | const Color.fromRGBO(0, 168, 181, 1),
228 | const Color.fromRGBO(73, 76, 162, 1),
229 | const Color.fromRGBO(255, 205, 96, 1),
230 | const Color.fromRGBO(255, 240, 219, 1),
231 | const Color.fromRGBO(238, 238, 238, 1)
232 | ];
233 |
234 | static const s2Palette = [
235 | Color(0xFF858585),
236 | Color(0xFF1B1B1B),
237 | Color(0xFF303030),
238 | Color(0xFF474747),
239 | Color(0xFF2C2C2C),
240 | Color(0xFF5E5E5E),
241 | Color(0xFF1D1D1D),
242 | Color(0xFF777777),
243 | Color(0xFF777777),
244 | Color(0xFF919191),
245 | Color(0xFF383838),
246 | Color(0xFF1D1D1D),
247 | ];
248 | }
249 |
--------------------------------------------------------------------------------
/lib/view/widgets/day_chart.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_bloc/flutter_bloc.dart';
9 | import 'package:syncfusion_flutter_charts/charts.dart';
10 | import 'package:vtime/core/cubits/preference_cubit.dart';
11 | import 'package:vtime/core/cubits/preference_state.dart';
12 |
13 | import 'package:vtime/core/model/task.dart';
14 | import 'package:vtime/core/utils/widgets.dart';
15 | import 'package:vtime/view/widgets/utils.dart';
16 |
17 | import 'components/themes.dart';
18 |
19 | // ignore: must_be_immutable
20 | class DayChart extends VTStatefulWidget {
21 | List tasks;
22 | final bool isTooltipBehaviorEnabled;
23 |
24 | DayChart({
25 | Key? key,
26 | required this.tasks,
27 | this.isTooltipBehaviorEnabled = false,
28 | }) : super(key: key);
29 |
30 | @override
31 | _DayChartState createState() => _DayChartState();
32 | }
33 |
34 | class _DayChartState extends VTState {
35 | final viewUtils = ViewUtils();
36 |
37 | dynamic currentPalette(String? themeName) {
38 | var palettes = {
39 | 's/2': DayChartColorPalettes.s2Palette,
40 | 'dark': DayChartColorPalettes().darkPalette,
41 | 'default': DayChartColorPalettes().lightPalette
42 | };
43 |
44 | return palettes[themeName];
45 | }
46 |
47 | @override
48 | Widget build(BuildContext context) {
49 | return BlocBuilder(
50 | builder: (context, state) {
51 | var total = (ViewUtils.fullDay -
52 | viewUtils.calculateTotalDuration(widget.tasks));
53 | widget.tasks.add(Task().remainingTimeFiller(total));
54 |
55 | return SfCircularChart(
56 | palette: currentPalette(state.themeName),
57 | tooltipBehavior:
58 | widget.isTooltipBehaviorEnabled ? tooltipBehavior() : null,
59 | series: >[
60 | PieSeries(
61 | dataSource: widget.tasks,
62 | xValueMapper: (Task data, _) => data.totalTime.toString(),
63 | yValueMapper: (Task data, _) => data.totalTime,
64 | animationDuration: state.isAnimationsEnabled! ? 1500 : 0,
65 | ),
66 | ],
67 | );
68 | },
69 | );
70 | }
71 |
72 | TooltipBehavior tooltipBehavior() {
73 | return TooltipBehavior(
74 | color: Colors.black,
75 | enable: true,
76 | builder: (dynamic data, dynamic point, dynamic series, int pointIndex,
77 | int seriesIndex) {
78 | return Container(
79 | height: 20,
80 | width: (data.title == remainingTimeFillerTaskCode) ? 150 : 100,
81 | decoration: BoxDecoration(
82 | color: Colors.black,
83 | borderRadius: BorderRadius.circular(10),
84 | ),
85 | child: Center(
86 | child: Text(
87 | generateTooltipText(data),
88 | style: const TextStyle(color: Colors.white, fontSize: 8.5),
89 | ),
90 | ),
91 | );
92 | },
93 | );
94 | }
95 |
96 | String generateTooltipText(Task data) {
97 | var time = Duration(hours: data.hours!, minutes: data.minutes!)
98 | .toHumanLang(vt, context);
99 | if (data.title == 'Remaining Time {#@!@#!@#8&**%@#%}') {
100 | return '${vt.intl.of(context)!.fmt('remaining')} - $time';
101 | }
102 | return time;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/lib/view/widgets/live-task/clock_count.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:vtime/core/utils/widgets.dart';
9 | import 'package:vtime/view/widgets/utils.dart';
10 |
11 | import '../components/loadings.dart';
12 |
13 | class ClockCount extends VTStatelessWidget {
14 | final bool disabled;
15 | final String time;
16 | final bool isAnimationDisabled;
17 |
18 | ClockCount({
19 | Key? key,
20 | required this.disabled,
21 | required this.time,
22 | this.isAnimationDisabled = false,
23 | }) : super(key: key);
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | double size = MediaQuery.of(context).size.width / 1.8;
28 | return _ThreeRoundCircleGrid(
29 | generalSize: size,
30 | child: Center(
31 | child: DoubleBounce(
32 | isAnimationsDisabled: isAnimationDisabled,
33 | disabled: disabled,
34 | size: size - 50,
35 | color: ViewUtils().pomodoroOrange(context),
36 | child: AnimatedContainer(
37 | duration: const Duration(seconds: 1),
38 | child: (time == 'dn')
39 | ? Icon(
40 | Icons.done,
41 | size: 50,
42 | color: ViewUtils().pomodoroOrange(context),
43 | )
44 | : Text(
45 | time,
46 | style: TextStyle(
47 | fontSize: 35,
48 | fontWeight: FontWeight.bold,
49 | color:
50 | disabled ? ViewUtils().pomodoroOrange(context) : null,
51 | ),
52 | ),
53 | ),
54 | ),
55 | ),
56 | );
57 | }
58 | }
59 |
60 | class _ThreeRoundCircleGrid extends StatelessWidget {
61 | final Widget child;
62 | final double generalSize;
63 |
64 | const _ThreeRoundCircleGrid({
65 | Key? key,
66 | required this.child,
67 | required this.generalSize,
68 | }) : super(key: key);
69 |
70 | @override
71 | Widget build(BuildContext context) {
72 | return Container(
73 | height: generalSize + 5,
74 | width: generalSize + 5,
75 | decoration: BoxDecoration(
76 | border: Border.all(
77 | width: 3,
78 | color: ViewUtils().pomodoroOrange(context).withOpacity(.1),
79 | ),
80 | shape: BoxShape.circle,
81 | ),
82 | padding: const EdgeInsets.all(3),
83 | child: Container(
84 | height: generalSize,
85 | width: generalSize,
86 | decoration: BoxDecoration(
87 | border: Border.all(
88 | width: 3,
89 | color: ViewUtils().pomodoroOrange(context).withOpacity(.1),
90 | ),
91 | shape: BoxShape.circle,
92 | ),
93 | child: child,
94 | ),
95 | );
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/lib/view/widgets/mini_day_card.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/foundation.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:hive/hive.dart';
10 | import 'package:vtime/core/model/task.dart';
11 |
12 | import 'day_chart.dart';
13 |
14 | class MiniDayChart extends StatelessWidget {
15 | final String title;
16 | final Function? onTap;
17 | final ValueListenable> todaysBox;
18 |
19 | const MiniDayChart({
20 | Key? key,
21 | required this.title,
22 | required this.onTap,
23 | required this.todaysBox,
24 | }) : super(key: key);
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return GestureDetector(
29 | onTap: () => onTap!(),
30 | child: Padding(
31 | padding: const EdgeInsets.all(10),
32 | child: Column(
33 | mainAxisSize: MainAxisSize.min,
34 | children: [
35 | Text(
36 | title,
37 | style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
38 | ),
39 | GestureDetector(
40 | onTap: () => onTap!(),
41 | child: ValueListenableBuilder>(
42 | valueListenable: todaysBox,
43 | builder: (context, box, _) {
44 | final tasks = box.values.toList().cast();
45 | return SizedBox(
46 | height: 65,
47 | width: 65,
48 | child: DayChart(tasks: tasks),
49 | );
50 | },
51 | ),
52 | ),
53 | ],
54 | ),
55 | ),
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/view/widgets/task_card.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_slidable/flutter_slidable.dart';
10 | import 'package:hive_flutter/hive_flutter.dart';
11 |
12 | import 'package:vtime/core/model/task.dart';
13 | import 'package:vtime/core/utils/widgets.dart';
14 | import 'package:vtime/view/edit.dart';
15 | import 'package:vtime/view/live-task/dashboard.dart';
16 |
17 | import 'utils.dart';
18 |
19 | class TaskCard extends VTStatelessWidget {
20 | final Task task;
21 | final Function onDismissed;
22 | final Box dayBox;
23 |
24 | TaskCard({
25 | Key? key,
26 | required this.task,
27 | required this.onDismissed,
28 | required this.dayBox,
29 | }) : super(key: key);
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return Slidable(
34 | key: key,
35 | actionPane: const SlidableDrawerActionPane(),
36 | child: Padding(
37 | padding: const EdgeInsets.symmetric(vertical: 10),
38 | child: ListTile(
39 | title: Text(task.title!),
40 | subtitle: Text(ViewUtils().generateSubtitle(context, task, vt)),
41 | ),
42 | ),
43 | actions: [
44 | IconSlideAction(
45 | caption: vt.intl.of(context)!.fmt('act.start'),
46 | color: ViewUtils().pomodoroOrange(context),
47 | icon: CupertinoIcons.time_solid,
48 | onTap: () => Navigator.push(
49 | context,
50 | MaterialPageRoute(
51 | builder: (context) =>
52 | LiveTaskDashboard(task: task, dayBox: dayBox),
53 | ),
54 | ),
55 | ),
56 | ],
57 | secondaryActions: [
58 | IconSlideAction(
59 | caption: vt.intl.of(context)!.fmt('act.edit'),
60 | color: const Color(0xFF07B307),
61 | icon: Icons.edit,
62 | onTap: () => Navigator.push(
63 | context,
64 | MaterialPageRoute(
65 | builder: (context) => EditPage(task: task, dayBox: dayBox),
66 | ),
67 | ),
68 | ),
69 | IconSlideAction(
70 | caption: vt.intl.of(context)!.fmt('act.delete'),
71 | color: const Color(0xffff0000),
72 | icon: Icons.delete,
73 | onTap: () => onDismissed(),
74 | ),
75 | ],
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/lib/view/widgets/utils.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_bloc/flutter_bloc.dart';
9 | import 'package:vtime/core/cubits/preference_cubit.dart';
10 | import 'package:vtime/core/model/task.dart';
11 | import 'package:vtime/core/vt.dart';
12 |
13 | import 'components/themes.dart';
14 |
15 | const remainingTimeFillerTaskCode = 'Remaining Time {#@!@#!@#8&**%@#%}';
16 |
17 | class ViewUtils {
18 | Color pomodoroOrange(BuildContext context) =>
19 | BlocProvider.of(context).state.theme!.buttonColor;
20 |
21 | // Style shortcut which is used for live-task start/stop button and setting's alarm sound button.
22 | ButtonStyle pomodoroButtonStyle(BuildContext context) {
23 | return ButtonStyle(
24 | overlayColor:
25 | MaterialStateProperty.all(pomodoroOrange(context).withOpacity(.1)),
26 | fixedSize: MaterialStateProperty.all(const Size(0, 40)),
27 | elevation: MaterialStateProperty.all(0),
28 | backgroundColor: MaterialStateProperty.all(Colors.transparent),
29 | shape: MaterialStateProperty.all(
30 | RoundedRectangleBorder(
31 | side: BorderSide(color: pomodoroOrange(context)),
32 | borderRadius: const BorderRadius.all(Radius.circular(30)),
33 | ),
34 | ),
35 | );
36 | }
37 |
38 | // A shortcut style method to show full functional alert dialog.
39 | alert(
40 | BuildContext context,
41 | VT vt, {
42 | required String title,
43 | required Function onAct,
44 | List? buttons,
45 | }) async {
46 | var actions = [
47 | TextButton(
48 | onPressed: () => Navigator.pop(context),
49 | child: Text(vt.intl.of(context)!.fmt('act.no')),
50 | ),
51 | TextButton(
52 | style: simpleButtonStyle(Colors.red.shade700),
53 | onPressed: () => onAct(),
54 | child: Text(
55 | vt.intl.of(context)!.fmt('act.yes'),
56 | style: TextStyle(color: Colors.red.shade700),
57 | ),
58 | ),
59 | ];
60 | if (buttons != null && buttons.isNotEmpty) {
61 | for (var i = 0; i < buttons.length; i++) {
62 | actions.add(buttons[i]);
63 | }
64 | }
65 |
66 | showDialog(
67 | context: context,
68 | builder: (context) => AlertDialog(
69 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
70 | title: Text(title),
71 | actions: actions,
72 | ),
73 | );
74 | }
75 |
76 | String generateSubtitle(BuildContext context, Task task, VT vt) {
77 | var time = Duration(hours: task.hours!, minutes: task.minutes!)
78 | .toHumanLang(vt, context);
79 | if (task.description!.isNotEmpty) {
80 | return '${task.description!} | $time';
81 | }
82 | return time;
83 | }
84 |
85 | // Generates right name by index.
86 | String rightDayNameGenerator(int index, VT vt, context) {
87 | var values = {
88 | 0: vt.intl.of(context)?.fmt('monday'),
89 | 1: vt.intl.of(context)?.fmt('tuesday'),
90 | 2: vt.intl.of(context)?.fmt('wednesday'),
91 | 3: vt.intl.of(context)?.fmt('thursday'),
92 | 4: vt.intl.of(context)?.fmt('friday'),
93 | 5: vt.intl.of(context)?.fmt('saturday'),
94 | 6: vt.intl.of(context)?.fmt('sunday'),
95 | };
96 | return values[index]!;
97 | }
98 |
99 | InputDecoration? nonBorderInputDecoration({
100 | String? hint,
101 | }) {
102 | return InputDecoration(
103 | hintText: hint,
104 | border: InputBorder.none,
105 | focusedBorder: InputBorder.none,
106 | enabledBorder: InputBorder.none,
107 | errorBorder: InputBorder.none,
108 | disabledBorder: InputBorder.none,
109 | focusedErrorBorder: InputBorder.none,
110 | );
111 | }
112 |
113 | static const Duration fullDay = Duration(hours: 24);
114 |
115 | Duration calculateTotalDuration(List? tasks) {
116 | Duration filledAmount = Duration.zero;
117 |
118 | for (var i = 0; i < tasks!.length; i++) {
119 | filledAmount = filledAmount +
120 | Duration(hours: tasks[i].hours!, minutes: tasks[i].minutes!);
121 | }
122 |
123 | return filledAmount;
124 | }
125 |
126 | static const divider = Divider(
127 | height: 5,
128 | thickness: 1,
129 | indent: 50,
130 | endIndent: 50,
131 | );
132 | }
133 |
134 | extension DurationToHumanLangEXT on Duration {
135 | String toHumanLang(VT vt, context) {
136 | var inMinutes = this.inMinutes.remainder(60).toString();
137 | var inHours = this.inHours.toString();
138 |
139 | String hour = vt.intl.of(context)!.fmt(this.inHours > 1 ? 'hours' : 'hour');
140 | String minute = vt.intl
141 | .of(context)!
142 | .fmt(int.parse(inMinutes) > 1 ? 'minutes' : 'minute');
143 |
144 | if (this == Duration.zero) {
145 | return vt.intl.of(context)!.fmt('task.duration.hint');
146 | }
147 | if (inMinutes != '0' && inHours != '0') {
148 | return '$inHours $hour ${vt.intl.of(context)!.fmt('and')} $inMinutes $minute';
149 | }
150 | if (inHours != '0' && inMinutes == '0') {
151 | return '$inHours $hour';
152 | }
153 | if (inMinutes != '0' && inHours == '0') {
154 | return '$inMinutes $minute';
155 | }
156 |
157 | return '';
158 | }
159 |
160 | int get minute => inMinutes.remainder(60);
161 |
162 | String get toHMS {
163 | String twoDigits(int n) => n.toString().padLeft(2, '0');
164 | String twoDigitMinutes = twoDigits(inMinutes.remainder(60));
165 | String twoDigitSeconds = twoDigits(inSeconds.remainder(60));
166 | if (inHours > 0) {
167 | return '${twoDigits(inHours)}:$twoDigitMinutes:$twoDigitSeconds';
168 | }
169 | return '$twoDigitMinutes:$twoDigitSeconds';
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/macos/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/.DS_Store
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/xcuserdata/
7 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 | import audioplayers
9 | import path_provider_macos
10 |
11 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
12 | AudioplayersPlugin.register(with: registry.registrar(forPlugin: "AudioplayersPlugin"))
13 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
14 | }
15 |
--------------------------------------------------------------------------------
/macos/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '10.11'
2 |
3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 |
6 | project 'Runner', {
7 | 'Debug' => :debug,
8 | 'Profile' => :release,
9 | 'Release' => :release,
10 | }
11 |
12 | def flutter_root
13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 | unless File.exist?(generated_xcode_build_settings_path)
15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 | end
17 |
18 | File.foreach(generated_xcode_build_settings_path) do |line|
19 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 | return matches[1].strip if matches
21 | end
22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 | end
24 |
25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 |
27 | flutter_macos_podfile_setup
28 |
29 | target 'Runner' do
30 | use_frameworks!
31 | use_modular_headers!
32 |
33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 | end
35 |
36 | post_install do |installer|
37 | installer.pods_project.targets.each do |target|
38 | flutter_additional_macos_build_settings(target)
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/macos/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - audioplayers (0.0.1):
3 | - FlutterMacOS
4 | - FlutterMacOS (1.0.0)
5 | - path_provider_macos (0.0.1):
6 | - FlutterMacOS
7 |
8 | DEPENDENCIES:
9 | - audioplayers (from `Flutter/ephemeral/.symlinks/plugins/audioplayers/macos`)
10 | - FlutterMacOS (from `Flutter/ephemeral`)
11 | - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
12 |
13 | EXTERNAL SOURCES:
14 | audioplayers:
15 | :path: Flutter/ephemeral/.symlinks/plugins/audioplayers/macos
16 | FlutterMacOS:
17 | :path: Flutter/ephemeral
18 | path_provider_macos:
19 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
20 |
21 | SPEC CHECKSUMS:
22 | audioplayers: 8b48e22684b6e0d9df143b2d1bbd61dca9dab6b4
23 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
24 | path_provider_macos: 160cab0d5461f0c0e02995469a98f24bdb9a3f1f
25 |
26 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
27 |
28 | COCOAPODS: 1.10.1
29 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
71 |
73 |
79 |
80 |
81 |
82 |
84 |
85 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/.DS_Store
--------------------------------------------------------------------------------
/macos/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | @NSApplicationMain
5 | class AppDelegate: FlutterAppDelegate {
6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 | return true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/Assets.xcassets/.DS_Store
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "logo 1-16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "logo 1-32.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "logo 1-32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "logo 1-64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "logo 1-128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "logo 1-256.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "logo 1-256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "logo 1-512.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "logo 1-512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "logo 1-1024.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-1024.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/macos/Runner/Assets.xcassets/AppIcon.appiconset/logo 1-64.png
--------------------------------------------------------------------------------
/macos/Runner/Configs/AppInfo.xcconfig:
--------------------------------------------------------------------------------
1 | // Application-level settings for the Runner target.
2 | //
3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 | // future. If not, the values below would default to using the project name when this becomes a
5 | // 'flutter create' template.
6 |
7 | // The application's name. By default this is also the title of the Flutter window.
8 | PRODUCT_NAME = vtime
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.vtime
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved.
15 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Warnings.xcconfig:
--------------------------------------------------------------------------------
1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 | GCC_WARN_UNDECLARED_SELECTOR = YES
3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 | CLANG_WARN_PRAGMA_PACK = YES
7 | CLANG_WARN_STRICT_PROTOTYPES = YES
8 | CLANG_WARN_COMMA = YES
9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 | GCC_WARN_SHADOW = YES
13 | CLANG_WARN_UNREACHABLE_CODE = YES
14 |
--------------------------------------------------------------------------------
/macos/Runner/DebugProfile.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 | com.apple.security.network.server
10 |
11 | com.apple.security.network.client
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/macos/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | $(PRODUCT_COPYRIGHT)
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 | NSAppTransportSecurity
32 |
33 | NSAllowsArbitraryLoads
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController.init()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.network.client
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: vtime
2 | description: An advanced, minimalist and powerful time management application.
3 | publish_to: "none"
4 |
5 | version: 1.0.0+1
6 |
7 | environment:
8 | sdk: ">=2.12.0 <3.0.0"
9 |
10 | dependencies:
11 | flutter:
12 | sdk: flutter
13 | hive: ^2.0.4
14 | hive_flutter: ^1.1.0
15 | flutter_bloc: ^7.0.1
16 | logger:
17 | syncfusion_flutter_charts: ^19.1.69+1
18 | flutter_slidable: ^0.6.0
19 | cupertino_icons: ^1.0.2
20 | audioplayers: ^0.19.1
21 |
22 | dev_dependencies:
23 | flutter_test:
24 | sdk: flutter
25 | flutter_localizations:
26 | sdk: flutter
27 |
28 | intl: ^0.17.0
29 | flutter_lints: ^1.0.2
30 | build_runner: ^2.0.4
31 | hive_generator: ^1.1.0
32 | mockito:
33 |
34 | flutter:
35 | uses-material-design: true
36 | assets:
37 | - assets/i18n/en.json
38 | - assets/i18n/tr.json
39 | - assets/i18n/ru.json
40 | - assets/i18n/ka.json
41 |
42 | - assets/alarms/Nonimooley.mp3
43 | - assets/alarms/Crystalie.mp3
44 | - assets/alarms/Favour.mp3
45 | - assets/alarms/Violet.mp3
46 | - assets/alarms/SMS.mp3
47 | - assets/alarms/Points.mp3
48 | - assets/alarms/Iris.mp3
49 | - assets/alarms/Crystal.mp3
50 | - assets/alarms/Harmonics.mp3
51 | - assets/alarms/Marigold.mp3
52 |
--------------------------------------------------------------------------------
/test/core/cubits/preference_state_test.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter_test/flutter_test.dart';
8 | import 'package:vtime/core/cubits/preference_state.dart';
9 | import 'package:vtime/view/widgets/components/themes.dart';
10 |
11 | void main() {
12 | late PreferenceState preferenceState;
13 |
14 | setUpAll(() {
15 | preferenceState = PreferenceState(
16 | langCode: 'en',
17 | themeName: 'default',
18 | theme: Themes().defaultTheme,
19 | selectedAlarmSound: 'Sound 1',
20 | isAnimationsEnabled: true,
21 | );
22 | });
23 |
24 | group('[PreferenceState]', () {
25 | test('executes copyWith correctly', () {
26 | final sameCopiedState = preferenceState.copyWith();
27 | final customState = preferenceState.copyWith(
28 | theme: Themes().dark,
29 | themeName: 'dark',
30 | langCode: 'ka', // ka = kartuli -> Georgian language
31 | selectedAlarmSound: 'Sound 2',
32 | isAnimationsEnabled: false,
33 | );
34 |
35 | // Expect nothing was changed in for sameCopiedDay.
36 | expect(sameCopiedState.theme, preferenceState.theme);
37 | expect(sameCopiedState.themeName, preferenceState.themeName);
38 | expect(sameCopiedState.langCode, preferenceState.langCode);
39 | expect(
40 | sameCopiedState.selectedAlarmSound,
41 | preferenceState.selectedAlarmSound,
42 | );
43 | expect(
44 | sameCopiedState.isAnimationsEnabled,
45 | preferenceState.isAnimationsEnabled,
46 | );
47 |
48 | // Expect difference between [task] and [customTask].
49 | expect(customState.theme == preferenceState.theme, false);
50 | expect(customState.themeName == preferenceState.themeName, false);
51 | expect(customState.langCode == preferenceState.langCode, false);
52 | expect(
53 | customState.selectedAlarmSound == preferenceState.selectedAlarmSound,
54 | false,
55 | );
56 | expect(
57 | customState.isAnimationsEnabled == preferenceState.isAnimationsEnabled,
58 | false,
59 | );
60 | });
61 | });
62 | }
63 |
--------------------------------------------------------------------------------
/test/core/models/day_test.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter_test/flutter_test.dart';
8 | import 'package:vtime/core/model/day.dart';
9 |
10 | void main() {
11 | late Day day;
12 |
13 | Map jsonModel = {
14 | 'name': 'Saturday',
15 | 'title': 'Saturday',
16 | 'dayIndex': 5
17 | };
18 |
19 | setUpAll(() {
20 | day = const Day(name: 'Saturday', title: 'Saturday', dayIndex: 5);
21 | });
22 |
23 | group('[Day]', () {
24 | test('converts from json correctly', () {
25 | final dayFromJson = Day.fromJson(jsonModel);
26 |
27 | // Need to match properties rather than instances.
28 | expect(dayFromJson.name, day.name);
29 | expect(dayFromJson.title, day.title);
30 | expect(dayFromJson.dayIndex, day.dayIndex);
31 | });
32 |
33 | test('converts to json correctly', () {
34 | final dayToJson = day.toJson();
35 |
36 | expect(jsonModel, dayToJson);
37 | });
38 |
39 | test('executes copyWith correctly', () {
40 | final sameCopiedDay = day.copyWith();
41 | final customDay = day.copyWith(
42 | name: 'different name',
43 | title: 'different title',
44 | dayIndex: 0,
45 | );
46 |
47 | // Expect nothing was changed in for sameCopiedDay.
48 | expect(sameCopiedDay.name, day.name);
49 | expect(sameCopiedDay.title, day.title);
50 | expect(sameCopiedDay.dayIndex, day.dayIndex);
51 |
52 | // Expect difference between [task] and [customTask].
53 | expect(customDay.name == day.name, false);
54 | expect(customDay.title == day.title, false);
55 | expect(customDay.dayIndex == day.dayIndex, false);
56 | });
57 | });
58 | }
59 |
--------------------------------------------------------------------------------
/test/core/models/task_test.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter_test/flutter_test.dart';
8 | import 'package:vtime/core/model/task.dart';
9 | import 'package:vtime/view/widgets/utils.dart';
10 |
11 | void main() {
12 | late Task task;
13 |
14 | const Map jsonModel = {
15 | 'title': 'Test title',
16 | 'description': 'Test description',
17 | 'hours': 5,
18 | 'minutes': 15,
19 | 'uniquekey': '',
20 | };
21 |
22 | setUpAll(() {
23 | task = Task(
24 | title: 'Test title',
25 | description: 'Test description',
26 | uniquekey: '',
27 | hours: 5,
28 | minutes: 15,
29 | );
30 | });
31 |
32 | group('[Task]', () {
33 | test('converts from json correctly', () {
34 | final taskFromJson = Task.fromJson(jsonModel);
35 |
36 | // Need to match properties rather than instances.
37 | expect(task.title, taskFromJson.title);
38 | expect(task.description, taskFromJson.description);
39 | expect(task.uniquekey, taskFromJson.uniquekey);
40 | expect(task.hours, taskFromJson.hours);
41 | expect(task.minutes, taskFromJson.minutes);
42 | });
43 |
44 | test('converts to json correctly', () {
45 | final taskToJson = task.toJson();
46 |
47 | expect(jsonModel, taskToJson);
48 | });
49 |
50 | test('executes copyWith correctly', () {
51 | final sameCopiedTask = task.copyWith();
52 | final customTask = task.copyWith(
53 | title: 'different task',
54 | description: 'different description',
55 | uniquekey: 'Uniquekey',
56 | hours: 3,
57 | minutes: 10,
58 | );
59 |
60 | // Expect nothing was changed in for sameCopiedTask.
61 | expect(sameCopiedTask.title, task.title);
62 | expect(sameCopiedTask.description, task.description);
63 | expect(sameCopiedTask.uniquekey, task.uniquekey);
64 | expect(sameCopiedTask.hours, task.hours);
65 | expect(sameCopiedTask.minutes, task.minutes);
66 |
67 | // Expect difference between [task] and [customTask].
68 | expect(customTask.title == task.title, false);
69 | expect(customTask.description == task.description, false);
70 | expect(customTask.uniquekey == task.uniquekey, false);
71 | expect(customTask.hours == task.hours, false);
72 | expect(customTask.minutes == task.minutes, false);
73 | });
74 |
75 | test('calculates totalTime correctly', () {
76 | double val = task.totalTime;
77 |
78 | double rightMinute = double.parse('0.${task.minutes}');
79 | double total = task.hours! + rightMinute;
80 |
81 | expect(total, val);
82 | });
83 |
84 | test('converts to duration correctly', () {
85 | var val = task.duration;
86 | expect(val.inHours, task.hours);
87 | expect(val.minute, task.minutes);
88 | });
89 |
90 | test('test remainingTimeFiller', () {
91 | Task remainingTimeFiller = Task().remainingTimeFiller(task.duration);
92 |
93 | int hours = task.totalTime.floor();
94 | int minutes = int.parse('${task.totalTime}'.replaceAll('$hours.', ''));
95 |
96 | expect(remainingTimeFiller.title, 'Remaining Time {#@!@#!@#8&**%@#%}');
97 | expect(remainingTimeFiller.description, '');
98 | expect(remainingTimeFiller.uniquekey, '');
99 | expect(remainingTimeFiller.hours, hours);
100 | expect(remainingTimeFiller.minutes, minutes);
101 | });
102 | });
103 | }
104 |
--------------------------------------------------------------------------------
/test/core/models/vt_model_test.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter_test/flutter_test.dart';
8 | import 'package:vtime/core/model/vt_model.dart';
9 |
10 | class TestVTModel extends VTModel {
11 | @override
12 | Map toJson() => {};
13 |
14 | @override
15 | copyWith() {}
16 | }
17 |
18 | void main() {
19 | late TestVTModel vtModel;
20 |
21 | setUpAll(() => vtModel = TestVTModel());
22 |
23 | test('test VTModel', () async {
24 | final vtModelToJson = vtModel.toJson();
25 |
26 | expect(vtModel.runtimeType, TestVTModel);
27 | expect(vtModelToJson, {});
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/test/core/utils/intl_test.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/widgets.dart';
8 | import 'package:flutter_test/flutter_test.dart';
9 | import 'package:mockito/mockito.dart';
10 |
11 | import 'package:vtime/core/utils/intl.dart';
12 |
13 | class MockBuildContext extends Mock implements BuildContext {}
14 |
15 | void main() {
16 | // The classes that are to be tested.
17 | late Intl intl;
18 | late IntlDelegate intlDelegate;
19 |
20 | late MockBuildContext mockBuildContext;
21 |
22 | // Pre-defined constant values intended for testing purposes (dependencies).
23 | const locale = Locale('en');
24 | const supportedLanguageCodes = ['en', 'tr', 'ru'];
25 | const unsupportedLocale = Locale('unsupported');
26 | const testLocalizedKey = 'ERROR.GENERAL';
27 | const testLocalizedKeyWithArgs = 'test.hello';
28 | const testLocalizedValueWithArgs = 'Hello Ismael, your age is 16';
29 |
30 | // Initializing the classes that are to be tested right before the test run.
31 | setUpAll(() {
32 | intl = Intl();
33 | intl.locale = locale;
34 | intlDelegate = const IntlDelegate();
35 |
36 | mockBuildContext = MockBuildContext();
37 | });
38 |
39 | // Main group consisting of all things related to Intl class.
40 | group('Intl', () {
41 | // Function that loads the translation file contents to memory
42 | // and assigns it to _intl's localizedValues property.
43 | Future testIntlLoad() async {
44 | // The .load() method depends on _intl's locale property.
45 | intl.locale = locale;
46 |
47 | // A way to ensure that the .load() method will work during the test.
48 | TestWidgetsFlutterBinding.ensureInitialized();
49 |
50 | // Setting the translation file contents to _intl.localizedValues.
51 | intl.localizedValues = (await intl.load()).cast();
52 | }
53 |
54 | // Verifying that Intl has the following default property values.
55 | test('has expected default property values', () {
56 | expect(intl, isA());
57 | expect(intl.delegate, isA());
58 | expect(intl.locale, isNotNull);
59 | expect(intl.localizedValues, isNull);
60 | expect(intl.supportedLocales, isNull);
61 | expect(intl.runtimeType, Intl);
62 | });
63 |
64 | test('Test Intl.of(...)', () async {
65 | // Loading the translation file contents.
66 | await testIntlLoad();
67 |
68 | expect(intl.of(mockBuildContext),
69 | Localizations.of(mockBuildContext, Intl));
70 | });
71 |
72 | // Verifying that Intl returns localized text.
73 | test('returns localized (formatted) text as defined', () async {
74 | // Initlaze a mock of localized values.
75 | intl.localizedValues = {'test.hello': 'Hello %1, your age is %2'};
76 |
77 | // Verifying the .fmt() with arguments method.
78 | expect(
79 | intl.fmt(testLocalizedKeyWithArgs, ['Ismael', '16']),
80 | testLocalizedValueWithArgs,
81 | );
82 | });
83 |
84 | // Verifying that Intl loads the translation file contents.
85 | test('loads the language JSON file as defined', () async {
86 | // Loading the translation file contents.
87 | await testIntlLoad();
88 |
89 | // Verifying that the localizedValues is not empty.
90 | expect(intl.localizedValues!.isNotEmpty, true);
91 | });
92 | });
93 |
94 | // Main group consisting of all things related to IntlDelegate class.
95 | group('IntlDelegate', () {
96 | // Verifying that IntlDelegate has the following default property values.
97 | test('has expected default property values', () {
98 | expect(intlDelegate, isA());
99 | expect(intlDelegate, isA());
100 | expect(intlDelegate.runtimeType, IntlDelegate);
101 | });
102 |
103 | // Verifying that IntlDelegate supports specific locales.
104 | test('checks if specific locale is supported', () {
105 | // Iterating over language codes and verifying that the locales
106 | // that have the aforementioned language code as the primary argument
107 | // are indeed supported by the IntlDelegate.
108 | for (var languageCode in supportedLanguageCodes) {
109 | expect(
110 | intlDelegate.isSupported(Locale(languageCode)),
111 | true,
112 | );
113 | }
114 |
115 | // Verifying that any other locales aren't supported.
116 | expect(intlDelegate.isSupported(unsupportedLocale), false);
117 | });
118 |
119 | // Verifying that IntlDelegate loads the translation file contents.
120 | test('loads the language JSON file as defined', () async {
121 | // Loading the translation file contents.
122 | intl = await intlDelegate.load(locale);
123 |
124 | // Verifying that the localizedValues is not empty.
125 | expect(intl.fmt(testLocalizedKey), testLocalizedKey);
126 | });
127 |
128 | // Verifying that IntlDelegate checks correctly if it should reload.
129 | test(
130 | 'checks if it should reload',
131 | () => expect(intlDelegate.shouldReload(intlDelegate), false),
132 | );
133 | });
134 | }
135 |
--------------------------------------------------------------------------------
/test/core/utils/logger_test.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter_test/flutter_test.dart';
8 | import 'package:logger/logger.dart' as logger;
9 | import 'package:vtime/core/utils/logger.dart';
10 |
11 | void main() {
12 | group('Log', () {
13 | test('has expected default property values', () {
14 | expect(Log.log, isA());
15 | expect(Log.logNoStack, isA());
16 | expect(Log.level, isNull);
17 | expect(Log.v, Log.logNoStack.v);
18 | expect(Log.d, Log.logNoStack.d);
19 | expect(Log.i, Log.logNoStack.i);
20 | expect(Log.w, Log.log.w);
21 | expect(Log.e, Log.log.e);
22 | expect(Log.c, Log.log.wtf);
23 |
24 | expect(Log.getLevel(), logger.Level.verbose);
25 |
26 | const levels = [
27 | 'verbose',
28 | 'debug',
29 | 'info',
30 | 'warning',
31 | 'error',
32 | 'critical'
33 | ];
34 |
35 | levels.asMap().forEach((index, level) {
36 | Log.level = level;
37 |
38 | expect(Log.getLevel(), logger.Level.values[index]);
39 | });
40 |
41 | Log.level = 'unsupported-level';
42 |
43 | expect(Log.getLevel(), logger.Level.verbose);
44 | });
45 | });
46 | }
47 |
--------------------------------------------------------------------------------
/test/core/utils/widgets_test.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_test/flutter_test.dart';
9 | import 'package:vtime/core/utils/widgets.dart';
10 | import 'package:vtime/core/vt.dart';
11 |
12 | class TestStatelessWidget extends VTStatelessWidget {
13 | TestStatelessWidget({Key? key}) : super(key: key);
14 |
15 | @override
16 | noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
17 | }
18 |
19 | class TestStatefulWidget extends VTStatefulWidget {
20 | TestStatefulWidget({Key? key}) : super(key: key);
21 | @override
22 | noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
23 | }
24 |
25 | class TestLomsaState extends VTStatefulWidget {
26 | TestLomsaState({Key? key}) : super(key: key);
27 |
28 | @override
29 | noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
30 | }
31 |
32 | void main() {
33 | late VTStatelessWidget testStateless;
34 | late VTStatefulWidget testStatefull;
35 | late VTStatefulWidget testState;
36 |
37 | late VT vt;
38 |
39 | setUpAll(() {
40 | testStateless = TestStatelessWidget();
41 | testStatefull = TestStatefulWidget();
42 | testState = TestLomsaState();
43 |
44 | vt = VT();
45 | });
46 |
47 | test('Check if vt singleton exists', () async {
48 | expect(vt, testStateless.vt);
49 | expect(vt, testStatefull.vt);
50 | expect(vt, testState.vt);
51 | });
52 | }
53 |
--------------------------------------------------------------------------------
/test/core/vt_test.dart:
--------------------------------------------------------------------------------
1 | //
2 | // This source code is distributed under the terms of Bad Code License.
3 | // You are forbidden from distributing software containing this code to
4 | // end users, because it is bad.
5 | //
6 |
7 | import 'package:flutter_test/flutter_test.dart';
8 | import 'package:vtime/core/services/local_db_service.dart';
9 | import 'package:vtime/core/utils/intl.dart';
10 | import 'package:vtime/core/vt.dart';
11 |
12 | void main() {
13 | VT? vt;
14 |
15 | setUpAll(() => vt = VT());
16 |
17 | group('VT', () {
18 | test('is a singleton', () {
19 | expect(vt.hashCode, VT().hashCode);
20 | });
21 |
22 | test('has expected default property values', () {
23 | expect(vt, isA());
24 | expect(vt?.instances.isEmpty, true);
25 | expect(vt.runtimeType, VT);
26 | });
27 |
28 | test('has expected property and preference setting behavior', () {
29 | vt?.intl = Intl();
30 | vt?.localDbService = LocalDBService();
31 |
32 | expect(vt?.instances.isNotEmpty, true);
33 | expect(vt?.localDbService, isNotNull);
34 | expect(vt?.intl, isNotNull);
35 | });
36 | });
37 | }
38 |
--------------------------------------------------------------------------------
/vtime.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theiskaa/Visual-Time/42ced07db2d0c89f03191bec1d58afc6b4a78f57/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | vtime
27 |
28 |
29 |
30 |
33 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vtime",
3 | "short_name": "vtime",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "An advanced time management application",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------