├── .github
└── workflows
│ └── release.yaml
├── .gitignore
├── .metadata
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── analog_clock
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── fonts
│ └── Lato-Regular.ttf
└── icons
│ ├── Liberty.svg
│ ├── Moon.svg
│ ├── Settings.svg
│ ├── Sun.svg
│ ├── Sydney.svg
│ ├── clock.svg
│ ├── stop_watch.svg
│ ├── watch_2.svg
│ └── world.svg
├── 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
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── 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
└── RunnerTests
│ └── RunnerTests.swift
├── lib
├── main.dart
└── src
│ ├── app.dart
│ ├── models
│ └── my_theme_provider.dart
│ ├── pages
│ ├── alarm
│ │ ├── alarm_page.dart
│ │ ├── controllers
│ │ │ └── alarm_controller.dart
│ │ └── widgets
│ │ │ └── list_alarm.dart
│ ├── bedtime
│ │ ├── bed_time_page.dart
│ │ └── widgets
│ │ │ └── pick_day.dart
│ ├── countdown
│ │ ├── controllers
│ │ │ └── count_down_controller.dart
│ │ ├── count_down_page.dart
│ │ └── widgets
│ │ │ ├── count_controll.dart
│ │ │ └── pick_time.dart
│ ├── global
│ │ ├── controllers
│ │ │ └── clock_controller.dart
│ │ ├── global_page.dart
│ │ └── widgets
│ │ │ ├── body.dart
│ │ │ ├── clock.dart
│ │ │ ├── clock_painter.dart
│ │ │ ├── country_card.dart
│ │ │ └── time_in_hour_and_minute.dart
│ ├── stopwatch
│ │ ├── controllers
│ │ │ └── stop_watch_controller.dart
│ │ ├── stop_watch_page.dart
│ │ └── widgets
│ │ │ ├── list_stop_watch.dart
│ │ │ └── stop_watch_controll.dart
│ └── tab
│ │ └── tab_bar_layout.dart
│ ├── public
│ ├── constants.dart
│ └── size_config.dart
│ ├── routes
│ ├── app_pages.dart
│ └── app_routes.dart
│ ├── shared
│ └── logger
│ │ └── logger_utils.dart
│ └── theme
│ ├── theme_service.dart
│ └── themes.dart
├── pubspec.lock
├── pubspec.yaml
├── screenshots
├── bed_dark.png
├── bed_light.png
├── clock_dark.png
├── clock_light.png
├── count_down_dark.png
├── count_down_light.png
├── stopwatch_dark.png
└── stopwatch_light.png
└── test
└── widget_test.dart
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Analyze, Build, Release APK
2 |
3 | on:
4 | push:
5 | tags:
6 | - "v*"
7 |
8 | jobs:
9 | test:
10 | name: Analyze project
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v1
14 | - uses: actions/setup-java@v3
15 | with:
16 | distribution: "temurin"
17 | java-version: "17"
18 | cache: "gradle"
19 | - uses: shimataro/ssh-key-action@v2
20 | with:
21 | key: ${{ secrets.SSH }}
22 | name: id_rsa
23 | known_hosts: ${{ secrets.KNOWN_HOSTS }}
24 | - uses: subosito/flutter-action@v2
25 | with:
26 | flutter-version: "3.13.7"
27 | cache: true
28 | - run: flutter pub get
29 | - run: flutter analyze
30 | # - run: flutter test
31 |
32 | build_apk:
33 | needs: [test]
34 | name: Build & Release APK
35 | runs-on: ubuntu-latest
36 | steps:
37 | - uses: actions/checkout@v1
38 | - uses: actions/setup-java@v3
39 | with:
40 | distribution: "temurin"
41 | java-version: "17"
42 | cache: "gradle"
43 | - uses: shimataro/ssh-key-action@v2
44 | with:
45 | key: ${{ secrets.SSH }}
46 | name: id_rsa
47 | known_hosts: ${{ secrets.KNOWN_HOSTS }}
48 | - uses: subosito/flutter-action@v2
49 | with:
50 | flutter-version: "3.13.7"
51 | cache: true
52 | - run: flutter pub get
53 | - run: flutter build apk --release
54 | - name: Create a Release APK
55 | uses: ncipollo/release-action@v1
56 | with:
57 | name: "Analog Clock ${{ github.ref_name }}"
58 | artifacts: "build/app/outputs/apk/release/*.apk"
59 | token: ${{ secrets.TOKEN }}
60 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Exceptions to above rules.
44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
45 |
--------------------------------------------------------------------------------
/.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: "2f708eb8396e362e280fac22cf171c2cb467343c"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
17 | base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
18 | - platform: android
19 | create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
20 | base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
21 |
22 | # User provided section
23 |
24 | # List of Local paths (relative to this file) that should be
25 | # ignored by the migrate tool.
26 | #
27 | # Files that are not part of the templates will be ignored by default.
28 | unmanaged_files:
29 | - 'lib/main.dart'
30 | - 'ios/Runner.xcodeproj/project.pbxproj'
31 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | lambiengcode@gmail.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Dao Hong Vinh
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 | # Analog Clock Light & Dark Theme 🕚 📆
2 |
3 | ## Description:
4 | - We design a nice clean analog clock app UI by using flutter. Our clock supports both the Dark and Light theme. If you want to learn how to use both Light and Dark theme then it helps a lot.
5 |
6 | ## How I can run it?
7 | - 🚀 Clone this repo
8 | - 🚀 Run below code in terminal of project
9 | ```terminal
10 | flutter pub get
11 | flutter run
12 | ```
13 |
14 | ## Author:
15 | - Primary Author: Flutter Way
16 | - Customize by lambiengcode
17 |
18 | ## Screenshots
19 |
20 | - Light Mode 🌞
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | - Dark Mode 🌙
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | analyzer:
13 | exclude:
14 | - "lib/**/*.freezed.dart"
15 | - "lib/**/*.g.dart"
16 | - "lib/**/*.config.dart"
17 | plugins:
18 | - dart_code_metrics
19 |
20 | linter:
21 | # The lint rules applied to this project can be customized in the
22 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
23 | # included above or to enable additional rules. A list of all available lints
24 | # and their documentation is published at
25 | # https://dart-lang.github.io/linter/lints/index.html.
26 | #
27 | # Instead of disabling a lint rule for the entire project in the
28 | # section below, it can also be suppressed for a single line of code
29 | # or a specific dart file by using the `// ignore: name_of_lint` and
30 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
31 | # producing the lint.
32 | rules:
33 | require_trailing_commas: true
34 | prefer_final_locals: true
35 | prefer_final_in_for_each: true
36 | null_check_on_nullable_type_parameter: true
37 | avoid_function_literals_in_foreach_calls: true
38 | avoid_relative_lib_imports: true
39 | always_use_package_imports: true
40 | avoid_types_on_closure_parameters: true
41 | avoid_void_async: true
42 | cancel_subscriptions: true
43 | close_sinks: true
44 | package_api_docs: true
45 | package_prefixed_library_names: true
46 | test_types_in_equals: true
47 | throw_in_finally: true
48 | unnecessary_statements: true
49 | use_super_parameters: true
50 | avoid_dynamic_calls: false
51 | avoid_slow_async_io: true
52 | no_duplicate_case_values: true
53 | use_build_context_synchronously: true
54 | valid_regexps: true
55 | depend_on_referenced_packages: true
56 | always_require_non_null_named_parameters: true
57 | annotate_overrides: true
58 | avoid_annotating_with_dynamic: true
59 | avoid_bool_literals_in_conditional_expressions: true
60 | avoid_catches_without_on_clauses: false
61 | avoid_catching_errors: false
62 | avoid_classes_with_only_static_members: false
63 | avoid_double_and_int_checks: true
64 | avoid_escaping_inner_quotes: true
65 | avoid_field_initializers_in_const_classes: true
66 | avoid_init_to_null: true
67 | avoid_null_checks_in_equality_operators: true
68 | # Need for LINT
69 | avoid_positional_boolean_parameters: false
70 | avoid_private_typedef_functions: true
71 | avoid_redundant_argument_values: true
72 | avoid_returning_null_for_void: true
73 | avoid_shadowing_type_parameters: true
74 | avoid_single_cascade_in_expression_statements: true
75 | avoid_unnecessary_containers: true
76 | await_only_futures: true
77 | cast_nullable_to_non_nullable: false
78 | combinators_ordering: true
79 | conditional_uri_does_not_exist: true
80 | enable_null_safety: true
81 | eol_at_end_of_file: true
82 | exhaustive_cases: true
83 | prefer_is_empty: true
84 | prefer_is_not_empty: true
85 | prefer_is_not_operator: true
86 | prefer_iterable_whereType: true
87 | prefer_null_aware_method_calls: true
88 | prefer_null_aware_operators: true
89 | prefer_spread_collections: true
90 | sized_box_for_whitespace: true
91 | sized_box_shrink_expand: true
92 | unnecessary_null_checks: true
93 | unnecessary_null_in_if_null_operators: true
94 | unnecessary_overrides: true
95 | unnecessary_parenthesis: true
96 | unnecessary_raw_strings: true
97 | unnecessary_string_interpolations: true
98 | unnecessary_this: true
99 | unnecessary_to_list_in_spreads: true
100 | unreachable_from_main: true
101 | use_colored_box: true
102 | use_enums: true
103 | use_full_hex_values_for_flutter_colors: true
104 | use_if_null_to_convert_nulls_to_bools: true
105 | use_is_even_rather_than_modulo: true
106 | use_named_constants: true
107 | use_raw_strings: true
108 | use_setters_to_change_properties: true
109 | use_string_buffers: false
110 | use_test_throws_matchers: true
111 | use_to_and_as_if_applicable: true
112 | void_checks: true
113 |
114 | # Pub rules
115 | secure_pubspec_urls: true
116 |
117 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
118 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
119 | # Additional information about this file can be found at
120 | # https://dart.dev/guides/language/analysis-options
121 |
122 | dart_code_metrics:
123 | # anti-patterns:
124 | # - long-method
125 | # - long-parameter-list
126 | metrics:
127 | cyclomatic-complexity: 20
128 | maximum-nesting-level: 5
129 | number-of-parameters: 10
130 | source-lines-of-code: 50
131 | metrics-exclude:
132 | - test/**
133 | rules:
134 | # - newline-before-return:
135 | # severity: style
136 | - no-boolean-literal-compare:
137 | severity: style
138 | # - no-empty-block:
139 | # severity: warning
140 | # - prefer-trailing-comma:
141 | # severity: none
142 | # - prefer-conditional-expressions:
143 | # severity: none
144 | - no-equal-then-else:
145 | severity: error
146 |
--------------------------------------------------------------------------------
/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 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.android.application"
3 | id "kotlin-android"
4 | id "dev.flutter.flutter-gradle-plugin"
5 | }
6 |
7 | def localProperties = new Properties()
8 | def localPropertiesFile = rootProject.file('local.properties')
9 | if (localPropertiesFile.exists()) {
10 | localPropertiesFile.withReader('UTF-8') { reader ->
11 | localProperties.load(reader)
12 | }
13 | }
14 |
15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
16 | if (flutterVersionCode == null) {
17 | flutterVersionCode = '1'
18 | }
19 |
20 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
21 | if (flutterVersionName == null) {
22 | flutterVersionName = '1.0'
23 | }
24 |
25 | android {
26 | namespace "com.example.analog_clock"
27 | compileSdkVersion flutter.compileSdkVersion
28 | ndkVersion flutter.ndkVersion
29 |
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 |
35 | kotlinOptions {
36 | jvmTarget = '1.8'
37 | }
38 |
39 | sourceSets {
40 | main.java.srcDirs += 'src/main/kotlin'
41 | }
42 |
43 | defaultConfig {
44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
45 | applicationId "com.example.analog_clock"
46 | // You can update the following values to match your application needs.
47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
48 | minSdkVersion flutter.minSdkVersion
49 | targetSdkVersion flutter.targetSdkVersion
50 | versionCode flutterVersionCode.toInteger()
51 | versionName flutterVersionName
52 | }
53 |
54 | buildTypes {
55 | release {
56 | // TODO: Add your own signing config for the release build.
57 | // Signing with the debug keys for now, so `flutter run --release` works.
58 | signingConfig signingConfigs.debug
59 | }
60 | }
61 | }
62 |
63 | flutter {
64 | source '../..'
65 | }
66 |
67 | dependencies {}
68 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
14 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/analog_clock/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.analog_clock
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.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 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.7.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.3.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | tasks.register("clean", Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | plugins {
14 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
15 | }
16 | }
17 |
18 | include ":app"
19 |
20 | apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"
21 |
--------------------------------------------------------------------------------
/assets/fonts/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/assets/fonts/Lato-Regular.ttf
--------------------------------------------------------------------------------
/assets/icons/Liberty.svg:
--------------------------------------------------------------------------------
1 | Liberty
--------------------------------------------------------------------------------
/assets/icons/Moon.svg:
--------------------------------------------------------------------------------
1 | Moon
--------------------------------------------------------------------------------
/assets/icons/Settings.svg:
--------------------------------------------------------------------------------
1 | Settings
--------------------------------------------------------------------------------
/assets/icons/Sun.svg:
--------------------------------------------------------------------------------
1 | Sun
--------------------------------------------------------------------------------
/assets/icons/Sydney.svg:
--------------------------------------------------------------------------------
1 | Sydney
--------------------------------------------------------------------------------
/assets/icons/clock.svg:
--------------------------------------------------------------------------------
1 | Group 5
--------------------------------------------------------------------------------
/assets/icons/stop_watch.svg:
--------------------------------------------------------------------------------
1 | Group 4
--------------------------------------------------------------------------------
/assets/icons/watch_2.svg:
--------------------------------------------------------------------------------
1 | Shape
--------------------------------------------------------------------------------
/assets/icons/world.svg:
--------------------------------------------------------------------------------
1 | Shape
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/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 | 11.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, '11.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 | target 'RunnerTests' do
36 | inherit! :search_paths
37 | end
38 | end
39 |
40 | post_install do |installer|
41 | installer.pods_project.targets.each do |target|
42 | flutter_additional_ios_build_settings(target)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - path_provider_foundation (0.0.1):
4 | - Flutter
5 | - FlutterMacOS
6 |
7 | DEPENDENCIES:
8 | - Flutter (from `Flutter`)
9 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
10 |
11 | EXTERNAL SOURCES:
12 | Flutter:
13 | :path: Flutter
14 | path_provider_foundation:
15 | :path: ".symlinks/plugins/path_provider_foundation/darwin"
16 |
17 | SPEC CHECKSUMS:
18 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
19 | path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
20 |
21 | PODFILE CHECKSUM: 70d9d25280d0dd177a5f637cdb0f0b0b12c6a189
22 |
23 | COCOAPODS: 1.12.1
24 |
--------------------------------------------------------------------------------
/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 |
37 |
38 |
39 |
40 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/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 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/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/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/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 | CFBundleDisplayName
8 | Analog Clock
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | analog_clock
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | CADisableMinimumFrameDurationOnPhone
45 |
46 | UIApplicationSupportsIndirectInputEvents
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/ios/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 | import 'package:get_storage/get_storage.dart';
7 |
8 | // Project imports:
9 | import 'package:analog_clock/src/routes/app_pages.dart';
10 | import 'package:analog_clock/src/shared/logger/logger_utils.dart';
11 | import 'package:analog_clock/src/theme/theme_service.dart';
12 | import 'package:analog_clock/src/theme/themes.dart';
13 |
14 | void main() async {
15 | await GetStorage.init();
16 | runApp(
17 | GetMaterialApp(
18 | debugShowCheckedModeBanner: false,
19 | logWriterCallback: Logger.write,
20 | initialRoute: AppPages.rootRoute,
21 | getPages: AppPages.routes,
22 | theme: Themes().lightTheme,
23 | darkTheme: Themes().darkTheme,
24 | themeMode: ThemeService().getThemeMode(),
25 | ),
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/app.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/services.dart';
4 |
5 | // Project imports:
6 | import 'package:analog_clock/src/pages/tab/tab_bar_layout.dart';
7 | import 'package:analog_clock/src/theme/theme_service.dart';
8 |
9 | class App extends StatefulWidget {
10 | const App({super.key});
11 |
12 | @override
13 | State createState() => _AppState();
14 | }
15 |
16 | class _AppState extends State with WidgetsBindingObserver {
17 | @override
18 | void initState() {
19 | WidgetsBinding.instance.addObserver(this);
20 | SystemChrome.setPreferredOrientations([
21 | DeviceOrientation.portraitDown,
22 | DeviceOrientation.portraitUp,
23 | ]);
24 | ThemeService().initBrighness();
25 | super.initState();
26 | }
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | return const TabBarLayout();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/src/models/my_theme_provider.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | class MyThemeModel extends ChangeNotifier {
5 | bool _isLightTheme = true;
6 |
7 | void changeTheme() {
8 | _isLightTheme = !_isLightTheme;
9 | notifyListeners();
10 | }
11 |
12 | bool get isLightTheme => _isLightTheme;
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/pages/alarm/alarm_page.dart:
--------------------------------------------------------------------------------
1 | // Package imports:
2 | import 'package:flutter_neumorphic_plus/flutter_neumorphic.dart';
3 | import 'package:get/get.dart';
4 | import 'package:percent_indicator/percent_indicator.dart';
5 |
6 | // Project imports:
7 | import 'package:analog_clock/src/pages/alarm/controllers/alarm_controller.dart';
8 | import 'package:analog_clock/src/pages/alarm/widgets/list_alarm.dart';
9 | import 'package:analog_clock/src/public/constants.dart';
10 |
11 | class AlarmPage extends StatefulWidget {
12 | const AlarmPage({super.key});
13 |
14 | @override
15 | State createState() => _AlarmPageState();
16 | }
17 |
18 | class _AlarmPageState extends State {
19 | final alarmController = Get.put(AlarmController());
20 |
21 | @override
22 | void initState() {
23 | alarmController.startTimer();
24 | super.initState();
25 | }
26 |
27 | @override
28 | void dispose() {
29 | alarmController.stopTimer();
30 | super.dispose();
31 | }
32 |
33 | @override
34 | Widget build(BuildContext context) {
35 | return Scaffold(
36 | body: SizedBox(
37 | width: width,
38 | child: Stack(
39 | children: [
40 | SizedBox.expand(
41 | child: Column(
42 | children: [
43 | const SizedBox(height: 16.0),
44 | StreamBuilder(
45 | stream: alarmController.currentTime.stream,
46 | builder: (context, snapshot) {
47 | if (!snapshot.hasData) {
48 | return _buildClock(DateTime.now());
49 | }
50 |
51 | return _buildClock(snapshot.data!);
52 | },
53 | ),
54 | const Expanded(
55 | child: ListAlarm(),
56 | ),
57 | const SizedBox(height: 12.0),
58 | ],
59 | ),
60 | ),
61 | Positioned(
62 | bottom: height * .045,
63 | left: 0.0,
64 | right: 0.0,
65 | child: Row(
66 | mainAxisAlignment: MainAxisAlignment.center,
67 | children: [
68 | NeumorphicButton(
69 | onPressed: () {},
70 | duration: const Duration(milliseconds: 200),
71 | padding: EdgeInsets.all(width / 22.5),
72 | style: NeumorphicStyle(
73 | shape: NeumorphicShape.convex,
74 | boxShape: const NeumorphicBoxShape.circle(),
75 | depth: 10.0,
76 | intensity: .15,
77 | surfaceIntensity: .75,
78 | color: Theme.of(context)
79 | .scaffoldBackgroundColor
80 | .withOpacity(.8),
81 | ),
82 | child: Icon(
83 | Icons.add,
84 | size: width / 12.0,
85 | ),
86 | ),
87 | ],
88 | ),
89 | ),
90 | ],
91 | ),
92 | ),
93 | );
94 | }
95 |
96 | Widget _buildClock(DateTime dateTime) {
97 | return CircularPercentIndicator(
98 | radius: width * .45,
99 | lineWidth: 60.0,
100 | percent: alarmController.percent,
101 | circularStrokeCap: CircularStrokeCap.round,
102 | backgroundColor: Theme.of(context).colorScheme.secondary,
103 | linearGradient: LinearGradient(
104 | begin: Alignment.topLeft,
105 | end: Alignment.bottomCenter,
106 | colors: [
107 | Theme.of(context).primaryColor,
108 | Theme.of(context).secondaryHeaderColor,
109 | ],
110 | tileMode: TileMode.mirror,
111 | ),
112 | animationDuration: 1000,
113 | animateFromLastPercent: true,
114 | rotateLinearGradient: true,
115 | center: Column(
116 | mainAxisAlignment: MainAxisAlignment.center,
117 | children: [
118 | Text(
119 | '${alarmController.formatTime(dateTime.hour)}:${alarmController.formatTime(dateTime.minute)}:${alarmController.formatTime(dateTime.second)}',
120 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
121 | fontSize: width / 10.0,
122 | fontFamily: 'Lato',
123 | fontWeight: FontWeight.w400,
124 | ),
125 | ),
126 | const SizedBox(height: 2.0),
127 | Text(
128 | 'The alarm will continue\nin 3 hours',
129 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
130 | fontSize: width / 26.0,
131 | fontFamily: 'Lato',
132 | fontWeight: FontWeight.w400,
133 | color: Theme.of(context).iconTheme.color,
134 | ),
135 | textAlign: TextAlign.center,
136 | ),
137 | ],
138 | ),
139 | );
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/lib/src/pages/alarm/controllers/alarm_controller.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:async';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 |
7 | // Package imports:
8 | import 'package:get/get.dart';
9 |
10 | class AlarmController extends GetxController {
11 | StreamController currentTime =
12 | StreamController.broadcast();
13 | ScrollController scrollController = ScrollController();
14 | Timer? timer;
15 | double percent = .0;
16 | bool isRunning = false;
17 | List dateTimes = [];
18 |
19 | formatTime(input) {
20 | if (input < 10) {
21 | return '0$input';
22 | }
23 | return input.toString();
24 | }
25 |
26 | startTimer() {
27 | isRunning = true;
28 | // <---> virtual data
29 | dateTimes.add(DateTime.now().add(const Duration(hours: 3)));
30 | dateTimes.add(DateTime.now().add(const Duration(hours: 4)));
31 | dateTimes.add(DateTime.now().add(const Duration(hours: 5)));
32 | dateTimes.add(DateTime.now().add(const Duration(hours: 7)));
33 | // <---> virtual data
34 | update();
35 | timer = Timer.periodic(const Duration(milliseconds: 17), (timer) {
36 | currentTime.add(DateTime.now());
37 | percent = DateTime.now().second / 60.0;
38 | update();
39 | });
40 | }
41 |
42 | stopTimer() {
43 | timer?.cancel();
44 | isRunning = false;
45 | update();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/src/pages/alarm/widgets/list_alarm.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 | import 'package:intl/intl.dart';
7 |
8 | // Project imports:
9 | import 'package:analog_clock/src/pages/alarm/controllers/alarm_controller.dart';
10 | import 'package:analog_clock/src/public/constants.dart';
11 |
12 | class ListAlarm extends StatefulWidget {
13 | const ListAlarm({super.key});
14 |
15 | @override
16 | State createState() => _ListAlarmState();
17 | }
18 |
19 | class _ListAlarmState extends State {
20 | DateFormat format = DateFormat('HH:mm:ss');
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return GetBuilder(
25 | builder: (_) => ListView.builder(
26 | controller: _.scrollController,
27 | padding: EdgeInsets.zero,
28 | itemCount: _.dateTimes.length,
29 | itemBuilder: (context, index) {
30 | return Container(
31 | padding: const EdgeInsets.symmetric(
32 | horizontal: 24.0,
33 | vertical: 12.0,
34 | ),
35 | child: Row(
36 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
37 | children: [
38 | Column(
39 | crossAxisAlignment: CrossAxisAlignment.start,
40 | mainAxisAlignment: MainAxisAlignment.center,
41 | children: [
42 | Text(
43 | 'Alarm: ${index + 1}',
44 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
45 | fontSize: width / 24.0,
46 | fontFamily: 'Lato',
47 | fontWeight: FontWeight.w600,
48 | ),
49 | ),
50 | const SizedBox(height: 8.0),
51 | Text(
52 | '${format.format(_.dateTimes[index])},\t\tAlarm Daily',
53 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
54 | fontSize: width / 24.0,
55 | fontFamily: 'Lato',
56 | fontWeight: FontWeight.w400,
57 | color: Theme.of(context)
58 | .textTheme
59 | .displayLarge
60 | ?.color
61 | ?.withOpacity(.8),
62 | ),
63 | ),
64 | ],
65 | ),
66 | Icon(
67 | Icons.alarm,
68 | size: width / 16.0,
69 | ),
70 | ],
71 | ),
72 | );
73 | },
74 | ),
75 | );
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/lib/src/pages/bedtime/bed_time_page.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:math';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 |
7 | // Package imports:
8 | import 'package:flutter_phosphor_icons/flutter_phosphor_icons.dart';
9 | import 'package:get/get.dart';
10 | import 'package:percent_indicator/circular_percent_indicator.dart';
11 |
12 | // Project imports:
13 | import 'package:analog_clock/src/pages/bedtime/widgets/pick_day.dart';
14 | import 'package:analog_clock/src/pages/global/controllers/clock_controller.dart';
15 | import 'package:analog_clock/src/pages/global/widgets/clock_painter.dart';
16 | import 'package:analog_clock/src/public/constants.dart';
17 | import 'package:analog_clock/src/public/size_config.dart';
18 | import 'package:analog_clock/src/theme/theme_service.dart';
19 |
20 | class BedTimePage extends StatefulWidget {
21 | const BedTimePage({super.key});
22 |
23 | @override
24 | State createState() => _BedTimePageState();
25 | }
26 |
27 | class _BedTimePageState extends State {
28 | final clockController = Get.put(ClockController());
29 | bool isOn = true;
30 |
31 | @override
32 | void initState() {
33 | clockController.startTimer();
34 | super.initState();
35 | }
36 |
37 | @override
38 | void dispose() {
39 | clockController.dispose();
40 | super.dispose();
41 | }
42 |
43 | toggle() {
44 | setState(() {
45 | isOn = !isOn;
46 | });
47 | }
48 |
49 | @override
50 | Widget build(BuildContext context) {
51 | return Column(
52 | children: [
53 | _buildTitle(context),
54 | const Spacer(),
55 | const PickDay(),
56 | const Spacer(flex: 2),
57 | Stack(
58 | alignment: Alignment.center,
59 | children: [
60 | CircularPercentIndicator(
61 | radius: width * .45,
62 | lineWidth: 35.0,
63 | percent: .5,
64 | circularStrokeCap: CircularStrokeCap.round,
65 | backgroundColor: Theme.of(context).colorScheme.secondary,
66 | linearGradient: LinearGradient(
67 | begin: Alignment.topLeft,
68 | end: Alignment.bottomCenter,
69 | colors: [
70 | Theme.of(context).primaryColor,
71 | Theme.of(context).secondaryHeaderColor,
72 | ],
73 | tileMode: TileMode.mirror,
74 | ),
75 | animationDuration: 2000,
76 | animateFromLastPercent: true,
77 | rotateLinearGradient: true,
78 | center: StreamBuilder(
79 | stream: clockController.currentDay.stream,
80 | builder: (context, snapshot) {
81 | if (!snapshot.hasData) {
82 | return _buildClock(context, DateTime.now());
83 | }
84 |
85 | return _buildClock(context, snapshot.data);
86 | },
87 | ),
88 | ),
89 | Positioned(
90 | top: width * .45 - 5,
91 | left: 0,
92 | right: 0,
93 | child: IconButton(
94 | icon: Icon(
95 | ThemeService().getThemeMode() == ThemeMode.dark
96 | ? PhosphorIcons.moon
97 | : PhosphorIcons.sun,
98 | color: Theme.of(context).primaryColor,
99 | size: getProportionateScreenWidth(26),
100 | ),
101 | onPressed: () => ThemeService().changeThemeMode(),
102 | ),
103 | ),
104 | Positioned(
105 | top: 35 / 2 + 8,
106 | left: 0,
107 | right: 0,
108 | child: Icon(
109 | Icons.power_settings_new_sharp,
110 | color: Colors.white,
111 | size: width / 16.0,
112 | ),
113 | ),
114 | Positioned(
115 | bottom: 35 / 2 + 6,
116 | left: 0,
117 | right: 0,
118 | child: Icon(
119 | Icons.notifications_active_outlined,
120 | color: Colors.white,
121 | size: width / 16.0,
122 | ),
123 | ),
124 | ],
125 | ),
126 | const Spacer(flex: 2),
127 | Row(
128 | mainAxisAlignment: MainAxisAlignment.spaceAround,
129 | children: [
130 | _buildBottomTime(
131 | context,
132 | '00:00',
133 | 'Bedtime',
134 | Icons.power_settings_new_sharp,
135 | ),
136 | _buildBottomTime(
137 | context,
138 | '06:00',
139 | 'Wakeup',
140 | Icons.notifications_active,
141 | ),
142 | ],
143 | ),
144 | const Spacer(flex: 3),
145 | ],
146 | );
147 | }
148 |
149 | Widget _buildTitle(context) {
150 | return Padding(
151 | padding: const EdgeInsets.only(left: 16.0, right: 8.0),
152 | child: Row(
153 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
154 | children: [
155 | Text(
156 | 'Bedtime Schedule',
157 | style: TextStyle(
158 | color: Theme.of(context).colorScheme.secondary,
159 | fontFamily: 'Lato',
160 | fontSize: width / 21.5,
161 | fontWeight: FontWeight.w600,
162 | ),
163 | ),
164 | Switch(
165 | activeColor: Theme.of(context).primaryColor,
166 | value: isOn,
167 | onChanged: (val) {
168 | toggle();
169 | },
170 | ),
171 | ],
172 | ),
173 | );
174 | }
175 |
176 | Widget _buildClock(context, dateTime) {
177 | return Padding(
178 | padding: EdgeInsets.symmetric(
179 | horizontal: 35 + width * .05,
180 | ),
181 | child: AspectRatio(
182 | aspectRatio: 1,
183 | child: Container(
184 | decoration: BoxDecoration(
185 | color: Theme.of(context).colorScheme.surface,
186 | shape: BoxShape.circle,
187 | boxShadow: [
188 | BoxShadow(
189 | color: kShadowColor.withOpacity(0.14),
190 | blurRadius: 64,
191 | ),
192 | ],
193 | ),
194 | child: Transform.rotate(
195 | angle: -pi / 2,
196 | child: CustomPaint(
197 | painter: ClockPainter(context, dateTime),
198 | ),
199 | ),
200 | ),
201 | ),
202 | );
203 | }
204 |
205 | Widget _buildBottomTime(context, time, title, icon) {
206 | return Column(
207 | children: [
208 | Text(
209 | time,
210 | style: TextStyle(
211 | color: Theme.of(context).textTheme.bodyLarge?.color,
212 | fontFamily: 'Lato',
213 | fontSize: width / 12.5,
214 | fontWeight: FontWeight.w600,
215 | ),
216 | ),
217 | const SizedBox(height: 8.0),
218 | Text(
219 | title,
220 | style: TextStyle(
221 | color: Theme.of(context).primaryColor,
222 | fontFamily: 'Lato',
223 | fontSize: width / 25.0,
224 | fontWeight: FontWeight.w600,
225 | ),
226 | ),
227 | const SizedBox(height: 6.0),
228 | Icon(
229 | icon,
230 | color: Theme.of(context).primaryColor,
231 | size: width / 14.0,
232 | ),
233 | ],
234 | );
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/lib/src/pages/bedtime/widgets/pick_day.dart:
--------------------------------------------------------------------------------
1 | // Package imports:
2 | import 'package:flutter_neumorphic_plus/flutter_neumorphic.dart';
3 |
4 | // Project imports:
5 | import 'package:analog_clock/src/public/constants.dart';
6 |
7 | class PickDay extends StatefulWidget {
8 | const PickDay({super.key});
9 |
10 | @override
11 | State createState() => _PickDayState();
12 | }
13 |
14 | class _PickDayState extends State {
15 | List values = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
16 | List picked = List.generate(7, (index) => index < 3);
17 |
18 | pickDay(index) {
19 | setState(() {
20 | picked[index] = !picked[index];
21 | });
22 | }
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return Container(
27 | padding: const EdgeInsets.symmetric(horizontal: 10.0),
28 | child: Row(
29 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
30 | children: [
31 | _buildAction(context, 0),
32 | _buildAction(context, 1),
33 | _buildAction(context, 2),
34 | _buildAction(context, 3),
35 | _buildAction(context, 4),
36 | _buildAction(context, 5),
37 | _buildAction(context, 6),
38 | ],
39 | ),
40 | );
41 | }
42 |
43 | Widget _buildAction(context, index) {
44 | return Container(
45 | height: width / 8,
46 | width: width / 8,
47 | alignment: Alignment.center,
48 | child: NeumorphicButton(
49 | onPressed: () => pickDay(index),
50 | style: NeumorphicStyle(
51 | shape: NeumorphicShape.convex,
52 | boxShape: const NeumorphicBoxShape.circle(),
53 | depth: 6.0,
54 | intensity: .25,
55 | color: picked[index]
56 | ? Theme.of(context).primaryColor
57 | : Theme.of(context).colorScheme.secondary,
58 | ),
59 | child: Text(
60 | values[index],
61 | style: Theme.of(context).textTheme.displayMedium?.copyWith(
62 | fontSize: width / 23.0,
63 | fontFamily: 'Lato',
64 | fontWeight: FontWeight.w400,
65 | ),
66 | ),
67 | ),
68 | );
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/src/pages/countdown/controllers/count_down_controller.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:async';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 |
7 | class CountDownController extends GetxController {
8 | StreamController currentTime =
9 | StreamController.broadcast();
10 | int hour = 0, minute = 0, second = 0;
11 | double percent = .0;
12 | bool isRunning = false;
13 | DateTime dateTime = DateTime(0, 0, 0);
14 | Timer? timer;
15 |
16 | formatTime(input) {
17 | if (input < 10) {
18 | return '0$input';
19 | }
20 | return input.toString();
21 | }
22 |
23 | play() {
24 | if ([hour, minute, second].join() != '000') {
25 | isRunning ? stopTimer() : startTimer();
26 | }
27 | }
28 |
29 | updateTime(h, m, s) {
30 | hour = h;
31 | minute = m;
32 | second = s;
33 | dateTime = DateTime(0, 0, 0, h, m, s);
34 | currentTime.add(dateTime);
35 | update();
36 | }
37 |
38 | startTimer() {
39 | isRunning = true;
40 | update();
41 | timer = Timer.periodic(const Duration(seconds: 1), (timer) {
42 | if (dateTime.hour == 0 && dateTime.minute == 0 && dateTime.second == 0) {
43 | stopTimer();
44 | } else {
45 | dateTime = dateTime.subtract(const Duration(seconds: 1));
46 | currentTime.add(dateTime);
47 | percent = 1.0 -
48 | ((dateTime.hour * 3600 + dateTime.minute * 60 + dateTime.second) /
49 | (hour * 3600 + minute * 60 + second));
50 | update();
51 | }
52 | });
53 | }
54 |
55 | stopTimer() {
56 | timer?.cancel();
57 | isRunning = false;
58 | update();
59 | }
60 |
61 | resetTime() {
62 | dateTime = DateTime(0, 0, 0, hour, minute, second);
63 | timer?.cancel();
64 | currentTime.add(dateTime);
65 | isRunning = false;
66 | update();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/lib/src/pages/countdown/count_down_page.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 | import 'package:percent_indicator/circular_percent_indicator.dart';
7 |
8 | // Project imports:
9 | import 'package:analog_clock/src/pages/countdown/controllers/count_down_controller.dart';
10 | import 'package:analog_clock/src/pages/countdown/widgets/count_controll.dart';
11 | import 'package:analog_clock/src/pages/countdown/widgets/pick_time.dart';
12 | import 'package:analog_clock/src/public/constants.dart';
13 |
14 | class CountDownPage extends StatefulWidget {
15 | const CountDownPage({super.key});
16 |
17 | @override
18 | State createState() => _CountDownPageState();
19 | }
20 |
21 | class _CountDownPageState extends State {
22 | final countDownController = Get.put(CountDownController());
23 |
24 | @override
25 | void initState() {
26 | super.initState();
27 | countDownController.updateTime(0, 0, 0);
28 | }
29 |
30 | @override
31 | void dispose() {
32 | countDownController.timer?.cancel();
33 | super.dispose();
34 | }
35 |
36 | @override
37 | Widget build(BuildContext context) {
38 | return Scaffold(
39 | body: SizedBox(
40 | child: Column(
41 | children: [
42 | const Spacer(flex: 4),
43 | StreamBuilder(
44 | stream: countDownController.currentTime.stream,
45 | builder: (context, snapshot) {
46 | if (!snapshot.hasData) {
47 | return _buildClock(DateTime(0, 0, 0));
48 | }
49 |
50 | return _buildClock(snapshot.data);
51 | },
52 | ),
53 | const Spacer(flex: 3),
54 | const PickTime(),
55 | const Spacer(flex: 2),
56 | const CountControll(),
57 | const Spacer(flex: 8),
58 | ],
59 | ),
60 | ),
61 | );
62 | }
63 |
64 | Widget _buildClock(dateTime) {
65 | return CircularPercentIndicator(
66 | radius: width * .45,
67 | lineWidth: 60.0,
68 | percent: countDownController.percent,
69 | circularStrokeCap: CircularStrokeCap.round,
70 | backgroundColor: Theme.of(context).colorScheme.secondary,
71 | linearGradient: LinearGradient(
72 | begin: Alignment.topLeft,
73 | end: Alignment.bottomCenter,
74 | colors: [
75 | Theme.of(context).primaryColor,
76 | Theme.of(context).secondaryHeaderColor,
77 | ],
78 | tileMode: TileMode.mirror,
79 | ),
80 | animationDuration: 1000,
81 | animateFromLastPercent: true,
82 | rotateLinearGradient: true,
83 | center: Center(
84 | child: Text(
85 | '${countDownController.formatTime(dateTime.hour)}:${countDownController.formatTime(dateTime.minute)}:${countDownController.formatTime(dateTime.second)}',
86 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
87 | fontSize: width / 10.0,
88 | fontFamily: 'Lato',
89 | fontWeight: FontWeight.w400,
90 | ),
91 | ),
92 | ),
93 | );
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/lib/src/pages/countdown/widgets/count_controll.dart:
--------------------------------------------------------------------------------
1 | // Package imports:
2 | import 'package:flutter_neumorphic_plus/flutter_neumorphic.dart';
3 | import 'package:get/get.dart';
4 |
5 | // Project imports:
6 | import 'package:analog_clock/src/pages/countdown/controllers/count_down_controller.dart';
7 | import 'package:analog_clock/src/public/constants.dart';
8 |
9 | class CountControll extends StatefulWidget {
10 | const CountControll({super.key});
11 |
12 | @override
13 | State createState() => _CountControllState();
14 | }
15 |
16 | class _CountControllState extends State {
17 | final countDownController = Get.put(CountDownController());
18 | @override
19 | Widget build(BuildContext context) {
20 | return GetBuilder(
21 | builder: (_) => Container(
22 | padding: const EdgeInsets.symmetric(horizontal: 24.0),
23 | child: Row(
24 | mainAxisAlignment: MainAxisAlignment.spaceAround,
25 | children: [
26 | IconButton(
27 | onPressed: () => _.resetTime(),
28 | icon: Icon(
29 | Icons.refresh,
30 | size: width / 12.0,
31 | ),
32 | ),
33 | NeumorphicButton(
34 | onPressed: () => _.play(),
35 | duration: const Duration(milliseconds: 200),
36 | padding: EdgeInsets.all(width / 22.5),
37 | style: NeumorphicStyle(
38 | shape: NeumorphicShape.convex,
39 | boxShape: const NeumorphicBoxShape.circle(),
40 | depth: 10.0,
41 | intensity: .18,
42 | surfaceIntensity: .5,
43 | color: Theme.of(context).scaffoldBackgroundColor,
44 | ),
45 | child: Icon(
46 | _.isRunning ? Icons.pause : Icons.play_arrow,
47 | size: width / 12.0,
48 | ),
49 | ),
50 | IconButton(
51 | onPressed: () {},
52 | icon: Icon(
53 | Icons.notifications,
54 | size: width / 12.0,
55 | ),
56 | ),
57 | ],
58 | ),
59 | ),
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/src/pages/countdown/widgets/pick_time.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 |
7 | // Project imports:
8 | import 'package:analog_clock/src/pages/countdown/controllers/count_down_controller.dart';
9 | import 'package:analog_clock/src/public/constants.dart';
10 |
11 | class PickTime extends StatefulWidget {
12 | const PickTime({super.key});
13 |
14 | @override
15 | State createState() => _PickTimeState();
16 | }
17 |
18 | class _PickTimeState extends State {
19 | List hours = List.generate(99, (index) => index);
20 | List minutes = List.generate(60, (index) => index);
21 | int hour = 0, minute = 0, second = 0;
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return SizedBox(
26 | height: height * .1,
27 | width: width,
28 | child: Row(
29 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
30 | children: [
31 | _buildColumnTime('Hour', hours, hour),
32 | _buildColumnTime('Minute', minutes, minute),
33 | _buildColumnTime('Second', minutes, second),
34 | ],
35 | ),
36 | );
37 | }
38 |
39 | Widget _buildColumnTime(title, List datas, value) {
40 | return SizedBox(
41 | width: width * .215,
42 | child: Column(
43 | children: [
44 | Padding(
45 | padding: const EdgeInsets.only(left: 38.0),
46 | child: GetBuilder(
47 | builder: (_) => DropdownButtonHideUnderline(
48 | child: DropdownButtonFormField(
49 | icon: const Icon(null),
50 | iconEnabledColor: Colors.grey.shade800,
51 | decoration: const InputDecoration(
52 | border: InputBorder.none,
53 | ),
54 | value: 0,
55 | style: TextStyle(
56 | fontSize: width / 28.5,
57 | fontWeight: FontWeight.w600,
58 | color: Theme.of(context).iconTheme.color,
59 | fontFamily: 'Lato',
60 | ),
61 | items: datas.map((data) {
62 | return DropdownMenuItem(
63 | value: data,
64 | child: Text(
65 | data.toString(),
66 | style: TextStyle(
67 | fontSize: width / 28.5,
68 | fontWeight: FontWeight.w600,
69 | color: Theme.of(context).iconTheme.color,
70 | fontFamily: 'Lato',
71 | ),
72 | textAlign: TextAlign.end,
73 | ),
74 | );
75 | }).toList(),
76 | onChanged: (val) {
77 | if (val == null || val is! int) return;
78 |
79 | setState(() {
80 | switch (title) {
81 | case "Hour":
82 | hour = val;
83 | break;
84 | case "Minute":
85 | minute = val;
86 | break;
87 | case "Second":
88 | second = val;
89 | break;
90 | }
91 | _.updateTime(hour, minute, second);
92 | });
93 | },
94 | ),
95 | ),
96 | ),
97 | ),
98 | const SizedBox(height: 12.0),
99 | Text(
100 | title,
101 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
102 | fontSize: width / 26.0,
103 | fontWeight: FontWeight.w500,
104 | color: Theme.of(context).iconTheme.color,
105 | ),
106 | textAlign: TextAlign.center,
107 | ),
108 | ],
109 | ),
110 | );
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/lib/src/pages/global/controllers/clock_controller.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:async';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 |
7 | // Package imports:
8 | import 'package:get/get.dart';
9 |
10 | class ClockController extends GetxController {
11 | StreamController currentDay =
12 | StreamController.broadcast();
13 | Timer? timer;
14 | TimeOfDay timeOfDay = TimeOfDay.now();
15 | String formatTime(int input) {
16 | if (input < 10) {
17 | return '0$input';
18 | }
19 | return input.toString();
20 | }
21 |
22 | startTimer() {
23 | timer = Timer.periodic(const Duration(seconds: 1), (timer) {
24 | currentDay.add(DateTime.now());
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/pages/global/global_page.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 |
7 | // Project imports:
8 | import 'package:analog_clock/src/pages/global/controllers/clock_controller.dart';
9 | import 'package:analog_clock/src/pages/global/widgets/body.dart';
10 | import 'package:analog_clock/src/public/size_config.dart';
11 |
12 | class GlobalPage extends StatefulWidget {
13 | const GlobalPage({super.key});
14 |
15 | @override
16 | State createState() => _GlobalPageState();
17 | }
18 |
19 | class _GlobalPageState extends State {
20 | final clockController = Get.put(ClockController());
21 |
22 | @override
23 | void initState() {
24 | super.initState();
25 | clockController.startTimer();
26 | }
27 |
28 | @override
29 | void dispose() {
30 | clockController.timer?.cancel();
31 | super.dispose();
32 | }
33 |
34 | @override
35 | Widget build(BuildContext context) {
36 | return Scaffold(
37 | body: StreamBuilder(
38 | stream: clockController.currentDay.stream,
39 | builder: (context, snapshot) {
40 | if (!snapshot.hasData) {
41 | return Body(
42 | dateTime: DateTime.now(),
43 | );
44 | }
45 |
46 | return Body(
47 | dateTime: snapshot.data!,
48 | );
49 | },
50 | ),
51 | );
52 | }
53 |
54 | Padding buildAddButton(BuildContext context) {
55 | return Padding(
56 | padding:
57 | EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(10)),
58 | child: InkWell(
59 | onTap: () {},
60 | child: Container(
61 | width: getProportionateScreenWidth(32),
62 | decoration: BoxDecoration(
63 | color: Theme.of(context).primaryColor,
64 | shape: BoxShape.circle,
65 | ),
66 | child: const Icon(
67 | Icons.add,
68 | color: Colors.white,
69 | ),
70 | ),
71 | ),
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/src/pages/global/widgets/body.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:intl/intl.dart';
6 |
7 | // Project imports:
8 | import 'package:analog_clock/src/pages/global/widgets/clock.dart';
9 | import 'package:analog_clock/src/pages/global/widgets/country_card.dart';
10 | import 'package:analog_clock/src/pages/global/widgets/time_in_hour_and_minute.dart';
11 | import 'package:analog_clock/src/public/constants.dart';
12 |
13 | class Body extends StatelessWidget {
14 | final DateTime dateTime;
15 | const Body({super.key, required this.dateTime});
16 | @override
17 | Widget build(BuildContext context) {
18 | final DateFormat format = DateFormat('hh:mm');
19 |
20 | return SizedBox(
21 | width: double.infinity,
22 | child: Column(
23 | children: [
24 | Text(
25 | "Ho Chi Minh, Viet Nam",
26 | style: Theme.of(context).textTheme.bodyLarge?.copyWith(
27 | fontFamily: 'Lato',
28 | fontWeight: FontWeight.w600,
29 | fontSize: width / 26.0,
30 | ),
31 | ),
32 | TimeInHourAndMinute(
33 | timeOfDay: TimeOfDay.fromDateTime(dateTime),
34 | showPeriod: true,
35 | ),
36 | const Spacer(),
37 | Clock(dateTime: dateTime),
38 | const Spacer(),
39 | SingleChildScrollView(
40 | scrollDirection: Axis.horizontal,
41 | child: Row(
42 | children: [
43 | CountryCard(
44 | country: "New York, USA",
45 | timeZone: "UTC -5 | EST",
46 | iconSrc: "assets/icons/Liberty.svg",
47 | time: format.format(
48 | DateTime.now().subtract(
49 | const Duration(hours: 11),
50 | ),
51 | ),
52 | period: "PM",
53 | ),
54 | CountryCard(
55 | country: "Sydney, AU",
56 | timeZone: "UTC +10 | AEST",
57 | iconSrc: "assets/icons/Sydney.svg",
58 | time: format.format(
59 | DateTime.now().add(
60 | const Duration(hours: 3),
61 | ),
62 | ),
63 | period: "AM",
64 | ),
65 | CountryCard(
66 | country: "HongKong, CN",
67 | timeZone: "UTC +8 | EA",
68 | iconSrc: "assets/icons/Sydney.svg",
69 | time: format.format(
70 | DateTime.now().add(
71 | const Duration(hours: 1),
72 | ),
73 | ),
74 | period: "AM",
75 | ),
76 | const SizedBox(width: 12.0),
77 | ],
78 | ),
79 | ),
80 | const SizedBox(height: 32.0),
81 | ],
82 | ),
83 | );
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/lib/src/pages/global/widgets/clock.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:math';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 |
7 | // Package imports:
8 | import 'package:flutter_phosphor_icons/flutter_phosphor_icons.dart';
9 |
10 | // Project imports:
11 | import 'package:analog_clock/src/pages/global/widgets/clock_painter.dart';
12 | import 'package:analog_clock/src/public/constants.dart';
13 | import 'package:analog_clock/src/public/size_config.dart';
14 | import 'package:analog_clock/src/theme/theme_service.dart';
15 |
16 | class Clock extends StatelessWidget {
17 | final DateTime dateTime;
18 | const Clock({super.key, required this.dateTime});
19 | @override
20 | Widget build(BuildContext context) {
21 | return Stack(
22 | children: [
23 | Padding(
24 | padding:
25 | EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(20)),
26 | child: AspectRatio(
27 | aspectRatio: 1,
28 | child: Container(
29 | decoration: BoxDecoration(
30 | color: Theme.of(context).colorScheme.surface,
31 | shape: BoxShape.circle,
32 | boxShadow: [
33 | BoxShadow(
34 | color: kShadowColor.withOpacity(0.14),
35 | blurRadius: 64,
36 | ),
37 | ],
38 | ),
39 | child: Transform.rotate(
40 | angle: -pi / 2,
41 | child: CustomPaint(
42 | painter: ClockPainter(context, dateTime),
43 | ),
44 | ),
45 | ),
46 | ),
47 | ),
48 | Positioned(
49 | top: height * .182,
50 | left: 0,
51 | right: 0,
52 | child: IconButton(
53 | icon: Icon(
54 | ThemeService().getThemeMode() == ThemeMode.dark
55 | ? PhosphorIcons.moon
56 | : PhosphorIcons.sun,
57 | color: Theme.of(context).primaryColor,
58 | size: getProportionateScreenWidth(26),
59 | ),
60 | onPressed: () => ThemeService().changeThemeMode(),
61 | ),
62 | ),
63 | ],
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/src/pages/global/widgets/clock_painter.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:math';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 |
7 | class ClockPainter extends CustomPainter {
8 | final BuildContext context;
9 | final DateTime dateTime;
10 |
11 | ClockPainter(this.context, this.dateTime);
12 |
13 | List clockOffset = [
14 | pi / 2,
15 | pi / 3,
16 | pi / 6,
17 | 0,
18 | -pi / 6,
19 | -pi / 3,
20 | -pi / 2,
21 | -2 * pi / 3,
22 | -5 * pi / 6,
23 | pi,
24 | 5 * pi / 6,
25 | 2 * pi / 3,
26 | ];
27 |
28 | @override
29 | void paint(Canvas canvas, Size size) {
30 | final double centerX = size.width / 2;
31 | final double centerY = size.height / 2;
32 | final Offset center = Offset(centerX, centerY);
33 |
34 | // Minute Calculation
35 | final double minX =
36 | centerX + size.width * 0.335 * cos((dateTime.minute * 6) * pi / 180);
37 | final double minY =
38 | centerY + size.width * 0.335 * sin((dateTime.minute * 6) * pi / 180);
39 |
40 | //Minute Line
41 | canvas.drawLine(
42 | center,
43 | Offset(minX, minY),
44 | Paint()
45 | ..color = Theme.of(context).colorScheme.secondary
46 | ..style = PaintingStyle.stroke
47 | ..strokeWidth = 10,
48 | );
49 | canvas.drawCircle(
50 | Offset(minX, minY),
51 | .1,
52 | Paint()
53 | ..color = Theme.of(context).colorScheme.secondary
54 | ..style = PaintingStyle.stroke
55 | ..strokeWidth = 10,
56 | );
57 |
58 | // Hour Calculation
59 | // dateTime.hour * 30 because 360/12 = 30
60 | // dateTime.minute * 0.5 each minute we want to turn our hour line a little
61 | final double hourX = centerX +
62 | size.width *
63 | 0.25 *
64 | cos((dateTime.hour * 30 + dateTime.minute * 0.5) * pi / 180);
65 | final double hourY = centerY +
66 | size.width *
67 | 0.25 *
68 | sin((dateTime.hour * 30 + dateTime.minute * 0.5) * pi / 180);
69 |
70 | // hour Line
71 | canvas.drawLine(
72 | center,
73 | Offset(hourX, hourY),
74 | Paint()
75 | ..color = Theme.of(context).colorScheme.secondary
76 | ..style = PaintingStyle.stroke
77 | ..strokeWidth = 15.0,
78 | );
79 | canvas.drawCircle(
80 | Offset(hourX, hourY),
81 | 1.5,
82 | Paint()
83 | ..color = Theme.of(context).colorScheme.secondary
84 | ..style = PaintingStyle.stroke
85 | ..strokeWidth = 10,
86 | );
87 |
88 | // Second Calculation
89 | // size.width * 0.4 define our line height
90 | // dateTime.second * 6 because 360 / 60 = 6
91 | final double secondX =
92 | centerX + size.width * 0.4 * cos((dateTime.second * 6) * pi / 180);
93 | final double secondY =
94 | centerY + size.width * 0.4 * sin((dateTime.second * 6) * pi / 180);
95 |
96 | // Second Line
97 | canvas.drawLine(
98 | center,
99 | Offset(secondX, secondY),
100 | Paint()..color = Theme.of(context).primaryColor,
101 | );
102 |
103 | // Draw minute
104 | for (int i = 1; i < 60; i++) {
105 | if ([5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55].contains(i) == false) {
106 | final double startX =
107 | centerX + size.width * 0.475 * cos((i * 6) * pi / 180);
108 | final double startY =
109 | centerY + size.width * 0.475 * sin((i * 6) * pi / 180);
110 | final double endX =
111 | centerX + size.width * 0.49 * cos((i * 6) * pi / 180);
112 | final double endY =
113 | centerY + size.width * 0.49 * sin((i * 6) * pi / 180);
114 |
115 | canvas.drawLine(
116 | Offset(startX, startY),
117 | Offset(endX, endY),
118 | Paint()..color = Theme.of(context).primaryColor,
119 | );
120 | }
121 | }
122 |
123 | // Draw time,
124 | // 12h
125 | clockOffset.asMap().forEach((i, e) {
126 | final double hour12XText =
127 | centerX + size.width * .4 * cos(e); // * cos((12 * 30) * pi / 180);
128 | final double hour12YText =
129 | centerY - size.width * .4 * sin(e); // * sin((12) * pi / 180);
130 |
131 | final double hour12X = centerX +
132 | size.width *
133 | ([0, 3, 6, 9].contains(i) ? .45 : .475) *
134 | cos(e); // * cos((12 * 30) * pi / 180);
135 | final double hour12Y = centerY +
136 | size.width *
137 | ([0, 3, 6, 9].contains(i) ? .45 : .475) *
138 | sin(e); // * sin((12) * pi / 180);
139 | // canvas.drawCircle(
140 | // Offset(hour12Y, hour12X), 4, Paint()..color = Colors.black);
141 |
142 | final double hour12Xx =
143 | centerX + size.width * 0.49 * cos(e); // * cos((12 * 30) * pi / 180);
144 | final double hour12Yy =
145 | centerY + size.width * 0.49 * sin(e); // * sin((12) * pi / 180);
146 | // canvas.drawCircle(
147 | // Offset(hour12Yy, hour12Xx), 4, Paint()..color = Colors.amber);
148 | //
149 | final TextSpan span = TextSpan(
150 | style: TextStyle(
151 | color: [0, 3, 6, 9].contains(i)
152 | ? Theme.of(context).primaryColor
153 | : Theme.of(context).secondaryHeaderColor,
154 | fontFamily: 'Lato',
155 | fontSize:
156 | [0, 3, 6, 9].contains(i) ? size.width / 22.0 : size.width / 28.0,
157 | fontWeight:
158 | [0, 3, 6, 9].contains(i) ? FontWeight.w600 : FontWeight.w400,
159 | ),
160 | text: i == 0 ? '12' : i.toString(),
161 | );
162 | final TextPainter tp = TextPainter(
163 | text: span,
164 | textAlign: TextAlign.left,
165 | textDirection: TextDirection.ltr,
166 | );
167 | canvas.rotate(pi / 2);
168 | tp.layout();
169 | tp.paint(
170 | canvas,
171 | Offset(
172 | hour12XText - (i == 0 ? 10.0 : 5.0),
173 | hour12YText - size.width - 8.0,
174 | ),
175 | );
176 | canvas.rotate(-pi / 2);
177 | canvas.drawLine(
178 | Offset(hour12Y, hour12X),
179 | Offset(hour12Yy, hour12Xx),
180 | Paint()
181 | ..color = [0, 3, 6, 9].contains(i)
182 | ? Theme.of(context).primaryColor
183 | : Theme.of(context).secondaryHeaderColor
184 | ..style = PaintingStyle.stroke
185 | ..strokeWidth = [0, 3, 6, 9].contains(i) ? 2.5 : 1,
186 | );
187 | });
188 |
189 | // Center Dots
190 | final Paint dotPainter = Paint()
191 | ..color = Theme.of(context).primaryIconTheme.color ?? Colors.grey;
192 | canvas.drawCircle(center, 24, dotPainter);
193 | canvas.drawCircle(
194 | center,
195 | 23,
196 | Paint()..color = Theme.of(context).colorScheme.background,
197 | );
198 | // canvas.drawCircle(center, 10, dotPainter);
199 | }
200 |
201 | @override
202 | bool shouldRepaint(CustomPainter oldDelegate) {
203 | return true;
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/lib/src/pages/global/widgets/country_card.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_svg/flutter_svg.dart';
6 |
7 | // Project imports:
8 | import 'package:analog_clock/src/public/size_config.dart';
9 |
10 | class CountryCard extends StatelessWidget {
11 | final String country, timeZone, iconSrc, time, period;
12 |
13 | const CountryCard({
14 | super.key,
15 | required this.country,
16 | required this.iconSrc,
17 | required this.period,
18 | required this.time,
19 | required this.timeZone,
20 | });
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return Padding(
25 | padding: EdgeInsets.only(left: getProportionateScreenWidth(20)),
26 | child: SizedBox(
27 | width: getProportionateScreenWidth(233),
28 | child: AspectRatio(
29 | aspectRatio: 1.32,
30 | child: Container(
31 | padding: EdgeInsets.all(getProportionateScreenWidth(20)),
32 | decoration: BoxDecoration(
33 | borderRadius: BorderRadius.circular(10),
34 | border: Border.all(
35 | color: Theme.of(context).primaryIconTheme.color ?? Colors.black,
36 | ),
37 | ),
38 | child: Column(
39 | crossAxisAlignment: CrossAxisAlignment.start,
40 | children: [
41 | Text(
42 | country,
43 | style: Theme.of(context)
44 | .textTheme
45 | .headlineMedium
46 | ?.copyWith(fontSize: getProportionateScreenWidth(16)),
47 | ),
48 | const SizedBox(height: 5),
49 | Text(timeZone),
50 | const Spacer(),
51 | Row(
52 | children: [
53 | SvgPicture.asset(
54 | iconSrc,
55 | width: getProportionateScreenWidth(40),
56 | ),
57 | const Spacer(),
58 | Text(
59 | time,
60 | style: Theme.of(context).textTheme.headlineMedium,
61 | ),
62 | RotatedBox(
63 | quarterTurns: 3,
64 | child: Text(period),
65 | ),
66 | ],
67 | ),
68 | ],
69 | ),
70 | ),
71 | ),
72 | ),
73 | );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/src/pages/global/widgets/time_in_hour_and_minute.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 |
7 | // Project imports:
8 | import 'package:analog_clock/src/pages/global/controllers/clock_controller.dart';
9 | import 'package:analog_clock/src/public/size_config.dart';
10 |
11 | class TimeInHourAndMinute extends StatelessWidget {
12 | final TimeOfDay timeOfDay;
13 | final bool showPeriod;
14 | final clockController = Get.put(ClockController());
15 |
16 | TimeInHourAndMinute({
17 | super.key,
18 | required this.timeOfDay,
19 | required this.showPeriod,
20 | });
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | final String period = timeOfDay.period == DayPeriod.am ? "AM" : "PM";
25 | return Row(
26 | mainAxisAlignment: MainAxisAlignment.center,
27 | children: [
28 | Text(
29 | // if you use _timeOfDay.hour then it will show 20:10 like that
30 | // But we want 8:10
31 | "${clockController.formatTime(timeOfDay.hourOfPeriod)}:${clockController.formatTime(timeOfDay.minute)}",
32 | style: Theme.of(context).textTheme.displayLarge,
33 | ),
34 | showPeriod
35 | ? Row(
36 | children: [
37 | const SizedBox(width: 5),
38 | RotatedBox(
39 | quarterTurns: 3,
40 | child: Text(
41 | period,
42 | style:
43 | TextStyle(fontSize: getProportionateScreenWidth(18)),
44 | ),
45 | ),
46 | ],
47 | )
48 | : Container(),
49 | ],
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/src/pages/stopwatch/controllers/stop_watch_controller.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:async';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 |
7 | // Package imports:
8 | import 'package:get/get.dart';
9 |
10 | class StopWatchController extends GetxController {
11 | StreamController currentTime =
12 | StreamController.broadcast();
13 | ScrollController scrollController = ScrollController();
14 | DateTime dateTime = DateTime(0, 0, 0);
15 | Timer? timer;
16 | double percent = .0;
17 | bool isRunning = false;
18 | List dateTimes = [];
19 |
20 | formatTime(input) {
21 | if (input < 10) {
22 | return '0$input';
23 | }
24 | return input.toString();
25 | }
26 |
27 | play() {
28 | isRunning ? stopTimer() : startTimer();
29 | }
30 |
31 | updateTime(h, m, s) {
32 | currentTime.add(dateTime);
33 | }
34 |
35 | startTimer() {
36 | isRunning = true;
37 | update();
38 | timer = Timer.periodic(const Duration(milliseconds: 17), (timer) {
39 | dateTime = dateTime.add(const Duration(milliseconds: 17));
40 | currentTime.add(dateTime);
41 | percent = dateTime.second / 60.0;
42 | update();
43 | });
44 | }
45 |
46 | stopTimer() {
47 | timer?.cancel();
48 | isRunning = false;
49 | update();
50 | }
51 |
52 | saveCurrentTime() {
53 | if (isRunning) {
54 | dateTimes.insert(0, dateTime);
55 | scrollController.animateTo(
56 | 0.0,
57 | curve: Curves.easeOut,
58 | duration: const Duration(milliseconds: 300),
59 | );
60 | update();
61 | }
62 | }
63 |
64 | resetTime() {
65 | dateTime = DateTime(0, 0, 0);
66 | timer?.cancel();
67 | currentTime.add(dateTime);
68 | dateTimes.clear();
69 | dateTimes.add(DateTime(0, 0, 0));
70 | percent = .0;
71 | isRunning = false;
72 | update();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/src/pages/stopwatch/stop_watch_page.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 | import 'package:percent_indicator/circular_percent_indicator.dart';
7 |
8 | // Project imports:
9 | import 'package:analog_clock/src/pages/stopwatch/controllers/stop_watch_controller.dart';
10 | import 'package:analog_clock/src/pages/stopwatch/widgets/list_stop_watch.dart';
11 | import 'package:analog_clock/src/pages/stopwatch/widgets/stop_watch_controll.dart';
12 | import 'package:analog_clock/src/public/constants.dart';
13 |
14 | class StopWatchPage extends StatefulWidget {
15 | const StopWatchPage({super.key});
16 |
17 | @override
18 | State createState() => _StopWatchPageState();
19 | }
20 |
21 | class _StopWatchPageState extends State {
22 | final stopWatchController = Get.put(StopWatchController());
23 |
24 | @override
25 | void initState() {
26 | super.initState();
27 | stopWatchController.dateTimes.add(DateTime(0, 0, 0));
28 | stopWatchController.updateTime(0, 0, 0);
29 | }
30 |
31 | @override
32 | void dispose() {
33 | stopWatchController.timer?.cancel();
34 | super.dispose();
35 | }
36 |
37 | @override
38 | Widget build(BuildContext context) {
39 | return Scaffold(
40 | body: Column(
41 | children: [
42 | const Spacer(),
43 | StreamBuilder(
44 | stream: stopWatchController.currentTime.stream,
45 | builder: (context, snapshot) {
46 | if (!snapshot.hasData) {
47 | return _buildClock(
48 | DateTime(0, 0, 0),
49 | DateTime(0, 0, 0),
50 | );
51 | }
52 |
53 | return _buildClock(
54 | snapshot.data!,
55 | stopWatchController.dateTimes[0],
56 | );
57 | },
58 | ),
59 | const Spacer(),
60 | SizedBox(
61 | height: height * .3,
62 | child: const ListStopWatch(),
63 | ),
64 | const Spacer(),
65 | const StopWatchControll(),
66 | const Spacer(flex: 3),
67 | ],
68 | ),
69 | );
70 | }
71 |
72 | Widget _buildClock(DateTime dateTime, DateTime dateTimePrevious) {
73 | return CircularPercentIndicator(
74 | radius: width * .45,
75 | lineWidth: 60.0,
76 | percent: stopWatchController.percent,
77 | circularStrokeCap: CircularStrokeCap.round,
78 | backgroundColor: Theme.of(context).colorScheme.secondary,
79 | linearGradient: LinearGradient(
80 | begin: Alignment.topLeft,
81 | end: Alignment.bottomCenter,
82 | colors: [
83 | Theme.of(context).primaryColor,
84 | Theme.of(context).secondaryHeaderColor,
85 | ],
86 | tileMode: TileMode.mirror,
87 | ),
88 | animationDuration: 1000,
89 | animateFromLastPercent: true,
90 | rotateLinearGradient: true,
91 | center: Column(
92 | mainAxisAlignment: MainAxisAlignment.center,
93 | children: [
94 | RichText(
95 | text: TextSpan(
96 | children: [
97 | TextSpan(
98 | text:
99 | '${stopWatchController.formatTime(dateTime.hour)}:${stopWatchController.formatTime(dateTime.minute)}:${stopWatchController.formatTime(dateTime.second)}',
100 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
101 | fontSize: width / 12.0,
102 | fontFamily: 'Lato',
103 | fontWeight: FontWeight.w400,
104 | ),
105 | ),
106 | TextSpan(
107 | text:
108 | ':${stopWatchController.formatTime((dateTime.millisecond / 17).round())}',
109 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
110 | fontSize: width / 18.0,
111 | fontFamily: 'Lato',
112 | fontWeight: FontWeight.w400,
113 | ),
114 | ),
115 | ],
116 | ),
117 | ),
118 | const SizedBox(height: 8.0),
119 | RichText(
120 | text: TextSpan(
121 | children: [
122 | TextSpan(
123 | text:
124 | '${stopWatchController.formatTime(dateTimePrevious.hour)}:${stopWatchController.formatTime(dateTimePrevious.minute)}:${stopWatchController.formatTime(dateTimePrevious.second)}',
125 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
126 | fontSize: width / 18.0,
127 | fontFamily: 'Lato',
128 | fontWeight: FontWeight.w400,
129 | ),
130 | ),
131 | TextSpan(
132 | text:
133 | ':${stopWatchController.formatTime((dateTimePrevious.millisecond / 17).round())}',
134 | style: Theme.of(context).textTheme.displayLarge?.copyWith(
135 | fontSize: width / 26.0,
136 | fontFamily: 'Lato',
137 | fontWeight: FontWeight.w400,
138 | ),
139 | ),
140 | ],
141 | ),
142 | ),
143 | ],
144 | ),
145 | );
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/lib/src/pages/stopwatch/widgets/list_stop_watch.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 | import 'package:intl/intl.dart';
7 |
8 | // Project imports:
9 | import 'package:analog_clock/src/pages/stopwatch/controllers/stop_watch_controller.dart';
10 | import 'package:analog_clock/src/public/constants.dart';
11 |
12 | class ListStopWatch extends StatefulWidget {
13 | const ListStopWatch({super.key});
14 |
15 | @override
16 | State createState() => _ListStopWatchState();
17 | }
18 |
19 | class _ListStopWatchState extends State {
20 | DateFormat format = DateFormat('HH:mm:ss');
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return GetBuilder(
25 | builder: (_) => ListView.builder(
26 | controller: _.scrollController,
27 | padding: EdgeInsets.zero,
28 | itemCount: _.dateTimes.length,
29 | itemBuilder: (context, index) {
30 | return index == _.dateTimes.length - 1
31 | ? Container()
32 | : Container(
33 | padding: const EdgeInsets.symmetric(
34 | horizontal: 24.0,
35 | vertical: 12.0,
36 | ),
37 | child: Row(
38 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
39 | children: [
40 | Column(
41 | crossAxisAlignment: CrossAxisAlignment.start,
42 | mainAxisAlignment: MainAxisAlignment.center,
43 | children: [
44 | Text(
45 | 'Stopwatch: ${_.dateTimes.length - index - 1}',
46 | style: Theme.of(context)
47 | .textTheme
48 | .displayLarge
49 | ?.copyWith(
50 | fontSize: width / 24.0,
51 | fontFamily: 'Lato',
52 | fontWeight: FontWeight.w600,
53 | ),
54 | ),
55 | const SizedBox(height: 8.0),
56 | Text(
57 | format.format(_.dateTimes[index]),
58 | style: Theme.of(context)
59 | .textTheme
60 | .displayLarge
61 | ?.copyWith(
62 | fontSize: width / 28.0,
63 | fontFamily: 'Lato',
64 | fontWeight: FontWeight.w400,
65 | ),
66 | ),
67 | ],
68 | ),
69 | Icon(
70 | Icons.alarm_add_sharp,
71 | size: width / 16.0,
72 | ),
73 | ],
74 | ),
75 | );
76 | },
77 | ),
78 | );
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/lib/src/pages/stopwatch/widgets/stop_watch_controll.dart:
--------------------------------------------------------------------------------
1 | // Package imports:
2 | import 'package:flutter_neumorphic_plus/flutter_neumorphic.dart';
3 | import 'package:get/get.dart';
4 |
5 | // Project imports:
6 | import 'package:analog_clock/src/pages/stopwatch/controllers/stop_watch_controller.dart';
7 | import 'package:analog_clock/src/public/constants.dart';
8 |
9 | class StopWatchControll extends StatefulWidget {
10 | const StopWatchControll({super.key});
11 |
12 | @override
13 | State createState() => _StopWatchControllState();
14 | }
15 |
16 | class _StopWatchControllState extends State {
17 | final stopWatchController = Get.put(StopWatchController());
18 | @override
19 | Widget build(BuildContext context) {
20 | return GetBuilder(
21 | builder: (_) => Container(
22 | padding: const EdgeInsets.symmetric(horizontal: 24.0),
23 | child: Row(
24 | mainAxisAlignment: MainAxisAlignment.spaceAround,
25 | children: [
26 | IconButton(
27 | onPressed: () => _.resetTime(),
28 | icon: Icon(
29 | Icons.refresh,
30 | size: width / 12.0,
31 | ),
32 | ),
33 | NeumorphicButton(
34 | onPressed: () => _.play(),
35 | duration: const Duration(milliseconds: 200),
36 | padding: EdgeInsets.all(width / 22.5),
37 | style: NeumorphicStyle(
38 | shape: NeumorphicShape.convex,
39 | boxShape: const NeumorphicBoxShape.circle(),
40 | depth: 10.0,
41 | intensity: .18,
42 | surfaceIntensity: .5,
43 | color: Theme.of(context).scaffoldBackgroundColor,
44 | ),
45 | child: Icon(
46 | _.isRunning ? Icons.pause : Icons.play_arrow,
47 | size: width / 12.0,
48 | ),
49 | ),
50 | IconButton(
51 | onPressed: () => _.saveCurrentTime(),
52 | icon: Icon(
53 | Icons.add_alarm_rounded,
54 | size: width / 12.0,
55 | ),
56 | ),
57 | ],
58 | ),
59 | ),
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/src/pages/tab/tab_bar_layout.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Project imports:
5 | import 'package:analog_clock/src/pages/alarm/alarm_page.dart';
6 | import 'package:analog_clock/src/pages/bedtime/bed_time_page.dart';
7 | import 'package:analog_clock/src/pages/countdown/count_down_page.dart';
8 | import 'package:analog_clock/src/pages/global/global_page.dart';
9 | import 'package:analog_clock/src/pages/stopwatch/stop_watch_page.dart';
10 | import 'package:analog_clock/src/public/constants.dart';
11 | import 'package:analog_clock/src/public/size_config.dart';
12 |
13 | class TabBarLayout extends StatefulWidget {
14 | const TabBarLayout({super.key});
15 |
16 | @override
17 | State createState() => _TabBarLayoutState();
18 | }
19 |
20 | class _TabBarLayoutState extends State
21 | with SingleTickerProviderStateMixin {
22 | late TabController _tabController;
23 |
24 | final _pages = [
25 | const AlarmPage(),
26 | const GlobalPage(),
27 | const BedTimePage(),
28 | const StopWatchPage(),
29 | const CountDownPage(),
30 | ];
31 |
32 | @override
33 | void initState() {
34 | super.initState();
35 | _tabController = TabController(
36 | vsync: this,
37 | length: _pages.length,
38 | );
39 | }
40 |
41 | @override
42 | Widget build(BuildContext context) {
43 | SizeConfig().init(context);
44 | return Scaffold(
45 | body: Column(
46 | children: [
47 | SizedBox(height: height / 20.0),
48 | _buildTopBar(context),
49 | const SizedBox(height: 16.0),
50 | Expanded(
51 | child: TabBarView(
52 | controller: _tabController,
53 | children: _pages.map((tab) {
54 | return tab;
55 | }).toList(),
56 | ),
57 | ),
58 | ],
59 | ),
60 | );
61 | }
62 |
63 | Widget _buildTopBar(context) {
64 | return TabBar(
65 | controller: _tabController,
66 | labelColor: Theme.of(context).primaryColor,
67 | indicatorColor: Colors.transparent,
68 | unselectedLabelColor: Theme.of(context).iconTheme.color,
69 | indicatorSize: TabBarIndicatorSize.tab,
70 | indicatorWeight: .1,
71 | labelStyle: TextStyle(
72 | fontWeight: FontWeight.bold,
73 | fontSize: width / 14.0,
74 | fontFamily: 'Raleway-Bold',
75 | ),
76 | unselectedLabelStyle: TextStyle(
77 | fontWeight: FontWeight.bold,
78 | fontSize: width / 14.0,
79 | fontFamily: 'Raleway-Bold',
80 | ),
81 | tabs: [
82 | Tab(
83 | icon: Icon(
84 | Icons.alarm,
85 | size: width / 15.0,
86 | ),
87 | ),
88 | Tab(
89 | icon: Icon(
90 | Icons.watch_later_outlined,
91 | size: width / 15.0,
92 | ),
93 | ),
94 | Tab(
95 | icon: Icon(
96 | Icons.king_bed_outlined,
97 | size: width / 15.0,
98 | ),
99 | ),
100 | Tab(
101 | icon: Icon(
102 | Icons.alarm_on_outlined,
103 | size: width / 15.0,
104 | ),
105 | ),
106 | Tab(
107 | icon: Icon(
108 | Icons.hourglass_empty_sharp,
109 | size: width / 15.0,
110 | ),
111 | ),
112 | ],
113 | );
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/lib/src/public/constants.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:get/get.dart';
6 |
7 | // Colors
8 | const kPrimaryColor = Color(0xFFFF97B3);
9 | const kSecondaryColor = Color(0xFF1DA1F2);
10 | const kSecondaryLightColor = Color(0xFFE4E9F2);
11 | const kSecondaryDarkColor = Color(0xFF404040);
12 | const kAccentLightColor = Color(0xFFB3BFD7);
13 | const kAccentDarkColor = Color(0xFF4E4E4E);
14 | const kBackgroundDarkColor = Color(0xFF3A3A3A);
15 | const kSurfaceDarkColor = Color(0xFF222225);
16 | // Icon Colors
17 | const kAccentIconLightColor = Color(0xFFECEFF5);
18 | const kAccentIconDarkColor = Color(0xFF303030);
19 | const kPrimaryIconLightColor = Color(0xFFECEFF5);
20 | const kPrimaryIconDarkColor = Color(0xFF232323);
21 | // Text Colors
22 | const kBodyTextColorLight = Color(0xFFA1B0CA);
23 | const kBodyTextColorDark = Color(0xFF7C7C7C);
24 | const kTitleTextLightColor = Color(0xFF101112);
25 | const kTitleTextDarkColor = Colors.white;
26 |
27 | const kShadowColor = Color(0xFF364564);
28 |
29 | AppBarTheme appBarTheme = const AppBarTheme(color: Colors.transparent, elevation: 0);
30 |
31 | // Device Size
32 | var height = Get.height;
33 | var width = Get.width;
34 |
--------------------------------------------------------------------------------
/lib/src/public/size_config.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | class SizeConfig {
5 | static late MediaQueryData _mediaQueryData;
6 | static late double screenWidth;
7 | static late double screenHeight;
8 | static late double defaultSize;
9 | static late Orientation orientation;
10 |
11 | void init(BuildContext context) {
12 | _mediaQueryData = MediaQuery.of(context);
13 | screenWidth = _mediaQueryData.size.width;
14 | screenHeight = _mediaQueryData.size.height;
15 | orientation = _mediaQueryData.orientation;
16 | }
17 | }
18 |
19 | // Get the proportionate height as per screen size
20 | double getProportionateScreenHeight(double inputHeight) {
21 | final double screenHeight = SizeConfig.screenHeight;
22 | // 896 is the layout height that designer use
23 | // or you can say iPhone 11
24 | return (inputHeight / 896.0) * screenHeight;
25 | }
26 |
27 | // Get the proportionate height as per screen size
28 | double getProportionateScreenWidth(double inputWidth) {
29 | final double screenWidth = SizeConfig.screenWidth;
30 | // 414 is the layout width that designer use
31 | return (inputWidth / 414.0) * screenWidth;
32 | }
33 |
--------------------------------------------------------------------------------
/lib/src/routes/app_pages.dart:
--------------------------------------------------------------------------------
1 | // Package imports:
2 | import 'package:get/get.dart';
3 |
4 | // Project imports:
5 | import 'package:analog_clock/src/app.dart';
6 |
7 | part 'app_routes.dart';
8 |
9 | // ignore: avoid_classes_with_only_static_members
10 | class AppPages {
11 | static const rootRoute = Routes.root;
12 |
13 | static final routes = [
14 | GetPage(
15 | name: Routes.root,
16 | page: () => const App(),
17 | ),
18 | ];
19 | }
20 |
--------------------------------------------------------------------------------
/lib/src/routes/app_routes.dart:
--------------------------------------------------------------------------------
1 | part of 'app_pages.dart';
2 |
3 | abstract class Routes {
4 | static const root = '/root';
5 | }
6 |
--------------------------------------------------------------------------------
/lib/src/shared/logger/logger_utils.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | class Logger {
5 | static void write(String text, {bool isError = false}) {
6 | Future.microtask(() => debugPrint('** $text. isError: [$isError]'));
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/theme/theme_service.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/services.dart';
4 |
5 | // Package imports:
6 | import 'package:get/get.dart';
7 | import 'package:get_storage/get_storage.dart';
8 |
9 | class ThemeService {
10 | final _getStorage = GetStorage();
11 | final storageKey = 'isDarkMode';
12 |
13 | ThemeMode getThemeMode() {
14 | return isSavedDarkMode() ? ThemeMode.dark : ThemeMode.light;
15 | }
16 |
17 | bool isSavedDarkMode() {
18 | return _getStorage.read(storageKey) ?? false;
19 | }
20 |
21 | void saveThemeMode(bool isDarkMode) {
22 | _getStorage.write(storageKey, isDarkMode);
23 | }
24 |
25 | void changeThemeMode() {
26 | Get.changeThemeMode(isSavedDarkMode() ? ThemeMode.light : ThemeMode.dark);
27 | saveThemeMode(!isSavedDarkMode());
28 | setBrighness();
29 | }
30 |
31 | void initBrighness() {
32 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
33 | statusBarColor: Colors.transparent,
34 | statusBarBrightness: Theme.of(Get.context!).brightness,
35 | statusBarIconBrightness: Theme.of(Get.context!).brightness,
36 | ),);
37 | }
38 |
39 | void setBrighness() {
40 | if (GetPlatform.isAndroid) {
41 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
42 | statusBarColor: Colors.transparent,
43 | statusBarBrightness: Theme.of(Get.context!).brightness,
44 | statusBarIconBrightness: Theme.of(Get.context!).brightness,
45 | ),);
46 | } else {
47 | if (Theme.of(Get.context!).brightness == Brightness.light) {
48 | SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
49 | statusBarColor: Colors.transparent,
50 | statusBarBrightness: Brightness.dark,
51 | statusBarIconBrightness: Brightness.dark,
52 | ),);
53 | } else {
54 | SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
55 | statusBarColor: Colors.transparent,
56 | statusBarBrightness: Brightness.light,
57 | statusBarIconBrightness: Brightness.light,
58 | ),);
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/src/theme/themes.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:google_fonts/google_fonts.dart';
6 |
7 | // Project imports:
8 | import 'package:analog_clock/src/public/constants.dart';
9 |
10 | class Themes {
11 | final lightTheme = ThemeData.light().copyWith(
12 | appBarTheme: appBarTheme,
13 | primaryColor: kPrimaryColor,
14 | secondaryHeaderColor: kSecondaryColor,
15 | scaffoldBackgroundColor: Colors.white,
16 | iconTheme: const IconThemeData(color: kBodyTextColorLight),
17 | primaryIconTheme: const IconThemeData(color: kPrimaryIconLightColor),
18 | textTheme: GoogleFonts.latoTextTheme().copyWith(
19 | bodyLarge: const TextStyle(color: kBodyTextColorLight),
20 | bodyMedium: const TextStyle(color: kBodyTextColorLight),
21 | headlineMedium: const TextStyle(color: kTitleTextLightColor, fontSize: 32),
22 | displayLarge: const TextStyle(color: kTitleTextLightColor, fontSize: 80),
23 | displayMedium: const TextStyle(color: kTitleTextDarkColor, fontSize: 80),
24 | ),
25 | brightness: Brightness.light, colorScheme: const ColorScheme.light(
26 | secondary: kSecondaryLightColor,
27 | // on light theme surface = Colors.white by default
28 | ).copyWith(secondary: kAccentLightColor).copyWith(background: Colors.white),
29 | );
30 | final darkTheme = ThemeData.dark().copyWith(
31 | primaryColor: kPrimaryColor,
32 | secondaryHeaderColor: kSecondaryColor,
33 | scaffoldBackgroundColor: const Color(0xFF0D0C0E),
34 | appBarTheme: appBarTheme,
35 | iconTheme: const IconThemeData(color: kBodyTextColorDark),
36 | primaryIconTheme: const IconThemeData(color: kPrimaryIconDarkColor),
37 | textTheme: GoogleFonts.latoTextTheme().copyWith(
38 | bodyLarge: const TextStyle(color: kBodyTextColorDark),
39 | bodyMedium: const TextStyle(color: kBodyTextColorDark),
40 | headlineMedium: const TextStyle(color: kTitleTextDarkColor, fontSize: 32),
41 | displayLarge: const TextStyle(color: kTitleTextDarkColor, fontSize: 80),
42 | displayMedium: const TextStyle(color: kTitleTextDarkColor, fontSize: 80),
43 | ),
44 | brightness: Brightness.dark, colorScheme: const ColorScheme.light(
45 | secondary: kSecondaryDarkColor,
46 | surface: kSurfaceDarkColor,
47 | ).copyWith(secondary: kAccentDarkColor).copyWith(background: kBackgroundDarkColor),
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | args:
5 | dependency: transitive
6 | description:
7 | name: args
8 | sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "2.4.2"
12 | async:
13 | dependency: transitive
14 | description:
15 | name: async
16 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "2.11.0"
20 | boolean_selector:
21 | dependency: transitive
22 | description:
23 | name: boolean_selector
24 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "2.1.1"
28 | characters:
29 | dependency: transitive
30 | description:
31 | name: characters
32 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "1.3.0"
36 | clock:
37 | dependency: transitive
38 | description:
39 | name: clock
40 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "1.1.1"
44 | collection:
45 | dependency: transitive
46 | description:
47 | name: collection
48 | sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "1.17.2"
52 | crypto:
53 | dependency: transitive
54 | description:
55 | name: crypto
56 | sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
57 | url: "https://pub.dev"
58 | source: hosted
59 | version: "3.0.3"
60 | cupertino_icons:
61 | dependency: "direct main"
62 | description:
63 | name: cupertino_icons
64 | sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
65 | url: "https://pub.dev"
66 | source: hosted
67 | version: "1.0.6"
68 | fake_async:
69 | dependency: transitive
70 | description:
71 | name: fake_async
72 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
73 | url: "https://pub.dev"
74 | source: hosted
75 | version: "1.3.1"
76 | ffi:
77 | dependency: transitive
78 | description:
79 | name: ffi
80 | sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
81 | url: "https://pub.dev"
82 | source: hosted
83 | version: "2.1.0"
84 | flutter:
85 | dependency: "direct main"
86 | description: flutter
87 | source: sdk
88 | version: "0.0.0"
89 | flutter_lints:
90 | dependency: "direct dev"
91 | description:
92 | name: flutter_lints
93 | sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
94 | url: "https://pub.dev"
95 | source: hosted
96 | version: "2.0.3"
97 | flutter_neumorphic_plus:
98 | dependency: "direct main"
99 | description:
100 | name: flutter_neumorphic_plus
101 | sha256: fc702c6414c6d9e1498f84ca124b59104e0dcbac59f92a47c5776e023d985e63
102 | url: "https://pub.dev"
103 | source: hosted
104 | version: "3.3.0"
105 | flutter_phosphor_icons:
106 | dependency: "direct main"
107 | description:
108 | name: flutter_phosphor_icons
109 | sha256: "60a970f5fb5b22c93cea61e96c2cd922612dd2d4a359fa441e4d31c2e3b3c664"
110 | url: "https://pub.dev"
111 | source: hosted
112 | version: "0.0.1+6"
113 | flutter_svg:
114 | dependency: "direct main"
115 | description:
116 | name: flutter_svg
117 | sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
118 | url: "https://pub.dev"
119 | source: hosted
120 | version: "2.0.7"
121 | flutter_test:
122 | dependency: "direct dev"
123 | description: flutter
124 | source: sdk
125 | version: "0.0.0"
126 | get:
127 | dependency: "direct main"
128 | description:
129 | name: get
130 | sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e
131 | url: "https://pub.dev"
132 | source: hosted
133 | version: "4.6.6"
134 | get_storage:
135 | dependency: "direct main"
136 | description:
137 | name: get_storage
138 | sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2"
139 | url: "https://pub.dev"
140 | source: hosted
141 | version: "2.1.1"
142 | google_fonts:
143 | dependency: "direct main"
144 | description:
145 | name: google_fonts
146 | sha256: f0b8d115a13ecf827013ec9fc883390ccc0e87a96ed5347a3114cac177ef18e8
147 | url: "https://pub.dev"
148 | source: hosted
149 | version: "6.1.0"
150 | http:
151 | dependency: transitive
152 | description:
153 | name: http
154 | sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
155 | url: "https://pub.dev"
156 | source: hosted
157 | version: "1.1.0"
158 | http_parser:
159 | dependency: transitive
160 | description:
161 | name: http_parser
162 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
163 | url: "https://pub.dev"
164 | source: hosted
165 | version: "4.0.2"
166 | import_sorter:
167 | dependency: "direct dev"
168 | description:
169 | name: import_sorter
170 | sha256: eb15738ccead84e62c31e0208ea4e3104415efcd4972b86906ca64a1187d0836
171 | url: "https://pub.dev"
172 | source: hosted
173 | version: "4.6.0"
174 | intl:
175 | dependency: "direct main"
176 | description:
177 | name: intl
178 | sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
179 | url: "https://pub.dev"
180 | source: hosted
181 | version: "0.18.1"
182 | lints:
183 | dependency: transitive
184 | description:
185 | name: lints
186 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
187 | url: "https://pub.dev"
188 | source: hosted
189 | version: "2.1.1"
190 | matcher:
191 | dependency: transitive
192 | description:
193 | name: matcher
194 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
195 | url: "https://pub.dev"
196 | source: hosted
197 | version: "0.12.16"
198 | material_color_utilities:
199 | dependency: transitive
200 | description:
201 | name: material_color_utilities
202 | sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
203 | url: "https://pub.dev"
204 | source: hosted
205 | version: "0.5.0"
206 | meta:
207 | dependency: transitive
208 | description:
209 | name: meta
210 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
211 | url: "https://pub.dev"
212 | source: hosted
213 | version: "1.9.1"
214 | nested:
215 | dependency: transitive
216 | description:
217 | name: nested
218 | sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
219 | url: "https://pub.dev"
220 | source: hosted
221 | version: "1.0.0"
222 | path:
223 | dependency: transitive
224 | description:
225 | name: path
226 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
227 | url: "https://pub.dev"
228 | source: hosted
229 | version: "1.8.3"
230 | path_parsing:
231 | dependency: transitive
232 | description:
233 | name: path_parsing
234 | sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
235 | url: "https://pub.dev"
236 | source: hosted
237 | version: "1.0.1"
238 | path_provider:
239 | dependency: transitive
240 | description:
241 | name: path_provider
242 | sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
243 | url: "https://pub.dev"
244 | source: hosted
245 | version: "2.1.1"
246 | path_provider_android:
247 | dependency: transitive
248 | description:
249 | name: path_provider_android
250 | sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1"
251 | url: "https://pub.dev"
252 | source: hosted
253 | version: "2.2.0"
254 | path_provider_foundation:
255 | dependency: transitive
256 | description:
257 | name: path_provider_foundation
258 | sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
259 | url: "https://pub.dev"
260 | source: hosted
261 | version: "2.3.1"
262 | path_provider_linux:
263 | dependency: transitive
264 | description:
265 | name: path_provider_linux
266 | sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
267 | url: "https://pub.dev"
268 | source: hosted
269 | version: "2.2.1"
270 | path_provider_platform_interface:
271 | dependency: transitive
272 | description:
273 | name: path_provider_platform_interface
274 | sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
275 | url: "https://pub.dev"
276 | source: hosted
277 | version: "2.1.1"
278 | path_provider_windows:
279 | dependency: transitive
280 | description:
281 | name: path_provider_windows
282 | sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
283 | url: "https://pub.dev"
284 | source: hosted
285 | version: "2.2.1"
286 | percent_indicator:
287 | dependency: "direct main"
288 | description:
289 | name: percent_indicator
290 | sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c
291 | url: "https://pub.dev"
292 | source: hosted
293 | version: "4.2.3"
294 | petitparser:
295 | dependency: transitive
296 | description:
297 | name: petitparser
298 | sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
299 | url: "https://pub.dev"
300 | source: hosted
301 | version: "5.4.0"
302 | platform:
303 | dependency: transitive
304 | description:
305 | name: platform
306 | sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
307 | url: "https://pub.dev"
308 | source: hosted
309 | version: "3.1.3"
310 | plugin_platform_interface:
311 | dependency: transitive
312 | description:
313 | name: plugin_platform_interface
314 | sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
315 | url: "https://pub.dev"
316 | source: hosted
317 | version: "2.1.6"
318 | provider:
319 | dependency: "direct main"
320 | description:
321 | name: provider
322 | sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
323 | url: "https://pub.dev"
324 | source: hosted
325 | version: "6.0.5"
326 | sky_engine:
327 | dependency: transitive
328 | description: flutter
329 | source: sdk
330 | version: "0.0.99"
331 | source_span:
332 | dependency: transitive
333 | description:
334 | name: source_span
335 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
336 | url: "https://pub.dev"
337 | source: hosted
338 | version: "1.10.0"
339 | stack_trace:
340 | dependency: transitive
341 | description:
342 | name: stack_trace
343 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
344 | url: "https://pub.dev"
345 | source: hosted
346 | version: "1.11.0"
347 | stream_channel:
348 | dependency: transitive
349 | description:
350 | name: stream_channel
351 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
352 | url: "https://pub.dev"
353 | source: hosted
354 | version: "2.1.1"
355 | string_scanner:
356 | dependency: transitive
357 | description:
358 | name: string_scanner
359 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
360 | url: "https://pub.dev"
361 | source: hosted
362 | version: "1.2.0"
363 | term_glyph:
364 | dependency: transitive
365 | description:
366 | name: term_glyph
367 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
368 | url: "https://pub.dev"
369 | source: hosted
370 | version: "1.2.1"
371 | test_api:
372 | dependency: transitive
373 | description:
374 | name: test_api
375 | sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
376 | url: "https://pub.dev"
377 | source: hosted
378 | version: "0.6.0"
379 | tint:
380 | dependency: transitive
381 | description:
382 | name: tint
383 | sha256: "9652d9a589f4536d5e392cf790263d120474f15da3cf1bee7f1fdb31b4de5f46"
384 | url: "https://pub.dev"
385 | source: hosted
386 | version: "2.0.1"
387 | typed_data:
388 | dependency: transitive
389 | description:
390 | name: typed_data
391 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
392 | url: "https://pub.dev"
393 | source: hosted
394 | version: "1.3.2"
395 | vector_graphics:
396 | dependency: transitive
397 | description:
398 | name: vector_graphics
399 | sha256: b16dadf7eb610e20da044c141b4a0199a5e8082ca21daba68322756f953ce714
400 | url: "https://pub.dev"
401 | source: hosted
402 | version: "1.1.9"
403 | vector_graphics_codec:
404 | dependency: transitive
405 | description:
406 | name: vector_graphics_codec
407 | sha256: a4b01403d5c613db115e30e71eca33f7e9e09f2d3c52c3fb84e16333ecddc539
408 | url: "https://pub.dev"
409 | source: hosted
410 | version: "1.1.9"
411 | vector_graphics_compiler:
412 | dependency: transitive
413 | description:
414 | name: vector_graphics_compiler
415 | sha256: d26c0e2f237476426523eb25512e4c09fa27c6d33ed659a0e69d79e20b5dc47f
416 | url: "https://pub.dev"
417 | source: hosted
418 | version: "1.1.9"
419 | vector_math:
420 | dependency: transitive
421 | description:
422 | name: vector_math
423 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
424 | url: "https://pub.dev"
425 | source: hosted
426 | version: "2.1.4"
427 | web:
428 | dependency: transitive
429 | description:
430 | name: web
431 | sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
432 | url: "https://pub.dev"
433 | source: hosted
434 | version: "0.1.4-beta"
435 | win32:
436 | dependency: transitive
437 | description:
438 | name: win32
439 | sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
440 | url: "https://pub.dev"
441 | source: hosted
442 | version: "5.0.9"
443 | xdg_directories:
444 | dependency: transitive
445 | description:
446 | name: xdg_directories
447 | sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
448 | url: "https://pub.dev"
449 | source: hosted
450 | version: "1.0.3"
451 | xml:
452 | dependency: transitive
453 | description:
454 | name: xml
455 | sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
456 | url: "https://pub.dev"
457 | source: hosted
458 | version: "6.3.0"
459 | yaml:
460 | dependency: transitive
461 | description:
462 | name: yaml
463 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
464 | url: "https://pub.dev"
465 | source: hosted
466 | version: "3.1.2"
467 | sdks:
468 | dart: ">=3.1.2 <4.0.0"
469 | flutter: ">=3.13.5"
470 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: analog_clock
2 | description: A new Flutter project.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `pub publish`. This is preferred for private packages.
6 | publish_to: "none" # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 1.0.0+1
19 |
20 | environment:
21 | sdk: ">=3.1.2 <4.0.0"
22 | flutter: ">=3.13.5"
23 |
24 | dependencies:
25 | flutter:
26 | sdk: flutter
27 |
28 | # The following adds the Cupertino Icons font to your application.
29 | # Use with the CupertinoIcons class for iOS style icons.
30 | cupertino_icons: ^1.0.6
31 | google_fonts: ^6.1.0 # it helps us to use google fonts on our app
32 | flutter_svg: ^2.0.7 # it helps us to use SVG in our app
33 | provider: ^6.0.5 # Our state management package
34 | get: ^4.6.6
35 | get_storage: ^2.1.1
36 | intl: ^0.18.0
37 | flutter_neumorphic_plus: ^3.3.0
38 | percent_indicator: ^4.2.3
39 | flutter_phosphor_icons: ^0.0.1+6
40 |
41 | dev_dependencies:
42 | flutter_test:
43 | sdk: flutter
44 | flutter_lints: ^2.0.3
45 | import_sorter: ^4.6.0
46 |
47 | # For information on the generic Dart part of this file, see the
48 | # following page: https://dart.dev/tools/pub/pubspec
49 |
50 | # The following section is specific to Flutter.
51 | flutter:
52 | # The following line ensures that the Material Icons font is
53 | # included with your application, so that you can use the icons in
54 | # the material Icons class.
55 | uses-material-design: true
56 |
57 | # To add assets to your application, add an assets section, like this:
58 | assets:
59 | - assets/icons/
60 | # - images/a_dot_ham.jpeg
61 |
62 | # An image asset can refer to one or more resolution-specific "variants", see
63 | # https://flutter.dev/assets-and-images/#resolution-aware.
64 |
65 | # For details regarding adding assets from package dependencies, see
66 | # https://flutter.dev/assets-and-images/#from-packages
67 |
68 | # To add custom fonts to your application, add a fonts section here,
69 | # in this "flutter" section. Each entry in this list should have a
70 | # "family" key with the font family name, and a "fonts" key with a
71 | # list giving the asset and other descriptors for the font. For
72 | # example:
73 | fonts:
74 | - family: Lato
75 | fonts:
76 | - asset: assets/fonts/Lato-Regular.ttf
77 | # - asset: fonts/Schyler-Italic.ttf
78 | # style: italic
79 | # - family: Trajan Pro
80 | # fonts:
81 | # - asset: fonts/TrajanPro.ttf
82 | # - asset: fonts/TrajanPro_Bold.ttf
83 | # weight: 700
84 | #
85 | # For details regarding fonts from package dependencies,
86 | # see https://flutter.dev/custom-fonts/#from-packages
87 |
--------------------------------------------------------------------------------
/screenshots/bed_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/screenshots/bed_dark.png
--------------------------------------------------------------------------------
/screenshots/bed_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/screenshots/bed_light.png
--------------------------------------------------------------------------------
/screenshots/clock_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/screenshots/clock_dark.png
--------------------------------------------------------------------------------
/screenshots/clock_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/screenshots/clock_light.png
--------------------------------------------------------------------------------
/screenshots/count_down_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/screenshots/count_down_dark.png
--------------------------------------------------------------------------------
/screenshots/count_down_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/screenshots/count_down_light.png
--------------------------------------------------------------------------------
/screenshots/stopwatch_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/screenshots/stopwatch_dark.png
--------------------------------------------------------------------------------
/screenshots/stopwatch_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lambiengcode/analog-clock/3d588ad35ff2aa542f75a576d5a326402c0c5bd0/screenshots/stopwatch_light.png
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | // Flutter imports:
9 | import 'package:flutter/material.dart';
10 |
11 | // Package imports:
12 | import 'package:flutter_test/flutter_test.dart';
13 |
14 | // Project imports:
15 | import 'package:analog_clock/src/app.dart';
16 |
17 | void main() {
18 | testWidgets('Counter increments smoke test', (tester) async {
19 | // Build our app and trigger a frame.
20 | await tester.pumpWidget(const App());
21 |
22 | // Verify that our counter starts at 0.
23 | expect(find.text('0'), findsOneWidget);
24 | expect(find.text('1'), findsNothing);
25 |
26 | // Tap the '+' icon and trigger a frame.
27 | await tester.tap(find.byIcon(Icons.add));
28 | await tester.pump();
29 |
30 | // Verify that our counter has incremented.
31 | expect(find.text('0'), findsNothing);
32 | expect(find.text('1'), findsOneWidget);
33 | });
34 | }
35 |
--------------------------------------------------------------------------------