├── lib ├── alarm │ ├── logic │ │ ├── tasks │ │ │ └── arithmetic.dart │ │ ├── time_icon.dart │ │ └── alarm_time.dart │ ├── screens │ │ ├── try_alarm_action_screen.dart │ │ └── try_alarm_task_screen.dart │ ├── types │ │ ├── range_interval.dart │ │ ├── notification_action.dart │ │ ├── time_of_day_icon.dart │ │ ├── schedules │ │ │ └── alarm_schedule.dart │ │ └── ringing_manager.dart │ ├── utils │ │ ├── alarm_id.dart │ │ └── next_alarm.dart │ ├── data │ │ ├── time_icons.dart │ │ └── alarm_events_sort_options.dart │ └── widgets │ │ └── try_alarm_task_button.dart ├── navigation │ ├── data │ │ ├── visisbility.dart │ │ ├── fullscreen_intent.dart │ │ └── route_observer.dart │ └── types │ │ ├── alignment.dart │ │ ├── quick_action_controller.dart │ │ ├── tab.dart │ │ ├── app_visibility.dart │ │ └── routes.dart ├── theme │ ├── types │ │ ├── dark_mode.dart │ │ └── theme_brightness.dart │ ├── logic │ │ └── theme_extension.dart │ ├── shape.dart │ ├── dialog.dart │ ├── toggle_buttons.dart │ ├── border.dart │ ├── radio.dart │ ├── card.dart │ ├── button.dart │ ├── bottom_sheet.dart │ ├── snackbar.dart │ ├── font.dart │ ├── popup_menu.dart │ ├── time_picker.dart │ ├── switch.dart │ ├── slider.dart │ └── data │ │ └── default_style_themes.dart ├── common │ ├── types │ │ ├── timer_state.dart │ │ ├── notification_type.dart │ │ ├── picker_result.dart │ │ ├── json.dart │ │ ├── clock_settings_types.dart │ │ ├── popup_action.dart │ │ ├── select_choice.dart │ │ ├── schedule_id.dart │ │ ├── list_item.dart │ │ ├── color_picker_type.dart │ │ └── weekday.dart │ ├── utils │ │ ├── id.dart │ │ ├── list_item.dart │ │ ├── list.dart │ │ ├── duration.dart │ │ ├── reorderable_list_decorator.dart │ │ ├── ringtones.dart │ │ ├── weekday_utils.dart │ │ ├── text_size.dart │ │ ├── time_picker_builder.dart │ │ ├── color.dart │ │ ├── time_format.dart │ │ ├── popup_action.dart │ │ ├── file_item.dart │ │ └── date_time.dart │ ├── widgets │ │ ├── list │ │ │ ├── list_footer.dart │ │ │ ├── animated_reorderable_list │ │ │ │ ├── animation │ │ │ │ │ ├── provider │ │ │ │ │ │ └── animation_type.dart │ │ │ │ │ ├── animation.dart │ │ │ │ │ ├── scale_in.dart │ │ │ │ │ ├── fade_in.dart │ │ │ │ │ ├── scale_in_left.dart │ │ │ │ │ ├── scale_in_top.dart │ │ │ │ │ ├── scale_in_bottom.dart │ │ │ │ │ ├── scale_in_right.dart │ │ │ │ │ ├── slide_in_up.dart │ │ │ │ │ ├── slide_in_left.dart │ │ │ │ │ ├── landing.dart │ │ │ │ │ ├── slide_in_right.dart │ │ │ │ │ ├── slide_in_down.dart │ │ │ │ │ ├── flipin_y.dart │ │ │ │ │ ├── flipin_x.dart │ │ │ │ │ └── size_animation.dart │ │ │ │ └── model │ │ │ │ │ └── motion_data.dart │ │ │ ├── static_list_view.dart │ │ │ ├── list_item_measurer.dart │ │ │ └── delete_alert_dialogue.dart │ │ ├── card_button.dart │ │ ├── color_box.dart │ │ ├── clock │ │ │ └── time_display.dart │ │ ├── fields │ │ │ └── select_field │ │ │ │ ├── field_cards │ │ │ │ ├── color_field_card.dart │ │ │ │ └── audio_field_card.dart │ │ │ │ └── option_cards │ │ │ │ └── color_option_card.dart │ │ └── measure_size.dart │ ├── logic │ │ ├── tags.dart │ │ └── customize_screen.dart │ └── data │ │ ├── default_tags.dart │ │ └── animations.dart ├── clock │ ├── types │ │ └── time.dart │ ├── logic │ │ ├── initialize_default_favorite_cities.dart │ │ └── timezone_database.dart │ └── data │ │ └── default_favorite_cities.dart ├── notifications │ ├── data │ │ ├── action_keys.dart │ │ ├── update_notification_intervals.dart │ │ └── fullscreen_notification_data.dart │ ├── types │ │ ├── fullscreen_notification_data.dart │ │ └── alarm_notification_arguments.dart │ ├── logic │ │ ├── notifications_listeners.dart │ │ ├── notifications.dart │ │ └── foreground_task.dart │ └── widgets │ │ └── notification_actions │ │ └── slide_notification_action.dart ├── settings │ ├── utils │ │ └── description.dart │ ├── types │ │ ├── vendor.dart │ │ ├── backup_option.dart │ │ ├── listener_manager.dart │ │ ├── setting_action.dart │ │ └── setting_link.dart │ ├── data │ │ └── accessibility_settings_schema.dart │ ├── logic │ │ └── backup.dart │ └── widgets │ │ ├── color_setting_card.dart │ │ ├── switch_setting_card.dart │ │ └── date_setting_card.dart ├── developer │ ├── types │ │ └── log_filter.dart │ ├── data │ │ ├── log_sort_options.dart │ │ └── log_list_filters.dart │ └── logic │ │ └── logger.dart ├── system │ ├── data │ │ ├── device_info.dart │ │ └── app_info.dart │ └── logic │ │ ├── permissions.dart │ │ ├── initialize_isolate_ports.dart │ │ ├── initialize_isolate.dart │ │ ├── quick_actions.dart │ │ └── handle_boot.dart ├── timer │ ├── logic │ │ └── initialize_default_timer_presets.dart │ ├── data │ │ ├── default_timer_presets.dart │ │ └── timer_list_filters.dart │ ├── utils │ │ └── timer_id.dart │ └── widgets │ │ └── timer_duration_picker.dart ├── audio │ ├── logic │ │ └── audio_session.dart │ ├── types │ │ └── ringtone_manager.dart │ └── audio_channels.dart └── stopwatch │ └── logic │ └── update_stopwatch.dart ├── cover.png ├── icon.png ├── fastlane └── metadata │ └── android │ ├── zh-CN │ ├── short_description.txt │ └── full_description.txt │ ├── en-US │ ├── short_description.txt │ ├── images │ │ ├── icon.png │ │ └── phoneScreenshots │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ └── 5.png │ ├── changelogs │ │ ├── 181.txt │ │ ├── 182.txt │ │ ├── 183.txt │ │ ├── 241.txt │ │ ├── 242.txt │ │ ├── 243.txt │ │ ├── 271.txt │ │ ├── 272.txt │ │ ├── 273.txt │ │ ├── 251.txt │ │ ├── 252.txt │ │ ├── 253.txt │ │ ├── 221.txt │ │ ├── 222.txt │ │ ├── 223.txt │ │ ├── 212.txt │ │ ├── 211.txt │ │ ├── 213.txt │ │ ├── 171.txt │ │ ├── 172.txt │ │ ├── 173.txt │ │ ├── 191.txt │ │ ├── 192.txt │ │ ├── 193.txt │ │ ├── 201.txt │ │ ├── 202.txt │ │ ├── 203.txt │ │ ├── 261.txt │ │ ├── 262.txt │ │ ├── 263.txt │ │ ├── 281.txt │ │ ├── 282.txt │ │ └── 283.txt │ └── full_description.txt │ ├── pl-PL │ ├── short_description.txt │ └── full_description.txt │ ├── tr-TR │ ├── short_description.txt │ └── full_description.txt │ ├── de-DE │ ├── short_description.txt │ └── full_description.txt │ ├── es-ES │ ├── short_description.txt │ └── full_description.txt │ ├── no-NO │ ├── short_description.txt │ └── full_description.txt │ ├── pt │ └── short_description.txt │ ├── uk │ ├── short_description.txt │ └── full_description.txt │ ├── fr-FR │ ├── short_description.txt │ └── full_description.txt │ ├── it-IT │ └── short_description.txt │ ├── vi │ ├── short_description.txt │ └── full_description.txt │ └── ru-RU │ ├── short_description.txt │ └── full_description.txt ├── assets ├── timezones.db ├── images │ └── logo.png ├── ringtones │ └── default.mp3 ├── contributors │ └── avatars │ │ ├── 100072714?v=4.jpg │ │ ├── 106187527?v=4.jpg │ │ ├── 106683928?v=4.jpg │ │ ├── 107004413?v=4.jpg │ │ ├── 10844456?v=4.jpg │ │ ├── 108967802?v=4.jpg │ │ ├── 110881926?v=4.jpg │ │ ├── 11250480?v=4.jpg │ │ ├── 11271828?v=4.jpg │ │ ├── 125894401?v=4.jpg │ │ ├── 132745784?v=4.jpg │ │ ├── 134877893?v=4.jpg │ │ ├── 137100988?v=4.jpg │ │ ├── 13767301?v=4.jpg │ │ ├── 13802408?v=4.jpg │ │ ├── 145045422?v=4.jpg │ │ ├── 145642963?v=4.jpg │ │ ├── 1607653?v=4.jpg │ │ ├── 170783727?v=4.jpg │ │ ├── 23003062?v=4.jpg │ │ ├── 23407397?v=4.jpg │ │ ├── 24733391?v=4.jpg │ │ ├── 3691490?v=4.jpg │ │ ├── 38784748?v=4.jpg │ │ ├── 39169351?v=4.jpg │ │ ├── 4150623?v=4.jpg │ │ ├── 41967492?v=4.jpg │ │ ├── 45366162?v=4.jpg │ │ ├── 46320254?v=4.jpg │ │ ├── 55799205?v=4.jpg │ │ ├── 56921008?v=4.jpg │ │ ├── 64812183?v=4.jpg │ │ ├── 65224669?v=4.jpg │ │ ├── 65340361?v=4.jpg │ │ ├── 66135366?v=4.jpg │ │ ├── 67970539?v=4.jpg │ │ ├── 69535896?v=4.jpg │ │ ├── 75314629?v=4.jpg │ │ ├── 79773329?v=4.jpg │ │ ├── 79972075?v=4.jpg │ │ ├── 80152003?v=4.jpg │ │ ├── 81525287?v=4.jpg │ │ ├── 82556573?v=4.jpg │ │ ├── 84540569?v=4.jpg │ │ ├── 88676873?v=4.jpg │ │ └── 91787031?v=4.jpg └── patreons │ └── patreons.json ├── fonts ├── FluxIcons.ttf └── Rubik │ └── Rubik-VariableFont.ttf ├── l10n.yaml ├── android ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── app │ └── src │ │ ├── dev │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── alarm_icon.png │ │ │ │ ├── clock_icon.png │ │ │ │ ├── timer_icon.png │ │ │ │ ├── stopwatch_icon.png │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ └── ic_launcher.xml │ │ │ ├── drawable-v21 │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── values │ │ │ │ └── styles.xml │ │ │ └── values-night │ │ │ │ └── styles.xml │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── alarm_icon.png │ │ │ │ ├── clock_icon.png │ │ │ │ ├── timer_icon.png │ │ │ │ ├── ic_alarm_icon.png │ │ │ │ ├── stopwatch_icon.png │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_background.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ └── ic_launcher.xml │ │ │ ├── drawable-v21 │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── xml │ │ │ │ ├── analogue_clock_widget.xml │ │ │ │ └── digital_clock_widget.xml │ │ │ ├── layout │ │ │ │ ├── digital_date.xml │ │ │ │ └── digital_clock.xml │ │ │ └── values-night │ │ │ │ └── styles.xml │ │ └── kotlin │ │ │ └── com │ │ │ └── vicolo │ │ │ └── chrono │ │ │ └── MainActivity.kt │ │ ├── debug │ │ └── AndroidManifest.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── .gitignore ├── build.gradle └── settings.gradle ├── CONTRIBUTING.md ├── .vscode └── settings.json ├── .github ├── workflows │ ├── tests.yml │ └── clear-cache.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── FUNDING.yml ├── test ├── common │ └── utils │ │ ├── duration_utils_test.dart │ │ ├── date_time_utils_test.dart │ │ └── weekday_utils_test.dart ├── clock │ └── widgets │ │ └── time_display_test.dart └── settings │ └── widget │ └── setting_group_card_test.dart ├── .gitignore └── scripts └── patreons.py /lib/alarm/logic/tasks/arithmetic.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/navigation/data/visisbility.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/alarm/screens/try_alarm_action_screen.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/cover.png -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/icon.png -------------------------------------------------------------------------------- /lib/theme/types/dark_mode.dart: -------------------------------------------------------------------------------- 1 | enum DarkMode { user, system, nightDay } 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/short_description.txt: -------------------------------------------------------------------------------- 1 | 时尚又强大的时钟,闹钟,计时器和秒表应用。 2 | -------------------------------------------------------------------------------- /lib/common/types/timer_state.dart: -------------------------------------------------------------------------------- 1 | enum TimerState { stopped, running, paused } 2 | -------------------------------------------------------------------------------- /lib/theme/types/theme_brightness.dart: -------------------------------------------------------------------------------- 1 | enum ThemeBrightness { light, dark, system } 2 | -------------------------------------------------------------------------------- /assets/timezones.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/timezones.db -------------------------------------------------------------------------------- /fonts/FluxIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/fonts/FluxIcons.ttf -------------------------------------------------------------------------------- /lib/alarm/types/range_interval.dart: -------------------------------------------------------------------------------- 1 | enum RangeInterval { 2 | daily, 3 | weekly, 4 | } 5 | -------------------------------------------------------------------------------- /lib/clock/types/time.dart: -------------------------------------------------------------------------------- 1 | enum TimeFormat { 2 | h24, 3 | h12, 4 | device, 5 | } 6 | -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/images/logo.png -------------------------------------------------------------------------------- /lib/navigation/data/fullscreen_intent.dart: -------------------------------------------------------------------------------- 1 | const fullscreenIntentKey = "fullscreen_intent"; 2 | -------------------------------------------------------------------------------- /lib/navigation/types/alignment.dart: -------------------------------------------------------------------------------- 1 | enum ElementAlignment { 2 | start, 3 | end, 4 | center, 5 | } 6 | -------------------------------------------------------------------------------- /assets/ringtones/default.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/ringtones/default.mp3 -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | Modern and powerful clock, alarms, timer and stopwatch. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/pl-PL/short_description.txt: -------------------------------------------------------------------------------- 1 | Nowoczesny i potężny zegar, budzik, minutnik i stoper. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/tr-TR/short_description.txt: -------------------------------------------------------------------------------- 1 | Modern ve güçlü saat, alarm, zamanlayıcı ve kronometre. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/short_description.txt: -------------------------------------------------------------------------------- 1 | Moderne und funktionsreich Uhr, Wecker, Timer und Stoppuhr. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/es-ES/short_description.txt: -------------------------------------------------------------------------------- 1 | Reloj, alarmas, cronómetro y cronómetro moderno y potente. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/no-NO/short_description.txt: -------------------------------------------------------------------------------- 1 | Moderne og kraftig ur, alarmklokke, tidsur, og stoppeklokke. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/pt/short_description.txt: -------------------------------------------------------------------------------- 1 | Relógio, alarme, temporizador e cronómetro moderno e poderoso. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/uk/short_description.txt: -------------------------------------------------------------------------------- 1 | Сучасний і потужний годинник, будильник, таймер і секундомір. 2 | -------------------------------------------------------------------------------- /l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: lib/l10n 2 | template-arb-file: app_en.arb 3 | output-localization-file: app_localizations.dart 4 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/fr-FR/short_description.txt: -------------------------------------------------------------------------------- 1 | Horloge, alarmes, minuterie et chronomètre modernes et puissants. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/it-IT/short_description.txt: -------------------------------------------------------------------------------- 1 | Potente e moderno orologio, allarmi, temporizzatore e cronometro. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/vi/short_description.txt: -------------------------------------------------------------------------------- 1 | Đồng hồ, báo thức, hẹn giờ và đồng hồ bấm giờ hiện đại và mạnh mẽ. 2 | -------------------------------------------------------------------------------- /fonts/Rubik/Rubik-VariableFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/fonts/Rubik/Rubik-VariableFont.ttf -------------------------------------------------------------------------------- /lib/common/types/notification_type.dart: -------------------------------------------------------------------------------- 1 | 2 | enum ScheduledNotificationType { 3 | alarm, 4 | timer, 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ru-RU/short_description.txt: -------------------------------------------------------------------------------- 1 | Современные и многофункциональные часы, будильник, таймер и секундомер. 2 | -------------------------------------------------------------------------------- /lib/common/utils/id.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | int getId() { 4 | return UniqueKey().hashCode; 5 | } 6 | -------------------------------------------------------------------------------- /lib/notifications/data/action_keys.dart: -------------------------------------------------------------------------------- 1 | const String snoozeActionKey = "snooze"; 2 | const String dismissActionKey = "dismiss"; 3 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /assets/contributors/avatars/100072714?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/100072714?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/106187527?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/106187527?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/106683928?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/106683928?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/107004413?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/107004413?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/10844456?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/10844456?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/108967802?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/108967802?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/110881926?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/110881926?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/11250480?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/11250480?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/11271828?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/11271828?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/125894401?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/125894401?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/132745784?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/132745784?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/134877893?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/134877893?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/137100988?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/137100988?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/13767301?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/13767301?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/13802408?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/13802408?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/145045422?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/145045422?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/145642963?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/145642963?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/1607653?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/1607653?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/170783727?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/170783727?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/23003062?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/23003062?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/23407397?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/23407397?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/24733391?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/24733391?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/3691490?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/3691490?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/38784748?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/38784748?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/39169351?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/39169351?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/4150623?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/4150623?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/41967492?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/41967492?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/45366162?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/45366162?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/46320254?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/46320254?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/55799205?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/55799205?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/56921008?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/56921008?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/64812183?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/64812183?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/65224669?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/65224669?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/65340361?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/65340361?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/66135366?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/66135366?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/67970539?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/67970539?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/69535896?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/69535896?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/75314629?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/75314629?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/79773329?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/79773329?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/79972075?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/79972075?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/80152003?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/80152003?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/81525287?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/81525287?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/82556573?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/82556573?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/84540569?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/84540569?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/88676873?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/88676873?v=4.jpg -------------------------------------------------------------------------------- /assets/contributors/avatars/91787031?v=4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/assets/contributors/avatars/91787031?v=4.jpg -------------------------------------------------------------------------------- /android/app/src/dev/res/drawable/alarm_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/drawable/alarm_icon.png -------------------------------------------------------------------------------- /android/app/src/dev/res/drawable/clock_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/drawable/clock_icon.png -------------------------------------------------------------------------------- /android/app/src/dev/res/drawable/timer_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/drawable/timer_icon.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/fastlane/metadata/android/en-US/images/icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/alarm_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/drawable/alarm_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/clock_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/drawable/clock_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/timer_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/drawable/timer_icon.png -------------------------------------------------------------------------------- /android/app/src/dev/res/drawable/stopwatch_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/drawable/stopwatch_icon.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_alarm_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/drawable/ic_alarm_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/stopwatch_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/drawable/stopwatch_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/common/types/picker_result.dart: -------------------------------------------------------------------------------- 1 | class PickerResult { 2 | T value; 3 | bool isCustomize; 4 | PickerResult(this.value, this.isCustomize); 5 | } 6 | -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/settings/utils/description.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | String defaultDescription(BuildContext context) { 4 | return ""; 5 | } 6 | -------------------------------------------------------------------------------- /lib/navigation/data/route_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | final RouteObserver routeObserver = RouteObserver(); 4 | -------------------------------------------------------------------------------- /lib/notifications/data/update_notification_intervals.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | Timer? stopwatchNotificationInterval; 4 | Timer? timerNotificationInterval; 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-hdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-hdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-mdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-mdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/181.txt: -------------------------------------------------------------------------------- 1 | Quick smol update :) 2 | 3 | 🐛 Fixes 4 | 5 | * Fixes all one time alarms getting disabled after alarm ringing or opening app 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/182.txt: -------------------------------------------------------------------------------- 1 | Quick smol update :) 2 | 3 | 🐛 Fixes 4 | 5 | * Fixes all one time alarms getting disabled after alarm ringing or opening app 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/183.txt: -------------------------------------------------------------------------------- 1 | Quick smol update :) 2 | 3 | 🐛 Fixes 4 | 5 | * Fixes all one time alarms getting disabled after alarm ringing or opening app 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicolo-dev/chrono/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | #262D2D2D 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/theme/logic/theme_extension.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter/material.dart'; 2 | // 3 | // T getThemeExtension (ThemeData theme) { 4 | // return theme.extension() ?? const T(); 5 | // 6 | // } 7 | -------------------------------------------------------------------------------- /lib/developer/types/log_filter.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart'; 2 | 3 | class FileLogFilter extends LogFilter { 4 | @override 5 | bool shouldLog(LogEvent event) { 6 | return true; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lib/common/types/json.dart: -------------------------------------------------------------------------------- 1 | typedef Json = Map?; 2 | 3 | abstract class JsonSerializable { 4 | const JsonSerializable(); 5 | 6 | JsonSerializable.fromJson(Json json); 7 | Json toJson(); 8 | } 9 | -------------------------------------------------------------------------------- /lib/common/utils/list_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/list_item.dart'; 2 | 3 | List copyItemList(List list) { 4 | return list.map((element) => element.copy() as T).toList(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/theme/shape.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/border.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | const OutlinedBorder defaultShape = RoundedRectangleBorder( 5 | borderRadius: defaultBorderRadius, 6 | ); 7 | -------------------------------------------------------------------------------- /lib/common/utils/list.dart: -------------------------------------------------------------------------------- 1 | extension ListUtils on List{ 2 | List rotate(int rotate){ 3 | if(isEmpty) return this; 4 | var index = rotate % length; 5 | return sublist(index)..addAll(sublist(0, index)); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lib/common/types/clock_settings_types.dart: -------------------------------------------------------------------------------- 1 | enum ClockNumeralType{ 2 | arabic, 3 | roman, 4 | } 5 | 6 | enum ClockTicksType{ 7 | none, 8 | major, 9 | all, 10 | } 11 | 12 | enum ClockNumbersType { none, quarter, all } 13 | 14 | -------------------------------------------------------------------------------- /lib/theme/dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/shape.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | const DialogTheme dialogTheme = DialogTheme( 5 | shape: defaultShape, 6 | surfaceTintColor: Colors.transparent, 7 | ); 8 | -------------------------------------------------------------------------------- /lib/theme/toggle_buttons.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/border.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | ToggleButtonsThemeData toggleButtonsTheme = const ToggleButtonsThemeData( 5 | borderRadius: defaultBorderRadius, 6 | ); 7 | -------------------------------------------------------------------------------- /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.6.4-all.zip 6 | -------------------------------------------------------------------------------- /lib/theme/border.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const BorderRadius defaultBorderRadius = BorderRadius.all( 4 | Radius.circular(16), 5 | ); 6 | 7 | const BorderRadius defaultTopBorderRadius = 8 | BorderRadius.vertical(top: Radius.circular(12)); 9 | -------------------------------------------------------------------------------- /android/app/src/dev/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /lib/common/types/popup_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MenuAction { 4 | IconData icon; 5 | String name; 6 | Function(BuildContext context) action; 7 | Color? color; 8 | 9 | MenuAction(this.name, this.action, this.icon, [this.color]); 10 | } 11 | -------------------------------------------------------------------------------- /lib/system/data/device_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:device_info_plus/device_info_plus.dart'; 2 | 3 | AndroidDeviceInfo? androidInfo; 4 | 5 | Future initializeAndroidInfo() async { 6 | DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); 7 | androidInfo = await deviceInfo.androidInfo; 8 | } 9 | -------------------------------------------------------------------------------- /lib/timer/logic/initialize_default_timer_presets.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/utils/list_storage.dart'; 2 | import 'package:clock_app/timer/data/default_timer_presets.dart'; 3 | 4 | 5 | void initializeDefaultTimerPresets() { 6 | saveList('timer_presets', defaultTimerPresets); 7 | } 8 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/241.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Updated translations 4 | 5 | 🐛 Fixes 6 | 7 | * Removed extra space at the end of long date formats 8 | * Fix timer fullscreen notification not dismissing 9 | * Fix fastest and slowest laps of stopwatch not saving 10 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/242.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Updated translations 4 | 5 | 🐛 Fixes 6 | 7 | * Removed extra space at the end of long date formats 8 | * Fix timer fullscreen notification not dismissing 9 | * Fix fastest and slowest laps of stopwatch not saving 10 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/243.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Updated translations 4 | 5 | 🐛 Fixes 6 | 7 | * Removed extra space at the end of long date formats 8 | * Fix timer fullscreen notification not dismissing 9 | * Fix fastest and slowest laps of stopwatch not saving 10 | -------------------------------------------------------------------------------- /lib/clock/logic/initialize_default_favorite_cities.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/clock/data/default_favorite_cities.dart'; 2 | import 'package:clock_app/common/utils/list_storage.dart'; 3 | 4 | void initializeDefaultFavoriteCities() { 5 | saveList('favorite_cities', initialFavoriteCities); 6 | } 7 | -------------------------------------------------------------------------------- /lib/common/widgets/list/list_footer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ListFooter extends StatelessWidget { 4 | const ListFooter({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return const SizedBox(height: 64); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/theme/radio.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/types/color_scheme.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | RadioThemeData getRadioTheme(ColorSchemeData colorScheme) { 5 | return RadioThemeData( 6 | fillColor: MaterialStateProperty.all(colorScheme.accent), 7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /lib/navigation/types/quick_action_controller.dart: -------------------------------------------------------------------------------- 1 | class QuickActionController { 2 | Function(String name)? _action; 3 | 4 | void setAction(Function(String name)? action) { 5 | _action = action; 6 | } 7 | 8 | void callAction(String name) { 9 | _action?.call(name); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/alarm/logic/time_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/data/time_icons.dart'; 2 | import 'package:clock_app/common/types/time.dart'; 3 | import 'package:clock_app/alarm/types/time_of_day_icon.dart'; 4 | 5 | TimeIcon getTimeIcon(Time time) => timeIcons 6 | .firstWhere((icon) => time.isBetween(icon.startTime, icon.endTime)); 7 | -------------------------------------------------------------------------------- /lib/alarm/types/notification_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NotificationAction { 4 | final void Function(VoidCallback onDismiss, VoidCallback? onSnooze, 5 | String dismissLabel, String snoozeLabel) builder; 6 | 7 | const NotificationAction({ 8 | required this.builder, 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /lib/theme/card.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/shape.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | const defaultElevation = 1.0; 5 | 6 | const cardTheme = CardTheme( 7 | shape: defaultShape, 8 | clipBehavior: Clip.hardEdge, 9 | elevation: defaultElevation, 10 | surfaceTintColor: Colors.transparent, 11 | ); 12 | -------------------------------------------------------------------------------- /lib/navigation/types/tab.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class Tab { 4 | final String id; 5 | final String title; 6 | final IconData icon; 7 | final Widget widget; 8 | 9 | Tab({ 10 | required this.id, 11 | required this.title, 12 | required this.icon, 13 | required this.widget, 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /lib/alarm/types/time_of_day_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/time.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class TimeIcon { 5 | final IconData icon; 6 | final Color color; 7 | final Time startTime; 8 | final Time endTime; 9 | 10 | TimeIcon(this.icon, this.color, this.startTime, this.endTime); 11 | } 12 | -------------------------------------------------------------------------------- /lib/clock/data/default_favorite_cities.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/clock/types/city.dart'; 2 | 3 | List initialFavoriteCities = [ 4 | City("New York City", "United States", "America/New_York"), 5 | City("London", "United Kingdom", "Europe/London"), 6 | City("Paris", "France", "Europe/Paris"), 7 | City("Tokyo", "Japan", "Asia/Tokyo"), 8 | ]; 9 | -------------------------------------------------------------------------------- /lib/notifications/types/fullscreen_notification_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/json.dart'; 2 | 3 | class FullScreenNotificationData { 4 | int id; 5 | final String route; 6 | 7 | FullScreenNotificationData({ 8 | required this.id, 9 | required this.route, 10 | }); 11 | } 12 | 13 | typedef Payload = Json; 14 | 15 | 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/common/utils/duration.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/timer/types/time_duration.dart'; 2 | 3 | extension DurationUtils on Duration { 4 | TimeDuration toTimeDuration() => TimeDuration( 5 | hours: inHours, 6 | minutes: inMinutes % 60, 7 | seconds: inSeconds % 60, 8 | milliseconds: inMilliseconds % 1000, 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/provider/animation_type.dart: -------------------------------------------------------------------------------- 1 | enum AnimationType { 2 | fadeIn, 3 | flipInY, 4 | flipInX, 5 | landing, 6 | size, 7 | scaleIn, 8 | scaleInTop, 9 | scaleInBottom, 10 | scaleInLeft, 11 | scaleInRight, 12 | slideInLeft, 13 | slideInRight, 14 | slideInDown, 15 | slideInUp, 16 | } 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | All contributions are welcome, so feel free to create a pull request. When contributing to this repository, please first discuss the change you wish to make via an issue. 4 | 5 | ## Coding Standards 6 | Please refer to [Effective Dart](https://dart.dev/effective-dart) as a guideline for the coding standards expected from pull requests. 7 | -------------------------------------------------------------------------------- /lib/common/types/select_choice.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SelectChoice { 4 | final String description; 5 | final String name; 6 | final T value; 7 | final Color? color; 8 | 9 | const SelectChoice( 10 | {required this.value, 11 | required this.name, 12 | this.description = "", 13 | this.color}); 14 | } 15 | -------------------------------------------------------------------------------- /lib/alarm/utils/alarm_id.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/types/alarm.dart'; 2 | import 'package:clock_app/common/utils/list_storage.dart'; 3 | 4 | Alarm? getAlarmById(int id) { 5 | try { 6 | final List alarms = loadListSync('alarms'); 7 | return alarms.firstWhere((alarm) => alarm.hasScheduleWithId(id)); 8 | } catch (e) { 9 | return null; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "AARRGGBB", 4 | "Animatable", 5 | "Cupertino", 6 | "dartpad", 7 | "endtemplate", 8 | "fullscreen", 9 | "fuzzywuzzy", 10 | "Layouter", 11 | "LTWH", 12 | "RGBO", 13 | "RRGGBB", 14 | "sublist", 15 | "Tappable", 16 | "unawaited", 17 | "unfocus", 18 | "Unmanaged" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /lib/common/logic/tags.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/tag.dart'; 2 | import 'package:clock_app/common/utils/list_storage.dart'; 3 | import 'package:clock_app/settings/types/setting.dart'; 4 | 5 | List> getTagOptions() { 6 | return loadListSync("tags") 7 | .map((tag) => SelectSettingOption((context)=>tag.name, tag)) 8 | .toList(); 9 | } 10 | -------------------------------------------------------------------------------- /lib/system/data/app_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:package_info_plus/package_info_plus.dart'; 2 | 3 | PackageInfo? packageInfo; 4 | 5 | Future initializePackageInfo() async { 6 | packageInfo = await PackageInfo.fromPlatform(); 7 | } 8 | 9 | String getAppName() { 10 | return '${packageInfo?.appName ?? 'Chrono'}${(packageInfo?.packageName.contains("dev") ?? false) ? " Dev" : ""}'; 11 | } 12 | -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /lib/theme/button.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/font.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | TextButtonThemeData textButtonTheme = TextButtonThemeData( 5 | style: TextButton.styleFrom( 6 | textStyle: const TextStyle( 7 | fontSize: 32, 8 | fontVariations: FontVariations.extraBold, 9 | // color: Theme.of(context).colorScheme.onBackground, 10 | ), 11 | ), 12 | ); 13 | -------------------------------------------------------------------------------- /lib/common/data/default_tags.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/tag.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | List defaultTags = [ 5 | Tag("Work", color: Colors.green), 6 | Tag("Home", color: Colors.blue), 7 | Tag("Personal", color: Colors.purple), 8 | Tag("School", color: Colors.orange), 9 | Tag("Shopping", color: Colors.red), 10 | Tag("Health", color: Colors.pink), 11 | ]; 12 | -------------------------------------------------------------------------------- /lib/settings/types/vendor.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/json.dart'; 2 | 3 | class Vendor { 4 | final String name; 5 | final String url; 6 | 7 | const Vendor({ 8 | required this.name, 9 | required this.url, 10 | }); 11 | 12 | Vendor.fromJson(Json json) 13 | : name = json != null ? json['name'] ?? 'Unknown' : 'Unknown', 14 | url = json != null ? json['url'] ?? '' : ''; 15 | } 16 | -------------------------------------------------------------------------------- /lib/common/utils/reorderable_list_decorator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Widget reorderableListDecorator(BuildContext context, Widget? child) { 4 | return Material( 5 | shadowColor: Colors.black.withOpacity(0.3), 6 | shape: Theme.of(context).cardTheme.shape, 7 | elevation: Theme.of(context).cardTheme.elevation! * 6, 8 | color: Colors.transparent, 9 | child: child, 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /lib/common/widgets/card_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/card_container.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class CardButton extends StatelessWidget { 5 | const CardButton({super.key}); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return const CardContainer( 10 | child: Padding( 11 | padding: EdgeInsets.all(8.0), 12 | )); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/system/logic/permissions.dart: -------------------------------------------------------------------------------- 1 | import 'package:permission_handler/permission_handler.dart'; 2 | 3 | Future requestBatteryOptimizationPermission( 4 | {Function? onAlreadyGranted}) async { 5 | var status = await Permission.ignoreBatteryOptimizations.status; 6 | if (!status.isGranted) { 7 | await Permission.ignoreBatteryOptimizations.request(); 8 | } else { 9 | onAlreadyGranted?.call(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /assets/patreons/patreons.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Thorsten", 4 | "lifetime_amount": "53.76", 5 | "email": "patreon.com@th23.net" 6 | }, 7 | { 8 | "name": "Potato", 9 | "lifetime_amount": "7.36", 10 | "email": "patreon@cinna.boo" 11 | }, 12 | { 13 | "name": "AnotherOnlineAlias", 14 | "lifetime_amount": "3.36", 15 | "email": "jakegbh4949@gmail.com" 16 | } 17 | ] -------------------------------------------------------------------------------- /lib/common/utils/ringtones.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/file_item.dart'; 2 | import 'package:clock_app/common/utils/list_storage.dart'; 3 | import 'package:clock_app/settings/types/setting.dart'; 4 | 5 | List> getRingtoneOptions() { 6 | return loadListSync("ringtones") 7 | .map((ringtone) => SelectSettingOption((context)=>ringtone.name, ringtone)) 8 | .toList(); 9 | } 10 | -------------------------------------------------------------------------------- /lib/notifications/types/alarm_notification_arguments.dart: -------------------------------------------------------------------------------- 1 | class AlarmNotificationArguments { 2 | final List scheduleIds; 3 | final bool tasksOnly; 4 | final AlarmDismissType dismissType; 5 | 6 | AlarmNotificationArguments( 7 | {required this.scheduleIds, 8 | required this.tasksOnly, 9 | required this.dismissType}); 10 | } 11 | 12 | enum AlarmDismissType { 13 | dismiss, 14 | skip, 15 | snooze, 16 | unsnooze, 17 | } 18 | -------------------------------------------------------------------------------- /lib/settings/types/backup_option.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BackupOption { 4 | final String Function(BuildContext context) getName; 5 | final String key; 6 | final Future Function() encode; 7 | final Future Function(BuildContext context, dynamic value) decode; 8 | bool selected = true; 9 | 10 | BackupOption(this.key, this.getName, 11 | {required this.encode, required this.decode}); 12 | } 13 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/common/types/schedule_id.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/json.dart'; 2 | 3 | class ScheduleId extends JsonSerializable { 4 | late int id; 5 | 6 | ScheduleId({ 7 | required this.id, 8 | }); 9 | 10 | ScheduleId.fromJson(Json? json) { 11 | if (json == null) { 12 | id = -1; 13 | return; 14 | } 15 | id = json['id'] ?? -1; 16 | } 17 | 18 | @override 19 | Json toJson() => { 20 | 'id': id, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/271.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Added memory (card matching) task 6 | 7 | 🐛 Fixes 8 | 9 | * Added option to disable background service 10 | * Fixed data corruption error in some cases 11 | * Fixed minutes not appearing when 0 12 | * Fixed sound still playing after dismissing alarm in some cases 13 | * Fixed data persisting even after uninstalling app (disabled auto backup) 14 | 15 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/272.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Added memory (card matching) task 6 | 7 | 🐛 Fixes 8 | 9 | * Added option to disable background service 10 | * Fixed data corruption error in some cases 11 | * Fixed minutes not appearing when 0 12 | * Fixed sound still playing after dismissing alarm in some cases 13 | * Fixed data persisting even after uninstalling app (disabled auto backup) 14 | 15 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/273.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Added memory (card matching) task 6 | 7 | 🐛 Fixes 8 | 9 | * Added option to disable background service 10 | * Fixed data corruption error in some cases 11 | * Fixed minutes not appearing when 0 12 | * Fixed sound still playing after dismissing alarm in some cases 13 | * Fixed data persisting even after uninstalling app (disabled auto backup) 14 | 15 | -------------------------------------------------------------------------------- /lib/common/utils/weekday_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/data/weekdays.dart'; 2 | import 'package:clock_app/common/types/weekday.dart'; 3 | 4 | bool weekdaysContains(List alarmWeekdays, int id) { 5 | Weekday weekday = 6 | weekdays.firstWhere((weekday) => weekday.id == id); 7 | return alarmWeekdays.contains(weekday); 8 | } 9 | 10 | bool weekdaysContainsAll(List alarmWeekdays, List ids) { 11 | return ids.every((id) => weekdaysContains(alarmWeekdays, id)); 12 | } 13 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/animation.dart: -------------------------------------------------------------------------------- 1 | export 'fade_in.dart'; 2 | export 'flipin_x.dart'; 3 | export 'flipin_y.dart'; 4 | export 'landing.dart'; 5 | export 'scale_in.dart'; 6 | export 'scale_in_bottom.dart'; 7 | export 'scale_in_left.dart'; 8 | export 'scale_in_right.dart'; 9 | export 'scale_in_top.dart'; 10 | export 'slide_in_down.dart'; 11 | export 'slide_in_left.dart'; 12 | export 'slide_in_right.dart'; 13 | export 'slide_in_up.dart'; 14 | export 'size_animation.dart'; 15 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | maven { url "${project(':background_fetch').projectDir}/libs" } 6 | } 7 | } 8 | 9 | rootProject.buildDir = '../build' 10 | subprojects { 11 | project.buildDir = "${rootProject.buildDir}/${project.name}" 12 | } 13 | subprojects { 14 | project.evaluationDependsOn(':app') 15 | } 16 | 17 | ext.kotlin_version = "1.8.0" 18 | 19 | tasks.register("clean", Delete) { 20 | delete rootProject.buildDir 21 | } 22 | -------------------------------------------------------------------------------- /lib/alarm/utils/next_alarm.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/types/alarm.dart'; 2 | import 'package:clock_app/common/utils/list_storage.dart'; 3 | 4 | Alarm? getNextAlarm() { 5 | List alarms = loadListSync('alarms'); 6 | if (alarms.isEmpty) return null; 7 | alarms.sort((a, b) { 8 | if (a.currentScheduleDateTime == null) return 1; 9 | if (b.currentScheduleDateTime == null) return -1; 10 | return a.currentScheduleDateTime!.compareTo(b.currentScheduleDateTime!); 11 | }); 12 | return alarms.first; 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/dev/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/dev/res/drawable-v21/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lib/common/utils/text_size.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Size calcTextSize(String text, TextStyle style) { 4 | // String text = '0' * length; 5 | final TextPainter textPainter = TextPainter( 6 | text: TextSpan(text: text, style: style), 7 | textDirection: TextDirection.ltr, 8 | textScaleFactor: WidgetsBinding.instance.window.textScaleFactor, 9 | )..layout(); 10 | return textPainter.size; 11 | } 12 | 13 | Size calcTextSizeFromLength(int length, TextStyle style) { 14 | return calcTextSize('0' * length, style); 15 | } 16 | -------------------------------------------------------------------------------- /lib/common/utils/time_picker_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/clock/types/time.dart'; 2 | import 'package:clock_app/settings/data/settings_schema.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | MediaQuery getTimePickerBuilder(BuildContext context, Widget? child) { 6 | bool shouldUse24h = MediaQuery.of(context).alwaysUse24HourFormat || 7 | appSettings.getSetting("Time Format").value == TimeFormat.h24; 8 | 9 | return MediaQuery( 10 | data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: shouldUse24h), 11 | child: child!, 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /lib/timer/data/default_timer_presets.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/timer/types/time_duration.dart'; 2 | import 'package:clock_app/timer/types/timer_preset.dart'; 3 | 4 | List defaultTimerPresets = [ 5 | TimerPreset("1 min", const TimeDuration(minutes: 1)), 6 | TimerPreset("5 min", const TimeDuration(minutes: 5)), 7 | TimerPreset("10 min", const TimeDuration(minutes: 10)), 8 | TimerPreset("Workout", const TimeDuration(minutes: 10)), 9 | TimerPreset("Meditation", const TimeDuration(minutes: 15)), 10 | TimerPreset("Sleep", const TimeDuration(hours: 5)), 11 | ]; 12 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | pull_request: 8 | branches: 9 | - "*" 10 | jobs: 11 | test: 12 | name: Test 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: subosito/flutter-action@v2 18 | with: 19 | flutter-version: '3.22.2' # or, you can use 1.22 20 | channel: 'stable' 21 | cache: true 22 | - run: flutter test --coverage 23 | - name: Upload coverage reports to Codecov 24 | uses: codecov/codecov-action@v3 25 | -------------------------------------------------------------------------------- /test/common/utils/duration_utils_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/utils/duration.dart'; 2 | import 'package:clock_app/timer/types/time_duration.dart'; 3 | import 'package:flutter_test/flutter_test.dart'; 4 | 5 | Duration duration = const Duration(hours: 1, minutes: 30); 6 | 7 | void main() { 8 | group('DurationUtils', () { 9 | test( 10 | 'toTimeDuration() returns correct value', 11 | () { 12 | expect(duration.toTimeDuration().inMilliseconds, 13 | const TimeDuration(hours: 1, minutes: 30).inMilliseconds); 14 | }, 15 | ); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/analogue_clock_widget.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/digital_clock_widget.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | -------------------------------------------------------------------------------- /lib/audio/logic/audio_session.dart: -------------------------------------------------------------------------------- 1 | import 'package:audio_session/audio_session.dart'; 2 | 3 | Future initializeAudioSession( 4 | [AndroidAudioUsage usage = AndroidAudioUsage.media]) async { 5 | final session = await AudioSession.instance; 6 | await session.configure(const AudioSessionConfiguration( 7 | // androidAudioAttributes: AndroidAudioAttributes( 8 | // usage: usage, 9 | // contentType: AndroidAudioContentType.music, 10 | // ), 11 | androidAudioFocusGainType: AndroidAudioFocusGainType.gainTransientMayDuck, 12 | androidWillPauseWhenDucked: false, 13 | )); 14 | } 15 | -------------------------------------------------------------------------------- /lib/developer/data/log_sort_options.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/list_filter.dart'; 2 | import 'package:clock_app/developer/types/log.dart'; 3 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 4 | 5 | final List> logSortOptions = [ 6 | ListSortOption((context) => "Earliest first", sortDateAscending), 7 | ListSortOption((context) => "Latest first", sortDateDescending), 8 | ]; 9 | 10 | int sortDateAscending(Log a, Log b) { 11 | return a.id.compareTo(b.id); 12 | } 13 | 14 | int sortDateDescending(Log a, Log b) { 15 | return b.id.compareTo(a.id); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /lib/theme/bottom_sheet.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/types/color_scheme.dart'; 2 | import 'package:clock_app/theme/types/style_theme.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | BottomSheetThemeData getBottomSheetTheme( 6 | ColorSchemeData colorScheme, StyleTheme styleTheme) => 7 | BottomSheetThemeData( 8 | backgroundColor: colorScheme.card, 9 | surfaceTintColor: Colors.transparent, 10 | shape: RoundedRectangleBorder( 11 | borderRadius: BorderRadius.vertical( 12 | top: Radius.circular(styleTheme.borderRadius), 13 | ), 14 | ), 15 | ); 16 | -------------------------------------------------------------------------------- /lib/timer/utils/timer_id.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/utils/list_storage.dart'; 2 | import 'package:clock_app/timer/types/timer.dart'; 3 | 4 | ClockTimer? getTimerById(id) { 5 | final List timers = loadListSync('timers'); 6 | try { 7 | return timers.firstWhere((timer) => timer.id == id); 8 | } catch (e) { 9 | return null; 10 | } 11 | } 12 | 13 | Future getSmallestTimer()async{ 14 | return (await loadList("timers")) 15 | .where((timer) => timer.isRunning) 16 | .reduce((a, b) => a.remainingSeconds < b.remainingSeconds ? a : b); 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /lib/common/widgets/list/static_list_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class StaticListView extends StatelessWidget { 4 | const StaticListView({super.key, required this.children}); 5 | 6 | final List children; 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return SingleChildScrollView( 11 | child: Padding( 12 | padding: const EdgeInsets.symmetric(horizontal: 16.0), 13 | child: Column( 14 | children: [ 15 | ...children, 16 | const SizedBox(height: 16), 17 | ], 18 | ), 19 | ), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/common/types/list_item.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:clock_app/common/types/json.dart'; 4 | import 'package:clock_app/settings/types/setting_group.dart'; 5 | 6 | abstract class ListItem extends JsonSerializable { 7 | int get id; 8 | bool get isDeletable; 9 | 10 | dynamic copy(); 11 | 12 | void copyFrom(dynamic other); 13 | } 14 | 15 | abstract class CustomizableListItem extends ListItem { 16 | SettingGroup get settings; 17 | 18 | bool hasSameSettingsAs(CustomizableListItem other) { 19 | return json.encode(settings.valueToJson()) == 20 | json.encode(other.settings.valueToJson()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/notifications/data/fullscreen_notification_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/notification_type.dart'; 2 | import 'package:clock_app/navigation/types/routes.dart'; 3 | import 'package:clock_app/notifications/types/fullscreen_notification_data.dart'; 4 | 5 | Map 6 | alarmNotificationData = { 7 | ScheduledNotificationType.alarm: FullScreenNotificationData( 8 | id: 0, 9 | route: Routes.alarmNotificationRoute, 10 | ), 11 | ScheduledNotificationType.timer: FullScreenNotificationData( 12 | id: 1, 13 | route: Routes.timerNotificationRoute, 14 | ), 15 | }; 16 | -------------------------------------------------------------------------------- /lib/settings/data/accessibility_settings_schema.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/settings/types/setting.dart'; 2 | import 'package:clock_app/settings/types/setting_group.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 5 | 6 | SettingGroup accessibilitySettingsSchema = SettingGroup( 7 | "Accessibility", 8 | (context) => AppLocalizations.of(context)!.accessibilitySettingGroup, 9 | [ 10 | SwitchSetting("Left Handed Mode", 11 | (context) => AppLocalizations.of(context)!.leftHandedSetting, false) 12 | ], 13 | icon: Icons.accessibility_new_rounded, 14 | showExpandedView: false, 15 | ); 16 | -------------------------------------------------------------------------------- /lib/alarm/types/schedules/alarm_schedule.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/types/alarm_runner.dart'; 2 | import 'package:clock_app/common/types/json.dart'; 3 | import 'package:clock_app/common/types/time.dart'; 4 | 5 | abstract class AlarmSchedule extends JsonSerializable { 6 | DateTime? get currentScheduleDateTime; 7 | int get currentAlarmRunnerId; 8 | bool get isDisabled; 9 | bool get isFinished; 10 | 11 | AlarmSchedule(); 12 | 13 | List get alarmRunners; 14 | Future schedule( 15 | Time time, 16 | String description, [ 17 | bool alarmClock = false, 18 | ]); 19 | Future cancel(); 20 | bool hasId(int id); 21 | } 22 | -------------------------------------------------------------------------------- /lib/common/logic/customize_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/list_item.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | Future openCustomizeScreen( 5 | BuildContext context, 6 | Widget widget, { 7 | Future Function(Item newItem)? onSave, 8 | Future Function()? onCancel, 9 | }) async { 10 | ScaffoldMessenger.of(context).removeCurrentSnackBar(); 11 | Item? item = await Navigator.push( 12 | context, MaterialPageRoute(builder: (context) => widget)); 13 | if (item == null) { 14 | await onCancel?.call(); 15 | } else { 16 | await onSave?.call(item); 17 | } 18 | return item; 19 | } 20 | -------------------------------------------------------------------------------- /lib/common/utils/color.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | extension ColorUtils on Color { 4 | Color darken([double amount = .1]) { 5 | assert(amount >= 0 && amount <= 1); 6 | 7 | final hsl = HSLColor.fromColor(this); 8 | final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); 9 | 10 | return hslDark.toColor(); 11 | } 12 | 13 | Color lighten([double amount = .1]) { 14 | assert(amount >= 0 && amount <= 1); 15 | 16 | final hsl = HSLColor.fromColor(this); 17 | final hslLight = 18 | hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); 19 | 20 | return hslLight.toColor(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/notifications/logic/notifications_listeners.dart: -------------------------------------------------------------------------------- 1 | import 'package:awesome_notifications/awesome_notifications.dart'; 2 | import 'package:clock_app/notifications/logic/notification_callbacks.dart'; 3 | 4 | void setNotificationListeners() { 5 | // Only after at least the action method is set, the notification events are delivered 6 | AwesomeNotifications().setListeners( 7 | onActionReceivedMethod: onActionReceivedMethod, 8 | onNotificationCreatedMethod: onNotificationCreatedMethod, 9 | onNotificationDisplayedMethod: onNotificationDisplayedMethod, 10 | onDismissActionReceivedMethod: onDismissActionReceivedMethod); 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /lib/common/utils/time_format.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/clock/types/time.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | String getTimeFormatString(BuildContext context, TimeFormat timeFormat, 5 | {bool showMeridiem = true, String separator = "default"}) { 6 | if (timeFormat == TimeFormat.device) { 7 | if (MediaQuery.of(context).alwaysUse24HourFormat) { 8 | timeFormat = TimeFormat.h24; 9 | } else { 10 | timeFormat = TimeFormat.h12; 11 | } 12 | } 13 | 14 | if (separator == "default") { 15 | separator = ":"; 16 | } 17 | 18 | return timeFormat == TimeFormat.h12 19 | ? "h${separator}mm${showMeridiem ? " a" : ""}" 20 | : "HH${separator}mm"; 21 | } 22 | -------------------------------------------------------------------------------- /lib/theme/snackbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/types/color_scheme.dart'; 2 | import 'package:clock_app/theme/text.dart'; 3 | import 'package:clock_app/theme/types/style_theme.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | SnackBarThemeData getSnackBarTheme( 7 | ColorSchemeData colorScheme, StyleTheme styleTheme) => 8 | SnackBarThemeData( 9 | backgroundColor: colorScheme.accent, 10 | behavior: SnackBarBehavior.floating, 11 | shape: RoundedRectangleBorder( 12 | borderRadius: BorderRadius.circular(styleTheme.borderRadius), 13 | ), 14 | contentTextStyle: 15 | textTheme.labelSmall?.copyWith(color: colorScheme.onAccent), 16 | ); 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/251.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Added option to turn on foreground notification to keep app alive. Go to General > Display > Reliability > Show Foreground Notification 4 | * Added current lap card for stopwatch. Now you can view the current lap time in real time. 5 | * Added option to show next alarm in filters. Go to Settings > Alarms > Filters > Show Next Alarm. 6 | * Changed timer and stopwatch notification so time appears in title 7 | * Updated translations 8 | 9 | 🐛 Fixes 10 | 11 | * Fixed range schedule automatically getting disabled 12 | * Fixed timer dismiss actions being mapped incorrectly 13 | * Fixed timer add length not working correctly after timer rings 14 | 15 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/252.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Added option to turn on foreground notification to keep app alive. Go to General > Display > Reliability > Show Foreground Notification 4 | * Added current lap card for stopwatch. Now you can view the current lap time in real time. 5 | * Added option to show next alarm in filters. Go to Settings > Alarms > Filters > Show Next Alarm. 6 | * Changed timer and stopwatch notification so time appears in title 7 | * Updated translations 8 | 9 | 🐛 Fixes 10 | 11 | * Fixed range schedule automatically getting disabled 12 | * Fixed timer dismiss actions being mapped incorrectly 13 | * Fixed timer add length not working correctly after timer rings 14 | 15 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/253.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Added option to turn on foreground notification to keep app alive. Go to General > Display > Reliability > Show Foreground Notification 4 | * Added current lap card for stopwatch. Now you can view the current lap time in real time. 5 | * Added option to show next alarm in filters. Go to Settings > Alarms > Filters > Show Next Alarm. 6 | * Changed timer and stopwatch notification so time appears in title 7 | * Updated translations 8 | 9 | 🐛 Fixes 10 | 11 | * Fixed range schedule automatically getting disabled 12 | * Fixed timer dismiss actions being mapped incorrectly 13 | * Fixed timer add length not working correctly after timer rings 14 | 15 | -------------------------------------------------------------------------------- /lib/audio/types/ringtone_manager.dart: -------------------------------------------------------------------------------- 1 | class RingtoneManager { 2 | static String _lastPlayedRingtoneUri = ""; 3 | 4 | static final List _listeners = []; 5 | 6 | static List get listeners => _listeners; 7 | static String get lastPlayedRingtoneUri => _lastPlayedRingtoneUri; 8 | static set lastPlayedRingtoneUri(String uri) { 9 | _lastPlayedRingtoneUri = uri; 10 | for (var listener in _listeners) { 11 | listener(); 12 | } 13 | } 14 | 15 | static void addListener(void Function() listener) { 16 | _listeners.add(listener); 17 | } 18 | 19 | static void removeListener(void Function() listener) { 20 | _listeners.remove(listener); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/221.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | ✨ Enhancements 4 | 5 | * Reversed card actions order so delete is at bottom 6 | * Add option to change long date format (displayed on clock screen and clock widget) 7 | 8 | 🐛 Fixes 9 | 10 | * Fixed duplicate action in dropdowns not working 11 | * Remove widget customization options based on availibity on the OS versions 12 | * Fixed digital clock widget not working on Android 11 and lower 13 | * Fixed theme page title not localized 14 | * Fixed app getting stuck on a screen when minimized after alarm rings 15 | * Fixed spinner time picker legibility 16 | * Fixed various localization issues 17 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/222.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | ✨ Enhancements 4 | 5 | * Reversed card actions order so delete is at bottom 6 | * Add option to change long date format (displayed on clock screen and clock widget) 7 | 8 | 🐛 Fixes 9 | 10 | * Fixed duplicate action in dropdowns not working 11 | * Remove widget customization options based on availibity on the OS versions 12 | * Fixed digital clock widget not working on Android 11 and lower 13 | * Fixed theme page title not localized 14 | * Fixed app getting stuck on a screen when minimized after alarm rings 15 | * Fixed spinner time picker legibility 16 | * Fixed various localization issues 17 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/223.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | ✨ Enhancements 4 | 5 | * Reversed card actions order so delete is at bottom 6 | * Add option to change long date format (displayed on clock screen and clock widget) 7 | 8 | 🐛 Fixes 9 | 10 | * Fixed duplicate action in dropdowns not working 11 | * Remove widget customization options based on availibity on the OS versions 12 | * Fixed digital clock widget not working on Android 11 and lower 13 | * Fixed theme page title not localized 14 | * Fixed app getting stuck on a screen when minimized after alarm rings 15 | * Fixed spinner time picker legibility 16 | * Fixed various localization issues 17 | -------------------------------------------------------------------------------- /lib/settings/types/listener_manager.dart: -------------------------------------------------------------------------------- 1 | class ListenerManager { 2 | static final Map> _listeners = {}; 3 | 4 | static void addOnChangeListener(String key, Function listener) { 5 | final listeners = _listeners[key]; 6 | if (listeners == null) { 7 | _listeners[key] = [listener]; 8 | } else { 9 | if(listeners.contains(listener)) { 10 | return; 11 | } 12 | listeners.add(listener); 13 | } 14 | } 15 | 16 | static void removeOnChangeListener(String key, Function listener) { 17 | _listeners[key]?.remove(listener); 18 | } 19 | 20 | static void notifyListeners(String key) { 21 | _listeners[key]?.forEach((listener) => listener()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/full_description.txt: -------------------------------------------------------------------------------- 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 |
外观 31 |
    32 |
  • Material You 主题
  • 33 |
  • 高度可定制的颜色主题
  • 34 |
  • 高度可定制的样式主题
  • 35 |
36 | -------------------------------------------------------------------------------- /lib/common/utils/popup_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/popup_action.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 4 | 5 | MenuAction getDeletePopupAction( 6 | BuildContext context, void Function() callback) { 7 | return MenuAction( 8 | AppLocalizations.of(context)!.deleteButton, 9 | (context) => callback(), 10 | Icons.delete_rounded, 11 | Theme.of(context).colorScheme.error); 12 | } 13 | 14 | MenuAction getDuplicatePopupAction( 15 | BuildContext context, void Function() callback) { 16 | return MenuAction(AppLocalizations.of(context)!.duplicateButton, 17 | (context) => callback(), Icons.copy_rounded); 18 | } 19 | -------------------------------------------------------------------------------- /lib/common/utils/file_item.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:clock_app/common/types/file_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | IconData getFileItemIcon(FileItem fileItem, bool isPlaying) { 6 | switch (fileItem.type) { 7 | case FileItemType.audio: 8 | return isPlaying ? Icons.pause_rounded : Icons.play_arrow_rounded; 9 | case FileItemType.image: 10 | return Icons.image; 11 | case FileItemType.video: 12 | return Icons.video_label; 13 | case FileItemType.text: 14 | return Icons.text_fields; 15 | case FileItemType.other: 16 | return Icons.insert_drive_file; 17 | case FileItemType.directory: 18 | return Icons.folder; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /lib/alarm/screens/try_alarm_task_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/types/alarm_task.dart'; 2 | import 'package:clock_app/navigation/widgets/app_top_bar.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class TryAlarmTaskScreen extends StatelessWidget { 6 | const TryAlarmTaskScreen({super.key, required this.alarmTask}); 7 | 8 | final AlarmTask alarmTask; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: const AppTopBar(), 14 | body: Column( 15 | mainAxisAlignment: MainAxisAlignment.center, 16 | children: [ 17 | alarmTask.builder(() { 18 | Navigator.pop(context); 19 | }), 20 | ], 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/common/types/color_picker_type.dart: -------------------------------------------------------------------------------- 1 | /// Enum that represents the different offered color picker types. 2 | enum ColorPickerTypes { 3 | /// A color picker that contains both primary and accent Material colors. 4 | both, 5 | 6 | /// A color picker that contain the primary Material color swatches. 7 | primary, 8 | 9 | /// A color picker that contain the accent Material color swatches. 10 | accent, 11 | 12 | /// A color picker that offers black and white and their very near shades 13 | /// as color swatches. 14 | bw, 15 | 16 | /// A color picker that shows custom provided colors and their material like 17 | /// swatches and a custom name for each color swatch. 18 | custom, 19 | 20 | /// A HSV color wheel picker that can select any color. 21 | wheel, 22 | } 23 | -------------------------------------------------------------------------------- /lib/theme/font.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class FontVariations { 4 | static const List thin = [FontVariation('wght', 100.0)]; 5 | static const List extraLight = [FontVariation('wght', 200.0)]; 6 | static const List light = [FontVariation('wght', 300.0)]; 7 | static const List regular = [FontVariation('wght', 400.0)]; 8 | static const List medium = [FontVariation('wght', 500.0)]; 9 | static const List semiBold = [FontVariation('wght', 600.0)]; 10 | static const List bold = [FontVariation('wght', 700.0)]; 11 | static const List extraBold = [FontVariation('wght', 800.0)]; 12 | static const List black = [FontVariation('wght', 900.0)]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/theme/popup_menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/text.dart'; 2 | import 'package:clock_app/theme/types/color_scheme.dart'; 3 | import 'package:clock_app/theme/types/style_theme.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | PopupMenuThemeData getPopupMenuTheme( 7 | ColorSchemeData colorScheme, StyleTheme styleTheme) { 8 | return PopupMenuThemeData( 9 | color: colorScheme.background, 10 | textStyle: 11 | textTheme.headlineMedium?.copyWith(color: colorScheme.onBackground), 12 | elevation: styleTheme.shadowElevation * 2, 13 | shadowColor: colorScheme.shadow, 14 | shape: RoundedRectangleBorder( 15 | borderRadius: BorderRadius.circular(styleTheme.borderRadius), 16 | ), 17 | surfaceTintColor: Colors.transparent, 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /lib/common/widgets/color_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ColorBox extends StatelessWidget { 4 | const ColorBox({super.key, required this.color}); 5 | 6 | final Color color; 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | CardTheme cardTheme = Theme.of(context).cardTheme; 11 | 12 | return Container( 13 | width: 36.0, 14 | height: 36.0, 15 | decoration: BoxDecoration( 16 | color: color, 17 | borderRadius: 18 | (cardTheme.shape != null) ? (cardTheme.shape as RoundedRectangleBorder) 19 | .borderRadius : null, 20 | border: Border.all( 21 | color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2), 22 | width: 1.0), 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Smartphone Information** 27 | - Device: [e.g. Samsung S10] 28 | - OS: [e.g. Android 13] 29 | - App version [e.g. 0.20] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /lib/settings/logic/backup.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:file_picker/file_picker.dart'; 6 | 7 | Future saveBackupFile(String data) async { 8 | return await FilePicker.platform.saveFile( 9 | bytes: Uint8List.fromList(utf8.encode(data)), 10 | fileName: 11 | "chrono_backup_${DateTime.now().toIso8601String().split(".")[0]}.json", 12 | ); 13 | } 14 | 15 | Future loadBackupFile() async { 16 | FilePickerResult? result = await FilePicker.platform 17 | .pickFiles(type: FileType.any, allowMultiple: false); 18 | 19 | if (result != null && result.files.isNotEmpty) { 20 | File file = File(result.files.single.path!); 21 | return utf8.decode(file.readAsBytesSync()); 22 | } 23 | return null; 24 | } 25 | -------------------------------------------------------------------------------- /lib/navigation/types/app_visibility.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter_fgbg/flutter_fgbg.dart'; 4 | 5 | class AppVisibility { 6 | static StreamSubscription? subscription; 7 | 8 | static FGBGType _state = FGBGType.foreground; 9 | 10 | static FGBGType get state => _state; 11 | 12 | static void setState(FGBGType type) { 13 | _state = type; 14 | } 15 | 16 | static void initialize() { 17 | // if (loadTextFileSync(fullscreenIntentKey) == "true") { 18 | // saveTextFile(fullscreenIntentKey, "false"); 19 | // } else { 20 | // setState(FGBGType.foreground); 21 | // } 22 | 23 | subscription = FGBGEvents.stream.listen((event) { 24 | setState(event); 25 | }); 26 | } 27 | 28 | static void dispose() { 29 | subscription?.cancel(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/stopwatch/logic/update_stopwatch.dart: -------------------------------------------------------------------------------- 1 | import 'dart:isolate'; 2 | import 'dart:ui'; 3 | 4 | import 'package:clock_app/alarm/logic/alarm_isolate.dart'; 5 | import 'package:clock_app/stopwatch/types/stopwatch.dart'; 6 | import 'package:clock_app/common/utils/list_storage.dart'; 7 | 8 | Future updateStopwatch(Future Function(ClockStopwatch) callback) async { 9 | List stopwatches = await loadList("stopwatches"); 10 | // int timerIndex = timers.indexWhere((timer) => timer.id == scheduleId); 11 | // if(timerIndex == -1) return; 12 | ClockStopwatch stopwatch = stopwatches.first; 13 | await callback(stopwatch); 14 | await saveList("stopwatches", [stopwatch]); 15 | 16 | SendPort? sendPort = IsolateNameServer.lookupPortByName(updatePortName); 17 | sendPort?.send("updateStopwatches"); 18 | } 19 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | 2 | pluginManagement { 3 | def flutterSdkPath = { 4 | def properties = new Properties() 5 | file("local.properties").withInputStream { properties.load(it) } 6 | def flutterSdkPath = properties.getProperty("flutter.sdk") 7 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 8 | return flutterSdkPath 9 | }() 10 | 11 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | } 19 | 20 | plugins { 21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 22 | id "com.android.application" version "7.4.2" apply false 23 | id "org.jetbrains.kotlin.android" version "1.8.0" apply false 24 | } 25 | 26 | include ":app" 27 | 28 | -------------------------------------------------------------------------------- /lib/audio/audio_channels.dart: -------------------------------------------------------------------------------- 1 | import 'package:audio_session/audio_session.dart'; 2 | import 'package:clock_app/settings/types/setting.dart'; 3 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 4 | 5 | List> audioChannelOptions = [ 6 | SelectSettingOption( 7 | (context) => AppLocalizations.of(context)!.audioChannelAlarm, 8 | AndroidAudioUsage.alarm), 9 | SelectSettingOption( 10 | (context) => AppLocalizations.of(context)!.audioChannelMedia, 11 | AndroidAudioUsage.media), 12 | SelectSettingOption( 13 | (context) => AppLocalizations.of(context)!.audioChannelNotification, 14 | AndroidAudioUsage.notification), 15 | SelectSettingOption( 16 | (context) => AppLocalizations.of(context)!.audioChannelRingtone, 17 | AndroidAudioUsage.notificationRingtone), 18 | ]; 19 | -------------------------------------------------------------------------------- /lib/common/data/animations.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_animate/flutter_animate.dart'; 3 | 4 | extension AnimateWidgetExtensions on Widget { 5 | Animate animateCard(dynamic key) => animate(delay: 50.ms, key: key) 6 | .slideY(begin: 0.15, end: 0, duration: 150.ms, curve: Curves.easeOut) 7 | .fade(duration: 150.ms, curve: Curves.easeOut); 8 | 9 | } 10 | 11 | extension AnimateListExtensions on List { 12 | /// Wraps the target `List` in an [AnimateList] instance, and returns 13 | /// the instance for chaining calls. 14 | /// Ex. `[foo, bar].animate()` is equivalent to `AnimateList(children: [foo, bar])`. 15 | AnimateList animateCardList() => animate(interval: 100.ms) 16 | .slideY(begin: 0.15, end: 0, duration: 150.ms, curve: Curves.easeOut) 17 | .fade(duration: 150.ms, curve: Curves.easeOut); 18 | } 19 | -------------------------------------------------------------------------------- /lib/common/widgets/list/list_item_measurer.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter/material.dart'; 2 | 3 | // class ListItemMeasurer extends StatefulWidget { 4 | // const ListItemMeasurer({ 5 | // super.key, 6 | // required this.controller, 7 | // required this.index, 8 | // }); 9 | // 10 | // final AnimatedListController controller; 11 | // final int index; 12 | // 13 | // @override 14 | // State createState() => _ListItemMeasurerState(); 15 | // } 16 | // 17 | // class _ListItemMeasurerState extends State { 18 | // late double? height; 19 | // 20 | // @override 21 | // void initState() { 22 | // super.initState(); 23 | // height = widget.controller.computeItemBox(0, true)?.height; 24 | // } 25 | // 26 | // @override 27 | // Widget build(BuildContext context) { 28 | // return SizedBox(height: height); 29 | // } 30 | // } 31 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/212.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | ✨ Enhancements 4 | 5 | * Added option to change first day of week 6 | * Improved spinner time picker interface 7 | * Improved dial time picker 24h interface 8 | * Added discription for audio channel options 9 | * Added option to change separator for digital clock widget 10 | 11 | 12 | 🐛 Fixes 13 | 14 | * Fixed app not opening on Android 11 and lower when Digital clock widget is used 15 | * Fixed app assuming foreground after alarm rings, even though it was closed before 16 | * Fixed media, notification and ringtone audio channels not working 17 | * Fixed other apps' music not restarting after alarm rings 18 | * Fixed upcoming alarm notification appearing after alarm rings 19 | * Fixed upcoming alarm notification not updating for repeating alarms 20 | * Fixed splash color 21 | 22 | 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | coverage/ 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/211.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | ✨ Enhancements 4 | 5 | * Added option to change first day of week 6 | * Improved spinner time picker interface 7 | * Improved dial time picker 24h interface 8 | * Added discription for audio channel options 9 | * Added option to change separator for digital clock widget 10 | 11 | 12 | 🐛 Fixes 13 | 14 | * Fixed app not opening on Android 11 and lower when Digital clock widget is used 15 | * Fixed app assuming foreground after alarm rings, even though it was closed before 16 | * Fixed media, notification and ringtone audio channels not working 17 | * Fixed other apps' music not restarting after alarm rings 18 | * Fixed upcoming alarm notification appearing after alarm rings 19 | * Fixed upcoming alarm notification not updating for repeating alarms 20 | * Fixed splash color 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/213.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | ✨ Enhancements 4 | 5 | * Added option to change first day of week 6 | * Improved spinner time picker interface 7 | * Improved dial time picker 24h interface 8 | * Added discription for audio channel options 9 | * Added option to change separator for digital clock widget 10 | 11 | 12 | 🐛 Fixes 13 | 14 | * Fixed app not opening on Android 11 and lower when Digital clock widget is used 15 | * Fixed app assuming foreground after alarm rings, even though it was closed before 16 | * Fixed media, notification and ringtone audio channels not working 17 | * Fixed other apps' music not restarting after alarm rings 18 | * Fixed upcoming alarm notification appearing after alarm rings 19 | * Fixed upcoming alarm notification not updating for repeating alarms 20 | * Fixed splash color 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /lib/system/logic/initialize_isolate_ports.dart: -------------------------------------------------------------------------------- 1 | import 'dart:isolate'; 2 | import 'dart:ui'; 3 | 4 | import 'package:clock_app/alarm/logic/alarm_isolate.dart'; 5 | import 'package:clock_app/developer/logic/logger.dart'; 6 | import 'package:clock_app/settings/types/listener_manager.dart'; 7 | 8 | void initializeIsolatePorts(){ 9 | ReceivePort receivePort = ReceivePort(); 10 | IsolateNameServer.removePortNameMapping(updatePortName); 11 | IsolateNameServer.registerPortWithName(receivePort.sendPort, updatePortName); 12 | printIsolateInfo(); 13 | receivePort.listen((message) { 14 | if (message == "updateAlarms") { 15 | ListenerManager.notifyListeners("alarms"); 16 | } else if (message == "updateTimers") { 17 | ListenerManager.notifyListeners("timers"); 18 | } else if (message == "updateStopwatches") { 19 | ListenerManager.notifyListeners("stopwatch"); 20 | } 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/171.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Improve UI in landscape mode 4 | * Add skip-alarm filter action 5 | * Add option to reset and add time to timer from dropdown menu on cards 6 | 7 | 🐛 Fixes 8 | 9 | * Fixed dates schedule not working 10 | * Fixed disabled alarms not scheduling on editing 11 | * Fixed weird behaviours when alarms were sorted 12 | * Fixed alarm logs not updating correctly when changing alarm or timer 13 | * Fixed sort order not being saved correctly 14 | * Fixed card color in style preview not appearing correctly 15 | * Fixed stopwatch flashing when resetting 16 | * Fixed timer not editable in landscape mode 17 | * Fixed timer notification not updating correctly 18 | * Fixed date and range schedule not updating after finishing 19 | * Fixed date and range schedule not duplicating correctly after finishing 20 | * Fixed animation speed not applying correctly on start 21 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/172.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Improve UI in landscape mode 4 | * Add skip-alarm filter action 5 | * Add option to reset and add time to timer from dropdown menu on cards 6 | 7 | 🐛 Fixes 8 | 9 | * Fixed dates schedule not working 10 | * Fixed disabled alarms not scheduling on editing 11 | * Fixed weird behaviours when alarms were sorted 12 | * Fixed alarm logs not updating correctly when changing alarm or timer 13 | * Fixed sort order not being saved correctly 14 | * Fixed card color in style preview not appearing correctly 15 | * Fixed stopwatch flashing when resetting 16 | * Fixed timer not editable in landscape mode 17 | * Fixed timer notification not updating correctly 18 | * Fixed date and range schedule not updating after finishing 19 | * Fixed date and range schedule not duplicating correctly after finishing 20 | * Fixed animation speed not applying correctly on start 21 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/173.txt: -------------------------------------------------------------------------------- 1 | ✨ Enhancements 2 | 3 | * Improve UI in landscape mode 4 | * Add skip-alarm filter action 5 | * Add option to reset and add time to timer from dropdown menu on cards 6 | 7 | 🐛 Fixes 8 | 9 | * Fixed dates schedule not working 10 | * Fixed disabled alarms not scheduling on editing 11 | * Fixed weird behaviours when alarms were sorted 12 | * Fixed alarm logs not updating correctly when changing alarm or timer 13 | * Fixed sort order not being saved correctly 14 | * Fixed card color in style preview not appearing correctly 15 | * Fixed stopwatch flashing when resetting 16 | * Fixed timer not editable in landscape mode 17 | * Fixed timer notification not updating correctly 18 | * Fixed date and range schedule not updating after finishing 19 | * Fixed date and range schedule not duplicating correctly after finishing 20 | * Fixed animation speed not applying correctly on start 21 | -------------------------------------------------------------------------------- /lib/developer/logic/logger.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/developer/types/file_logger_output.dart'; 2 | import 'package:clock_app/developer/types/log_filter.dart'; 3 | import 'package:logger/logger.dart'; 4 | import 'dart:isolate'; 5 | 6 | var logger = Logger( 7 | filter: FileLogFilter(), 8 | output: FileLoggerOutput(), 9 | printer: PrettyPrinter( 10 | methodCount: 100, // Number of method calls to be displayed 11 | errorMethodCount: 100, // Number of method calls if stacktrace is provided 12 | lineLength: 80, // Width of the output 13 | colors: true, // Colorful log messages 14 | printEmojis: true, // Print an emoji for each log message 15 | // Should each log print contain a timestamp 16 | dateTimeFormat: DateTimeFormat.none, 17 | ), 18 | ); 19 | 20 | void printIsolateInfo() { 21 | logger.t( 22 | "Isolate: ${Isolate.current.debugName}, id: ${Isolate.current.hashCode}"); 23 | } 24 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/191.txt: -------------------------------------------------------------------------------- 1 | 🚀 Features 2 | 3 | * Added option to automatically delete one time alarm after ringing 4 | * Added option to automatically delete dates and range alarm after finishing 5 | * Added spinner UI to select time 6 | 7 | ✨ Enhancements 8 | 9 | * Added count setting to math and retype tasks 10 | * Added option to select default UI for selecting time 11 | * Added credits to about page 12 | * Improved timer fullscreen button UI on smaller devices 13 | * Improved timer fullscreen layout in landscape mode 14 | 15 | 🐛 Fixes 16 | 17 | * Fixed numbers appearing after melody name 18 | * Fixed alarm screen not updating after adding alarm through external app 19 | * Fixed snackbar text clipping 20 | * Fixed time picker stretching over the entire screen 21 | * Fixed alarm tasks not getting deleted properly 22 | * Fixed alarm tasks not working properly when same task is added multiple times 23 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/192.txt: -------------------------------------------------------------------------------- 1 | 🚀 Features 2 | 3 | * Added option to automatically delete one time alarm after ringing 4 | * Added option to automatically delete dates and range alarm after finishing 5 | * Added spinner UI to select time 6 | 7 | ✨ Enhancements 8 | 9 | * Added count setting to math and retype tasks 10 | * Added option to select default UI for selecting time 11 | * Added credits to about page 12 | * Improved timer fullscreen button UI on smaller devices 13 | * Improved timer fullscreen layout in landscape mode 14 | 15 | 🐛 Fixes 16 | 17 | * Fixed numbers appearing after melody name 18 | * Fixed alarm screen not updating after adding alarm through external app 19 | * Fixed snackbar text clipping 20 | * Fixed time picker stretching over the entire screen 21 | * Fixed alarm tasks not getting deleted properly 22 | * Fixed alarm tasks not working properly when same task is added multiple times 23 | -------------------------------------------------------------------------------- /.github/workflows/clear-cache.yml: -------------------------------------------------------------------------------- 1 | name: Clear cache 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | permissions: 7 | actions: write 8 | 9 | jobs: 10 | clear-cache: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Clear cache 14 | uses: actions/github-script@v6 15 | with: 16 | script: | 17 | console.log("About to clear") 18 | const caches = await github.rest.actions.getActionsCacheList({ 19 | owner: context.repo.owner, 20 | repo: context.repo.repo, 21 | }) 22 | for (const cache of caches.data.actions_caches) { 23 | console.log(cache) 24 | github.rest.actions.deleteActionsCacheById({ 25 | owner: context.repo.owner, 26 | repo: context.repo.repo, 27 | cache_id: cache.id, 28 | }) 29 | } 30 | console.log("Clear completed") 31 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/scale_in.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class ScaleIn extends AnimationEffect { 5 | static const double beginValue = 0.0; 6 | static const double endValue = 1.0; 7 | final double? begin; 8 | final double? end; 9 | 10 | ScaleIn({super.delay, super.duration, super.curve, this.begin, this.end}); 11 | 12 | @override 13 | Widget build(BuildContext context, Widget child, Animation animation, 14 | EffectEntry entry, Duration totalDuration) { 15 | final Animation scale = buildAnimation(entry, totalDuration, 16 | begin: begin ?? beginValue, end: endValue) 17 | .animate(animation); 18 | return ScaleTransition( 19 | scale: scale, 20 | child: child, 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/193.txt: -------------------------------------------------------------------------------- 1 | 🚀 Features 2 | 3 | * Added option to automatically delete one time alarm after ringing 4 | * Added option to automatically delete dates and range alarm after finishing (no more dates are scheduled) 5 | * Added spinner UI to select time 6 | 7 | ✨ Enhancements 8 | 9 | * Added count setting to math and retype tasks 10 | * Added option to select default UI for selecting time 11 | * Added credits to about page 12 | * Improved timer fullscreen button UI on smaller devices 13 | * Improved timer fullscreen layout in landscape mode 14 | 15 | 🐛 Fixes 16 | 17 | * Fixed numbers appearing after melody name 18 | * Fixed alarm screen not updating after adding alarm through external app 19 | * Fixed snackbar text clipping 20 | * Fixed time picker stretching over the entire screen 21 | * Fixed alarm tasks not getting deleted properly 22 | * Fixed alarm tasks not working properly when same task is added multiple times 23 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/fade_in.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class FadeIn extends AnimationEffect { 5 | static const double beginValue = 0.0; 6 | static const double endValue = 1.0; 7 | final double? begin; 8 | final double? end; 9 | 10 | FadeIn({super.delay, super.duration, super.curve, this.begin, this.end}); 11 | 12 | @override 13 | Widget build(BuildContext context, Widget child, Animation animation, 14 | EffectEntry entry, Duration totalDuration) { 15 | final Animation opacity = buildAnimation( 16 | entry, 17 | begin: begin ?? beginValue, 18 | end: end ?? endValue, 19 | totalDuration) 20 | .animate(animation); 21 | return FadeTransition(opacity: opacity, child: child); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/clock/widgets/time_display_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/clock/time_display.dart'; 2 | import 'package:clock_app/theme/theme.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:intl/intl.dart'; 6 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 7 | 8 | void main() { 9 | testWidgets('TimeDisplay shows time correctly ...', (tester) async { 10 | DateTime dateTime = DateTime.now(); 11 | String format = "hh:mm"; 12 | await tester.pumpWidget(MaterialApp( 13 | theme: defaultTheme, 14 | locale: const Locale('en'), 15 | localizationsDelegates: AppLocalizations.localizationsDelegates, 16 | supportedLocales: AppLocalizations.supportedLocales, 17 | home: TimeDisplay(format: format, fontSize: 32, dateTime: dateTime), 18 | )); 19 | 20 | expect(find.text(DateFormat(format).format(dateTime)), findsOneWidget); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /lib/notifications/widgets/notification_actions/slide_notification_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/slidable_action.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class SlideNotificationAction extends StatelessWidget { 5 | const SlideNotificationAction( 6 | {super.key, 7 | required this.dismissLabel, 8 | required this.snoozeLabel, 9 | required this.onDismiss, 10 | this.onSnooze}); 11 | 12 | final String dismissLabel; 13 | final String snoozeLabel; 14 | final VoidCallback onDismiss; 15 | final VoidCallback? onSnooze; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Padding( 20 | padding: const EdgeInsets.symmetric(horizontal: 8.0), 21 | child: SlideAction( 22 | leftText: onSnooze != null ? snoozeLabel : null, 23 | rightText: dismissLabel, 24 | onSubmitRight: onDismiss, 25 | onSubmitLeft: onSnooze, 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/common/widgets/clock/time_display.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'package:intl/intl.dart'; 4 | 5 | class TimeDisplay extends StatelessWidget { 6 | const TimeDisplay({ 7 | 8 | super.key, 9 | required this.format, 10 | required this.fontSize, 11 | this.height, 12 | this.color, 13 | required this.dateTime, 14 | }); 15 | 16 | final DateTime dateTime; 17 | final String format; 18 | final double fontSize; 19 | final double? height; 20 | final Color? color; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | Locale locale = Localizations.localeOf(context); 25 | String formattedTime = DateFormat(format, locale.languageCode).format(dateTime); 26 | return Text( 27 | formattedTime, 28 | style: Theme.of(context).textTheme.displaySmall?.copyWith( 29 | fontSize: fontSize, 30 | height: height, 31 | color: color, 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/common/utils/date_time_utils_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/utils/date_time.dart'; 2 | import 'package:clock_app/timer/types/time_duration.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | 6 | DateTime dateTime = DateTime(2023, 1, 1, 1, 30, 0); 7 | 8 | void main() { 9 | group('DateTimeUtils', () { 10 | test( 11 | 'toHours() returns correct value', 12 | () { 13 | expect(dateTime.toHours(), 1.5); 14 | }, 15 | ); 16 | 17 | test( 18 | 'toTimeOfDay() returns correct value', 19 | () { 20 | expect(dateTime.toTimeOfDay(), const TimeOfDay(hour: 1, minute: 30)); 21 | }, 22 | ); 23 | test( 24 | 'addTimeDuration() returns correct value', 25 | () { 26 | expect( 27 | dateTime.addTimeDuration(const TimeDuration(hours: 5, minutes: 7)), 28 | DateTime(2023, 1, 1, 6, 37, 0)); 29 | }, 30 | ); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /test/settings/widget/setting_group_card_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 in the flutter_test package. 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 | // import 'package:clock_app/settings/data/settings_data.dart'; 9 | // import 'package:clock_app/settings/widgets/setting_group_card.dart'; 10 | // import 'package:flutter/material.dart'; 11 | // import 'package:flutter_test/flutter_test.dart'; 12 | 13 | void main() { 14 | // testWidgets('SettingGroupCard shows title', (WidgetTester tester) async { 15 | // await tester.pumpWidget(MaterialApp( 16 | // home: SettingGroupCard(settingGroup: settingsItems[0]), 17 | // )); 18 | 19 | // expect(find.text('General'), findsOneWidget); 20 | // }); 21 | } 22 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/scale_in_left.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class ScaleInLeft extends AnimationEffect { 5 | static const double beginValue = 0.0; 6 | static const double endValue = 1.0; 7 | final double? begin; 8 | final double? end; 9 | 10 | ScaleInLeft({super.delay, super.duration, super.curve, this.begin, this.end}); 11 | 12 | @override 13 | Widget build(BuildContext context, Widget child, Animation animation, 14 | EffectEntry entry, Duration totalDuration) { 15 | final Animation scale = buildAnimation(entry, totalDuration, 16 | begin: begin ?? beginValue, end: endValue) 17 | .animate(animation); 18 | return ScaleTransition( 19 | alignment: Alignment.centerLeft, 20 | scale: scale, 21 | child: child, 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: vicolo-dev # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: vicolo # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/scale_in_top.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | 5 | class ScaleInTop extends AnimationEffect { 6 | static const double beginValue = 0.0; 7 | static const double endValue = 1.0; 8 | final double? begin; 9 | final double? end; 10 | 11 | ScaleInTop({super.delay, super.duration, super.curve, this.begin, this.end}); 12 | 13 | @override 14 | Widget build(BuildContext context, Widget child, Animation animation, 15 | EffectEntry entry, Duration totalDuration) { 16 | final Animation scale = buildAnimation(entry, totalDuration, 17 | begin: begin ?? beginValue, end: endValue) 18 | .animate(animation); 19 | return ScaleTransition( 20 | alignment: Alignment.topCenter, 21 | scale: scale, 22 | child: child, 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/vicolo/chrono/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.vicolo.chrono 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import io.flutter.embedding.engine.plugins.FlutterPlugin 6 | import io.flutter.plugin.common.MethodCall 7 | import io.flutter.plugin.common.MethodChannel 8 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 9 | import io.flutter.plugin.common.MethodChannel.Result 10 | import io.flutter.plugin.common.PluginRegistry.Registrar 11 | import java.util.ArrayList 12 | import androidx.annotation.NonNull 13 | import io.flutter.embedding.android.FlutterActivity 14 | import io.flutter.embedding.engine.FlutterEngine 15 | import io.flutter.plugins.GeneratedPluginRegistrant; 16 | 17 | class MainActivity: FlutterActivity() { 18 | private val CHANNEL = "com.vicolo.chrono/alarm" 19 | 20 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 21 | super.configureFlutterEngine(flutterEngine) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/common/types/weekday.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/json.dart'; 2 | import 'package:clock_app/common/types/list_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class Weekday extends ListItem { 6 | @override 7 | int id; 8 | String Function(BuildContext) getAbbreviation; 9 | String Function(BuildContext) getDisplayName; 10 | String Function(BuildContext) getFullName; 11 | 12 | Weekday(this.id, this.getAbbreviation, this.getDisplayName, this.getFullName); 13 | 14 | @override 15 | copy() { 16 | return Weekday(id, getAbbreviation, getDisplayName, getFullName); 17 | } 18 | 19 | @override 20 | void copyFrom(other) { 21 | id = other.id; 22 | getAbbreviation = other.getAbbreviation; 23 | getDisplayName = other.getDisplayName; 24 | getFullName = other.getFullName; 25 | } 26 | 27 | @override 28 | bool get isDeletable => false; 29 | 30 | @override 31 | Json? toJson() { 32 | return { 33 | 'id': id, 34 | }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/alarm/data/time_icons.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/types/time_of_day_icon.dart'; 2 | import 'package:clock_app/common/types/time.dart'; 3 | import 'package:clock_app/icons/flux_icons.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | List timeIcons = [ 7 | TimeIcon( 8 | FluxIcons.sunrise, 9 | const Color.fromARGB(255, 80, 218, 183), 10 | const Time(hour: 5, minute: 0), 11 | const Time(hour: 10, minute: 0), 12 | ), 13 | TimeIcon( 14 | FluxIcons.noon, 15 | const Color.fromARGB(255, 243, 222, 127), 16 | const Time(hour: 10, minute: 0), 17 | const Time(hour: 16, minute: 0), 18 | ), 19 | TimeIcon( 20 | FluxIcons.sunset, 21 | const Color.fromARGB(255, 255, 201, 169), 22 | const Time(hour: 16, minute: 0), 23 | const Time(hour: 19, minute: 0), 24 | ), 25 | TimeIcon( 26 | FluxIcons.night, 27 | const Color.fromARGB(255, 211, 172, 255), 28 | const Time(hour: 19, minute: 0), 29 | const Time(hour: 5, minute: 0), 30 | ), 31 | ]; 32 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/scale_in_bottom.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class ScaleInBottom extends AnimationEffect { 5 | static const double beginValue = 0.0; 6 | static const double endValue = 1.0; 7 | final double? begin; 8 | final double? end; 9 | 10 | ScaleInBottom( 11 | {super.delay, super.duration, super.curve, this.begin, this.end}); 12 | 13 | @override 14 | Widget build(BuildContext context, Widget child, Animation animation, 15 | EffectEntry entry, Duration totalDuration) { 16 | final Animation scale = buildAnimation(entry, totalDuration, 17 | begin: begin ?? beginValue, end: endValue) 18 | .animate(animation); 19 | return ScaleTransition( 20 | alignment: Alignment.bottomCenter, 21 | scale: scale, 22 | child: child, 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/scale_in_right.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class ScaleInRight extends AnimationEffect { 5 | static const double beginValue = 0.0; 6 | static const double endValue = 1.0; 7 | final double? begin; 8 | final double? end; 9 | 10 | ScaleInRight( 11 | {super.delay, super.duration, super.curve, this.begin, this.end}); 12 | 13 | @override 14 | Widget build(BuildContext context, Widget child, Animation animation, 15 | EffectEntry entry, Duration totalDuration) { 16 | final Animation scale = buildAnimation(entry, totalDuration, 17 | begin: begin ?? beginValue, end: endValue) 18 | .animate(animation); 19 | return ScaleTransition( 20 | alignment: Alignment.centerRight, 21 | scale: scale, 22 | child: child, 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/navigation/types/routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/app.dart'; 2 | 3 | class Routes { 4 | static const String rootRoute = '/'; 5 | static const String alarmNotificationRoute = '/alarm-notification-screen'; 6 | static const String timerNotificationRoute = '/timer-notification-screen'; 7 | 8 | static String _currentRoute = rootRoute; 9 | static final List _previousRoutes = []; 10 | 11 | static String get currentRoute => _currentRoute; 12 | static List get previousRoutes => _previousRoutes; 13 | 14 | static void push(String route) { 15 | _previousRoutes.add(_currentRoute); 16 | _currentRoute = route; 17 | } 18 | 19 | static void pop({bool onlyUpdateRoute = false}) { 20 | if (!onlyUpdateRoute) { 21 | App.navigatorKey.currentState?.pop(); 22 | } 23 | 24 | _currentRoute = _previousRoutes.removeLast(); 25 | } 26 | 27 | static void popIf(String? route) { 28 | if (Routes.currentRoute == route) { 29 | Routes.pop(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/201.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Widget support! 6 | * Added analog and digital clock widgets 7 | * Added option to customize size, alignment, color, font weight 8 | * Added localizations 9 | * Chinese, French, Spanish mostly complete 10 | * Partial support for Bengali, German, Italian, Norwegian, Polish, Portuguese, Russian, Turkish, and Vietnamese 11 | * Add your favorite language here: https://hosted.weblate.org/projects/chrono 12 | 13 | ✨ Enhancements 14 | 15 | * Added option to specify default page 16 | * Added 'plus' button when selecting melodies and tags 17 | * Added patreons list in about screen 18 | * Added contributors list in about screen 19 | * Added popup to ignore battery optimizations automatically 20 | * Added sections in settings to get notification and ignore baterry optimization settings 21 | 22 | 🐛 Fixes 23 | 24 | * Fixed various inconsistencies in setting names 25 | 26 | 27 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/202.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Widget support! 6 | * Added analog and digital clock widgets 7 | * Added option to customize size, alignment, color, font weight 8 | * Added localizations 9 | * Chinese, French, Spanish mostly complete 10 | * Partial support for Bengali, German, Italian, Norwegian, Polish, Portuguese, Russian, Turkish, and Vietnamese 11 | * Add your favorite language here: https://hosted.weblate.org/projects/chrono 12 | 13 | ✨ Enhancements 14 | 15 | * Added option to specify default page 16 | * Added 'plus' button when selecting melodies and tags 17 | * Added patreons list in about screen 18 | * Added contributors list in about screen 19 | * Added popup to ignore battery optimizations automatically 20 | * Added sections in settings to get notification and ignore baterry optimization settings 21 | 22 | 🐛 Fixes 23 | 24 | * Fixed various inconsistencies in setting names 25 | 26 | 27 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/203.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Widget support! 6 | * Added analog and digital clock widgets 7 | * Added option to customize size, alignment, color, font weight 8 | * Added localizations 9 | * Chinese, French, Spanish mostly complete 10 | * Partial support for Bengali, German, Italian, Norwegian, Polish, Portuguese, Russian, Turkish, and Vietnamese 11 | * Add your favorite language here: https://hosted.weblate.org/projects/chrono 12 | 13 | ✨ Enhancements 14 | 15 | * Added option to specify default page 16 | * Added 'plus' button when selecting melodies and tags 17 | * Added patreons list in about screen 18 | * Added contributors list in about screen 19 | * Added popup to ignore battery optimizations automatically 20 | * Added sections in settings to get notification and ignore baterry optimization settings 21 | 22 | 🐛 Fixes 23 | 24 | * Fixed various inconsistencies in setting names 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/slide_in_up.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class SlideInUp extends AnimationEffect { 5 | static const Offset beginValue = Offset(0, -1); 6 | static const Offset endValue = Offset(0, 0); 7 | final Offset? begin; 8 | final Offset? end; 9 | 10 | SlideInUp({super.delay, super.duration, super.curve, this.begin, this.end}); 11 | 12 | @override 13 | Widget build(BuildContext context, Widget child, Animation animation, 14 | EffectEntry entry, Duration totalDuration) { 15 | final Animation position = buildAnimation(entry, totalDuration, 16 | begin: begin ?? beginValue, end: end ?? endValue) 17 | .animate(animation); 18 | return ClipRect( 19 | clipBehavior: Clip.hardEdge, 20 | child: SlideTransition(position: position, child: child)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/model/motion_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | class MotionData { 4 | final Offset startOffset; 5 | final Offset endOffset; 6 | final bool visible; 7 | 8 | MotionData( 9 | {this.startOffset = Offset.zero, 10 | this.endOffset = Offset.zero, 11 | this.visible = true}); 12 | 13 | MotionData copyWith({Offset? startOffset, Offset? endOffset, bool? visible}) { 14 | return MotionData( 15 | startOffset: startOffset ?? this.startOffset, 16 | endOffset: endOffset ?? this.endOffset, 17 | visible: visible ?? this.visible); 18 | } 19 | 20 | @override 21 | bool operator ==(Object other) => 22 | identical(this, other) || 23 | other is MotionData && 24 | runtimeType == other.runtimeType && 25 | startOffset == other.startOffset && 26 | endOffset == other.endOffset; 27 | 28 | @override 29 | int get hashCode => startOffset.hashCode ^ endOffset.hashCode; 30 | } 31 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/digital_date.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/slide_in_left.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class SlideInLeft extends AnimationEffect { 5 | static const Offset beginValue = Offset(-1, 0); 6 | static const Offset endValue = Offset(0, 0); 7 | final Offset? begin; 8 | final Offset? end; 9 | 10 | SlideInLeft({super.delay, super.duration, super.curve, this.begin, this.end}); 11 | 12 | @override 13 | Widget build(BuildContext context, Widget child, Animation animation, 14 | EffectEntry entry, Duration totalDuration) { 15 | final Animation position = buildAnimation(entry, totalDuration, 16 | begin: begin ?? beginValue, end: end ?? endValue) 17 | .animate(animation); 18 | return ClipRect( 19 | clipBehavior: Clip.hardEdge, 20 | child: SlideTransition(position: position, child: child)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/landing.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class Landing extends AnimationEffect { 5 | static const double beginValue = 1.5; 6 | static const double endValue = 1.0; 7 | final double? begin; 8 | final double? end; 9 | 10 | Landing({super.delay, super.duration, super.curve, this.begin, this.end}); 11 | 12 | @override 13 | Widget build(BuildContext context, Widget child, Animation animation, 14 | EffectEntry entry, Duration totalDuration) { 15 | final Animation scale = buildAnimation(entry, totalDuration, 16 | begin: begin ?? beginValue, end: end ?? endValue) 17 | .animate(animation); 18 | return FadeTransition( 19 | opacity: animation, 20 | child: ScaleTransition( 21 | scale: scale, 22 | child: child, 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/theme/time_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/shape.dart'; 2 | import 'package:clock_app/theme/text.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | TimePickerThemeData timePickerTheme = TimePickerThemeData( 6 | hourMinuteShape: defaultShape, 7 | dayPeriodShape: defaultShape, 8 | // dialBackgroundColor: Colors.grey.shade200, 9 | helpTextStyle: textTheme.displaySmall?.copyWith( 10 | // color: Theme.of(context).colorScheme.onBackground.withOpacity(0.8), 11 | ), 12 | hourMinuteTextStyle: textTheme.displayMedium, 13 | dayPeriodTextStyle: textTheme.displaySmall, 14 | // hourMinuteTextColor: Theme.of(context).colorScheme.onBackground.withOpacity(0.8), 15 | // dialTextColor: Theme.of(context).colorScheme.onBackground.withOpacity(0.8), 16 | // dayPeriodTextColor: Theme.of(context).colorScheme.onBackground.withOpacity(0.8), 17 | shape: defaultShape, 18 | dayPeriodBorderSide: BorderSide.none, 19 | 20 | // entryModeIconColor: Theme.of(context).colorScheme.onBackground.withOpacity(0.8), 21 | ); 22 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/slide_in_right.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class SlideInRight extends AnimationEffect { 5 | static const Offset beginValue = Offset(1, 0); 6 | static const Offset endValue = Offset(0, 0); 7 | final Offset? begin; 8 | final Offset? end; 9 | 10 | SlideInRight( 11 | {super.delay, super.duration, super.curve, this.begin, this.end}); 12 | 13 | @override 14 | Widget build(BuildContext context, Widget child, Animation animation, 15 | EffectEntry entry, Duration totalDuration) { 16 | final Animation position = buildAnimation(entry, totalDuration, 17 | begin: begin ?? beginValue, end: end ?? endValue) 18 | .animate(animation); 19 | return ClipRect( 20 | clipBehavior: Clip.hardEdge, 21 | child: SlideTransition(position: position, child: child)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/system/logic/initialize_isolate.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart'; 4 | import 'package:clock_app/audio/logic/audio_session.dart'; 5 | import 'package:clock_app/audio/types/ringtone_player.dart'; 6 | import 'package:clock_app/common/data/paths.dart'; 7 | import 'package:clock_app/notifications/logic/notifications.dart'; 8 | import 'package:clock_app/settings/logic/initialize_settings.dart'; 9 | import 'package:clock_app/system/data/device_info.dart'; 10 | import 'package:flutter/widgets.dart'; 11 | 12 | Future initializeIsolate() async { 13 | DartPluginRegistrant.ensureInitialized(); 14 | WidgetsFlutterBinding.ensureInitialized(); 15 | 16 | await initializeAndroidInfo(); 17 | await initializeAppDataDirectory(); 18 | await initializeStorage(false); 19 | await initializeSettings(); 20 | await initializeNotifications(); 21 | await initializeAudioSession(); 22 | await AndroidAlarmManager.initialize(); 23 | await RingtonePlayer.initialize(); 24 | } 25 | -------------------------------------------------------------------------------- /lib/theme/switch.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/types/color_scheme.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | SwitchThemeData getSwitchTheme(ColorSchemeData colorScheme) { 5 | return SwitchThemeData( 6 | thumbColor: MaterialStateProperty.resolveWith((states) => 7 | states.contains(MaterialState.selected) ? colorScheme.card : Colors.white), 8 | trackColor: MaterialStateProperty.resolveWith((states) => 9 | states.contains(MaterialState.selected) 10 | ? colorScheme.accent 11 | : colorScheme.onBackground.withOpacity(0.3)), 12 | overlayColor: MaterialStateProperty.resolveWith((states) => 13 | states.contains(MaterialState.selected) 14 | ? colorScheme.accent 15 | : colorScheme.onBackground.withOpacity(0.3)), 16 | trackOutlineColor: MaterialStateProperty.resolveWith((states) => 17 | states.contains(MaterialState.selected) 18 | ? colorScheme.accent 19 | : Colors.transparent), 20 | splashRadius: 0, 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /lib/clock/logic/timezone_database.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:clock_app/developer/logic/logger.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter/services.dart'; 7 | 8 | import 'package:clock_app/common/data/paths.dart'; 9 | import 'package:path/path.dart'; 10 | // Database? database; 11 | 12 | Future initializeDatabases() async { 13 | String timezonesDatabasePath = await getTimezonesDatabasePath(); 14 | 15 | // Only copy if the database doesn't exist 16 | if (FileSystemEntity.typeSync(timezonesDatabasePath) == 17 | FileSystemEntityType.notFound) { 18 | // Load database from asset and copy 19 | ByteData data = await rootBundle.load(join('assets', 'timezones.db')); 20 | List bytes = 21 | data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); 22 | 23 | logger.i('Copying timzones.db to $timezonesDatabasePath'); 24 | // Save copied asset to documents 25 | await File(timezonesDatabasePath).writeAsBytes(bytes); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/alarm/types/ringing_manager.dart: -------------------------------------------------------------------------------- 1 | 2 | // This class is used to keep track of what alarms/timers are currently ringing 3 | class RingingManager { 4 | static int _ringingAlarmId = -1; 5 | static final List _ringingTimerIds = []; 6 | 7 | static int get ringingAlarmId => _ringingAlarmId; 8 | static List get ringingTimerIds => _ringingTimerIds; 9 | static int get activeTimerId => 10 | _ringingTimerIds.isNotEmpty ? _ringingTimerIds.last : -1; 11 | 12 | static bool get isAlarmRinging => _ringingAlarmId != -1; 13 | static bool get isTimerRinging => _ringingTimerIds.isNotEmpty; 14 | 15 | static void ringAlarm(int alarmId) { 16 | _ringingAlarmId = alarmId; 17 | } 18 | 19 | static void stopAlarm() { 20 | _ringingAlarmId = -1; 21 | } 22 | 23 | static void ringTimer(int timerId) { 24 | _ringingTimerIds.add(timerId); 25 | } 26 | 27 | static void stopTimer(int timerId) { 28 | _ringingTimerIds.remove(timerId); 29 | } 30 | 31 | static void stopAllTimers() { 32 | _ringingTimerIds.clear(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/slide_in_down.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class SlideInDown extends AnimationEffect { 5 | static const Offset beginValue = Offset(0, 1); 6 | static const Offset endValue = Offset(0, 0); 7 | final Offset? begin; 8 | final Offset? end; 9 | 10 | SlideInDown({super.delay, super.duration, super.curve, this.begin, this.end}); 11 | 12 | @override 13 | Widget build(BuildContext context, Widget child, Animation animation, 14 | EffectEntry entry, Duration totalDuration) { 15 | final Animation position = buildAnimation(entry, totalDuration, 16 | begin: begin ?? beginValue, end: endValue) 17 | .animate(animation); 18 | return ClipRect( 19 | clipBehavior: Clip.hardEdge, 20 | child: SlideTransition( 21 | position: position, 22 | child: child, 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/digital_clock.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | -------------------------------------------------------------------------------- /android/app/src/dev/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/common/widgets/list/delete_alert_dialogue.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Future showDeleteAlertDialogue(BuildContext context) async { 4 | ThemeData theme = Theme.of(context); 5 | ColorScheme colorScheme = theme.colorScheme; 6 | return await showDialog( 7 | context: context, 8 | builder: (buildContext) { 9 | return AlertDialog( 10 | actionsPadding: const EdgeInsets.only(bottom: 6, right: 10), 11 | content: const Text("Do you want to delete all filtered items?"), 12 | actions: [ 13 | TextButton( 14 | onPressed: () { 15 | Navigator.pop(context, false); 16 | }, 17 | child: Text("No", style: TextStyle(color: colorScheme.primary)), 18 | ), 19 | TextButton( 20 | onPressed: () { 21 | Navigator.pop(context, true); 22 | }, 23 | child: Text("Yes", style: TextStyle(color: colorScheme.error)), 24 | ), 25 | ], 26 | ); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /android/app/src/dev/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/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/theme/slider.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/types/color_scheme.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class CustomTrackShape extends RoundedRectSliderTrackShape { 5 | @override 6 | Rect getPreferredRect({ 7 | required RenderBox parentBox, 8 | Offset offset = Offset.zero, 9 | required SliderThemeData sliderTheme, 10 | bool isEnabled = false, 11 | bool isDiscrete = false, 12 | }) { 13 | final trackHeight = sliderTheme.trackHeight; 14 | final trackLeft = offset.dx; 15 | final trackTop = offset.dy + (parentBox.size.height - trackHeight!) / 2; 16 | final trackWidth = parentBox.size.width; 17 | return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight); 18 | } 19 | } 20 | 21 | SliderThemeData getSliderTheme(ColorSchemeData colorScheme) { 22 | return SliderThemeData( 23 | // trackShape: CustomTrackShape(), 24 | overlayShape: SliderComponentShape.noOverlay, 25 | inactiveTrackColor: colorScheme.onBackground.withOpacity(0.2) 26 | // overlayShape: RoundSliderOverlayShape(overlayRadius: 16), 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /lib/system/logic/quick_actions.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/navigation/data/tabs.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:quick_actions/quick_actions.dart'; 4 | 5 | Future initializeQuickActions( 6 | BuildContext context, Function(int, [String?]) setTab) async { 7 | const QuickActions quickActions = QuickActions(); 8 | await quickActions.initialize((shortcutType) { 9 | if (shortcutType == 'action_add_alarm') { 10 | setTab(getTabs(context).indexWhere((tab) => tab.id == "alarm"), "add_alarm"); 11 | } 12 | if (shortcutType == 'action_add_timer') { 13 | setTab(getTabs(context).indexWhere((tab) => tab.id == "timer"), "add_timer"); 14 | } 15 | // More handling code... 16 | }); 17 | 18 | await quickActions.setShortcutItems([ 19 | const ShortcutItem( 20 | type: 'action_add_alarm', 21 | localizedTitle: 'Add alarm', 22 | icon: 'alarm_icon'), 23 | const ShortcutItem( 24 | type: 'action_add_timer', 25 | localizedTitle: 'Add timer', 26 | icon: 'timer_icon') 27 | ]); 28 | } 29 | -------------------------------------------------------------------------------- /lib/system/logic/handle_boot.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/logic/update_alarms.dart'; 2 | import 'package:clock_app/developer/logic/logger.dart'; 3 | import 'package:clock_app/system/logic/initialize_isolate.dart'; 4 | import 'package:clock_app/timer/logic/update_timers.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | @pragma('vm:entry-point') 8 | void handleBoot() async { 9 | // String appDataDirectory = await getAppDataDirectoryPath(); 10 | // 11 | // String message = '[${DateTime.now().toString()}] Test2\n'; 12 | // 13 | // File('$appDataDirectory/log-dart.txt') 14 | // .writeAsStringSync(message, mode: FileMode.append); 15 | // 16 | FlutterError.onError = (FlutterErrorDetails details) { 17 | logger.f("Error in handleBoot isolate: ${details.exception.toString()}"); 18 | }; 19 | 20 | await initializeIsolate(); 21 | try { 22 | await updateAlarms("handleBoot(): Update alarms on system boot"); 23 | await updateTimers("handleBoot(): Update timers on system boot"); 24 | } catch (e) { 25 | logger.f("Error in handleBoot isolate: ${e.toString()}"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scripts/patreons.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import json 3 | import requests 4 | import os 5 | 6 | def csv_to_json(csv_file, json_file): 7 | members = [] 8 | with open(csv_file, 'r') as file: 9 | csv_reader = csv.DictReader(file) 10 | for row in csv_reader: 11 | if(float(row['Lifetime Amount']) > 0): 12 | member_info = { 13 | 'name': row['Name'], 14 | 'lifetime_amount': row['Lifetime Amount'], 15 | 'email': row['Email'], 16 | } 17 | members.append(member_info) 18 | members = sorted(members, key=lambda x: float(x['lifetime_amount']), reverse=True) 19 | json_output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../assets/patreons/') 20 | os.makedirs(json_output_dir, exist_ok=True) 21 | json_output_path = os.path.join(json_output_dir, 'patreons.json') 22 | with open(json_output_path, 'w') as json_file: 23 | json.dump(members, json_file, indent=4) 24 | print("CSV converted to JSON") 25 | 26 | if __name__ == "__main__": 27 | csv_to_json('patreons.csv', 'patreons.json') 28 | -------------------------------------------------------------------------------- /lib/alarm/data/alarm_events_sort_options.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/types/alarm.dart'; 2 | import 'package:clock_app/alarm/types/alarm_event.dart'; 3 | import 'package:clock_app/common/types/list_filter.dart'; 4 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 5 | 6 | final List> alarmEventSortOptions = [ 7 | ListSortOption((context) => "Earliest start date", sortStartDateAscending), 8 | ListSortOption((context) => "Latest start date", sortStartDateDescending), 9 | ListSortOption((context) => "Earliest event date", sortEventDateAscending), 10 | ListSortOption((context) => "Latest event date", sortEventDateDescending), 11 | ]; 12 | 13 | int sortStartDateAscending(AlarmEvent a, AlarmEvent b) { 14 | return a.startDate.compareTo(b.startDate); 15 | } 16 | 17 | int sortStartDateDescending(AlarmEvent a, AlarmEvent b) { 18 | return b.startDate.compareTo(a.startDate); 19 | } 20 | 21 | int sortEventDateAscending(AlarmEvent a, AlarmEvent b) { 22 | return a.eventTime.compareTo(b.eventTime); 23 | } 24 | 25 | int sortEventDateDescending(AlarmEvent a, AlarmEvent b) { 26 | return b.eventTime.compareTo(a.eventTime); 27 | } 28 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 |

Features

2 |
    3 |
  • Modern and easy to use interface
  • 4 |
5 |

Alarms

6 |
    7 |
  • Customizable schedules (daily, weekly, specific week days, specific dates, date range)
  • 8 |
  • Configure melody, rising volume and vibrations
  • 9 |
  • Configure snooze length and max snoozes
  • 10 |
  • Alarm tasks (math problems, retype text, sequence, more to come)
  • 11 |
  • Filter alarms (all, today, tomorrow, snoozed, disabled, completed)
  • 12 |
13 |

Clock

14 |
    15 |
  • Customizable clock display
  • 16 |
  • World clocks with relative time difference
  • 17 |
  • Search and add cities
  • 18 |
19 |

Timer

20 |
    21 |
  • Configure melody, rising volume and vibrations
  • 22 |
  • Timer presets
  • 23 |
  • Filter timers (all, running, paused, stopped)
  • 24 |
25 |

Stopwatch

26 |
    27 |
  • Lap history with lap times and elapsed times
  • 28 |
  • Lap comparisons
  • 29 |
Appearance 31 |
    32 |
  • Material You themes
  • 33 |
  • Highly customizable color themes
  • 34 |
  • Highly customizable style themes
  • 35 |
36 | -------------------------------------------------------------------------------- /lib/alarm/logic/alarm_time.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock/clock.dart'; 2 | import 'package:clock_app/common/types/time.dart'; 3 | import 'package:clock_app/developer/logic/logger.dart'; 4 | 5 | // Calculates the DateTime when the provided `time` will next occur 6 | DateTime getScheduleDateForTime( 7 | Time time, { 8 | DateTime? scheduleStartDate, 9 | int interval = 1, 10 | }) { 11 | DateTime now = clock.now(); 12 | 13 | // If a date has not been provided, assume it to be today 14 | DateTime scheduleDate = scheduleStartDate ?? now; 15 | DateTime alarmTime = DateTime(scheduleDate.year, scheduleDate.month, 16 | scheduleDate.day, time.hour, time.minute, time.second); 17 | 18 | while (!alarmTime.isAfter(now)) { 19 | alarmTime = alarmTime.add(Duration(days: interval)); 20 | } 21 | 22 | return alarmTime; 23 | } 24 | 25 | // Calculates the DateTime when the provided `time` will next occur on the 26 | // provided `weekday` 27 | DateTime getWeeklyScheduleDateForTIme(Time time, int weekday) { 28 | DateTime dateTime = getScheduleDateForTime(time); 29 | while (dateTime.weekday != weekday) { 30 | dateTime = dateTime.add(const Duration(days: 1)); 31 | } 32 | return dateTime; 33 | } 34 | -------------------------------------------------------------------------------- /lib/notifications/logic/notifications.dart: -------------------------------------------------------------------------------- 1 | import 'package:awesome_notifications/awesome_notifications.dart'; 2 | import 'package:clock_app/notifications/data/notification_channel.dart'; 3 | 4 | void requestNotificationPermissions({Function? onAlreadyGranted}) async { 5 | AwesomeNotifications().isNotificationAllowed().then((allowed) { 6 | if (!allowed) { 7 | AwesomeNotifications().requestPermissionToSendNotifications( 8 | permissions: [ 9 | // NotificationPermission.Sound, 10 | NotificationPermission.Alert, 11 | NotificationPermission.FullScreenIntent, 12 | ], 13 | ); 14 | } else { 15 | onAlreadyGranted?.call(); 16 | } 17 | }); 18 | } 19 | 20 | Future initializeNotifications() async { 21 | requestNotificationPermissions(); 22 | await AwesomeNotifications().initialize( 23 | null, // use default app icon 24 | [ 25 | alarmNotificationChannel, 26 | reminderNotificationChannel, 27 | stopwatchNotificationChannel, 28 | timerNotificationChannel, 29 | // foregroundNotificationChannel, 30 | ], 31 | // channelGroups: [alarmNotificationChannelGroup], 32 | debug: false, 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /lib/settings/types/setting_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/settings/types/setting_enable_condition.dart'; 2 | import 'package:clock_app/settings/types/setting_item.dart'; 3 | import 'package:clock_app/settings/utils/description.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class SettingAction extends SettingItem { 7 | void Function(BuildContext context) action; 8 | 9 | SettingAction( 10 | String name, 11 | String Function(BuildContext) getLocalizedName, 12 | this.action, { 13 | String Function(BuildContext) getDescription = defaultDescription, 14 | List searchTags = const [], 15 | List enableConditions = const [], 16 | }) : super(name, getLocalizedName, getDescription, searchTags, enableConditions); 17 | 18 | @override 19 | SettingAction copy() { 20 | return SettingAction(name, getLocalizedName, action, 21 | getDescription: getDescription, 22 | searchTags: searchTags, 23 | enableConditions: enableConditions,); 24 | } 25 | 26 | @override 27 | dynamic valueToJson() { 28 | return null; 29 | } 30 | 31 | @override 32 | void loadValueFromJson(dynamic value) { 33 | return; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/common/utils/weekday_utils_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/data/weekdays.dart'; 2 | import 'package:clock_app/common/utils/weekday_utils.dart'; 3 | import 'package:flutter_test/flutter_test.dart'; 4 | 5 | void main() { 6 | group('weekdaysContains', () { 7 | test('returns true when the weekday is contained in the list', () { 8 | final testWeekdays = [weekdays[0]]; 9 | expect(weekdaysContains(testWeekdays, 1), isTrue); 10 | }); 11 | 12 | test('returns false when the weekday is not contained in the list', () { 13 | final testWeekdays = [weekdays[0]]; 14 | expect(weekdaysContains(testWeekdays, 2), isFalse); 15 | }); 16 | }); 17 | 18 | group('weekdaysContainsAll', () { 19 | test('returns true when all the weekdays are contained in the list', () { 20 | final testWeekdays = [weekdays[5], weekdays[6]]; 21 | expect(weekdaysContainsAll(testWeekdays, [6, 7]), isTrue); 22 | }); 23 | 24 | test('returns false when at least one weekday is not contained in the list', 25 | () { 26 | final testWeekdays = [weekdays[4], weekdays[6]]; 27 | expect(weekdaysContainsAll(testWeekdays, [6, 1]), isFalse); 28 | }); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /lib/common/widgets/fields/select_field/field_cards/color_field_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/select_choice.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class ColorFieldCard extends StatelessWidget { 5 | const ColorFieldCard({super.key, required this.title, required this.choice}); 6 | 7 | final String title; 8 | final SelectChoice choice; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Row( 13 | children: [ 14 | Column( 15 | crossAxisAlignment: CrossAxisAlignment.start, 16 | children: [ 17 | Text( 18 | title, 19 | style: Theme.of(context).textTheme.headlineMedium, 20 | ), 21 | const SizedBox(height: 4.0), 22 | ], 23 | ), 24 | const Spacer(), 25 | Container( 26 | width: 36.0, 27 | height: 36.0, 28 | decoration: BoxDecoration( 29 | color: choice.value, 30 | borderRadius: 31 | (Theme.of(context).cardTheme.shape as RoundedRectangleBorder) 32 | .borderRadius, 33 | ), 34 | ) 35 | ], 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/261.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Added option to select directory for ringtones (random ringtone will be selected from the directory each time) 6 | * Added multiselect for lists 7 | * Added option to shuffle alarm ringtone 8 | * Added backup and restore for alarms, timers, themes etc. 9 | * Added numpad input for timers 10 | * Added option to reduce volume while solving alarm tasks 11 | * Added quick home screen actions for alarms and timers 12 | * Added option to start ringtone at random position 13 | * Added background service to keep app alive 14 | * Added analog clock to clock tab 15 | 16 | ✨ Enhancements 17 | 18 | * Made alarm tasks reorderable 19 | * Added better logging system 20 | * Added alarm labels to alarm notifications 21 | 22 | 🐛 Fixes 23 | 24 | * Fixed non-deletable items getting deleted by list actions 25 | * Fixed range weekly schedule not working 26 | * Fixed system navigation bar color 27 | * Fixed database for cities 28 | * Fixed skipped alarms being visible to the system 29 | * Fixed foreground notification foreground type 30 | * Fixed date picker being stuck in the past for range alarms 31 | 32 | 33 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/262.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Added option to select directory for ringtones (random ringtone will be selected from the directory each time) 6 | * Added multiselect for lists 7 | * Added option to shuffle alarm ringtone 8 | * Added backup and restore for alarms, timers, themes etc. 9 | * Added numpad input for timers 10 | * Added option to reduce volume while solving alarm tasks 11 | * Added quick home screen actions for alarms and timers 12 | * Added option to start ringtone at random position 13 | * Added background service to keep app alive 14 | * Added analog clock to clock tab 15 | 16 | ✨ Enhancements 17 | 18 | * Made alarm tasks reorderable 19 | * Added better logging system 20 | * Added alarm labels to alarm notifications 21 | 22 | 🐛 Fixes 23 | 24 | * Fixed non-deletable items getting deleted by list actions 25 | * Fixed range weekly schedule not working 26 | * Fixed system navigation bar color 27 | * Fixed database for cities 28 | * Fixed skipped alarms being visible to the system 29 | * Fixed foreground notification foreground type 30 | * Fixed date picker being stuck in the past for range alarms 31 | 32 | 33 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/flipin_y.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | 6 | class FlipInY extends AnimationEffect { 7 | static const double beginValue = pi / 2; 8 | static const double endValue = 0.0; 9 | final double? begin; 10 | final double? end; 11 | 12 | FlipInY({super.delay, super.duration, super.curve, this.begin, this.end}); 13 | 14 | @override 15 | Widget build(BuildContext context, Widget child, Animation animation, 16 | EffectEntry entry, Duration totalDuration) { 17 | final Animation rotation = buildAnimation(entry, totalDuration, 18 | begin: begin ?? beginValue, end: endValue) 19 | .animate(animation); 20 | return AnimatedBuilder( 21 | animation: rotation, 22 | builder: (BuildContext context, Widget? child) { 23 | return Transform( 24 | transform: Matrix4.rotationY(rotation.value), 25 | alignment: Alignment.center, 26 | child: child, 27 | ); 28 | }, 29 | child: child, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/flipin_x.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | 6 | class FlipInX extends AnimationEffect { 7 | static const double beginValue = pi / 2; 8 | static const double endValue = 0.0; 9 | final double? begin; 10 | final double? end; 11 | 12 | FlipInX({super.delay, super.duration, super.curve, this.begin, this.end}); 13 | 14 | @override 15 | Widget build(BuildContext context, Widget child, Animation animation, 16 | EffectEntry entry, Duration totalDuration) { 17 | final Animation rotation = buildAnimation(entry, totalDuration, 18 | begin: begin ?? beginValue, end: endValue) 19 | .animate(animation); 20 | return AnimatedBuilder( 21 | animation: animation, 22 | builder: (BuildContext context, Widget? child) { 23 | return Transform( 24 | transform: Matrix4.rotationX(rotation.value), 25 | alignment: Alignment.center, 26 | child: child, 27 | ); 28 | }, 29 | child: child); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/common/widgets/measure_size.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/rendering.dart'; 3 | 4 | typedef OnWidgetSizeChange = void Function(Size size); 5 | 6 | class MeasureSizeRenderObject extends RenderProxyBox { 7 | Size? oldSize; 8 | OnWidgetSizeChange onChange; 9 | 10 | MeasureSizeRenderObject(this.onChange); 11 | 12 | @override 13 | void performLayout() { 14 | super.performLayout(); 15 | 16 | Size newSize = child!.size; 17 | if (oldSize == newSize) return; 18 | 19 | oldSize = newSize; 20 | WidgetsBinding.instance.addPostFrameCallback((_) { 21 | onChange(newSize); 22 | }); 23 | } 24 | } 25 | 26 | class MeasureSize extends SingleChildRenderObjectWidget { 27 | final OnWidgetSizeChange onChange; 28 | 29 | const MeasureSize({ 30 | super.key, 31 | required this.onChange, 32 | required Widget super.child, 33 | }); 34 | 35 | @override 36 | RenderObject createRenderObject(BuildContext context) { 37 | return MeasureSizeRenderObject(onChange); 38 | } 39 | 40 | @override 41 | void updateRenderObject( 42 | BuildContext context, covariant MeasureSizeRenderObject renderObject) { 43 | renderObject.onChange = onChange; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/263.txt: -------------------------------------------------------------------------------- 1 | This is a beta release. Please report any issues via GitHub or email. 2 | 3 | 🚀 Features 4 | 5 | * Added option to select directory for ringtones (random ringtone will be selected from the directory each time) 6 | * Added multiselect for lists 7 | * Added option to shuffle alarm ringtone 8 | * Added backup and restore for alarms, timers, themes etc. 9 | * Added numpad input for timers 10 | * Added option to reduce volume while solving alarm tasks 11 | * Added quick home screen actions for alarms and timers 12 | * Added option to start ringtone at random position 13 | * Added background service to keep app alive 14 | * Added analog clock to clock tab 15 | 16 | ✨ Enhancements 17 | 18 | * Made alarm tasks reorderable 19 | * Added better logging system 20 | * Added alarm labels to alarm notifications 21 | * Updated translations 22 | 23 | 🐛 Fixes 24 | 25 | * Fixed non-deletable items getting deleted by list actions 26 | * Fixed range weekly schedule not working 27 | * Fixed system navigation bar color 28 | * Fixed database for cities 29 | * Fixed skipped alarms being visible to the system 30 | * Fixed foreground notification foreground type 31 | * Fixed date picker being stuck in the past for range alarms 32 | 33 | 34 | -------------------------------------------------------------------------------- /fastlane/metadata/android/no-NO/full_description.txt: -------------------------------------------------------------------------------- 1 |

Funksjoner

2 |
    3 |
  • Moderne og lettfattelig grensesnitt
  • 4 |
5 |

Alarmer

6 |
    7 |
  • Tilpassbare timeplaner, (daglig, ukentlig, spesifikke ukedager, spesifikke dager, datofølge)
  • 8 |
  • Velg melodi, økende lydstyrke, og vibrasjon
  • 9 |
  • Slumringsvarighet, og maks. antall slumringer
  • 10 |
  • Alarmgjøremål (matematikkproblemer, gjenskriving av tekst, sekvensering, og andre planlagte ting)
  • 11 |
  • Filtrering av alarmer, (alle, i dag, i morgen, slumrede, avskrudde, fullførte)
  • 12 |
13 |

Klokke

14 |
    15 |
  • Tilpassbar klokkevisning
  • 16 |
  • Verdensklokke med relativ tidsforskyvelse
  • 17 |
  • Søk etter og legg til byer
  • 18 |
19 |

Tidsur

20 |
    21 |
  • Velg melodi, økende lydstyrke, og vibrasjon
  • 22 |
  • Tidsurforhåndsstillinger
  • 23 |
  • Filtrering av tidsur (alle, kjørende, pausede, stoppede)
  • 24 |
25 |

Stoppeklokke

26 |
    27 |
  • Rundehistorikk med rundetider og forløpt tid
  • 28 |
  • Rundesammenligninger
  • 29 |
Utseende 31 |
    32 |
  • Drakt av materiell deig
  • 33 |
  • Tilpassbar fargepalett
  • 34 |
  • Tilpassbare stilvalg
  • 35 |
36 | -------------------------------------------------------------------------------- /lib/common/widgets/fields/select_field/option_cards/color_option_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/select_choice.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class SelectColorOptionCard extends StatelessWidget { 5 | const SelectColorOptionCard({ 6 | super.key, 7 | required this.isSelected, 8 | required this.choice, 9 | required this.index, 10 | required this.onSelect, 11 | }); 12 | 13 | final bool isSelected; 14 | final SelectChoice choice; 15 | final int index; 16 | final void Function(List) onSelect; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return InkWell( 21 | onTap: () => onSelect([index]), 22 | child: Container( 23 | width: 64.0, 24 | height: 64.0, 25 | decoration: BoxDecoration( 26 | color: choice.value, 27 | borderRadius: 28 | (Theme.of(context).cardTheme.shape as RoundedRectangleBorder) 29 | .borderRadius, 30 | ), 31 | child: InkWell( 32 | onTap: () => onSelect([index]), 33 | child: isSelected 34 | ? const Icon(Icons.check, color: Colors.white) 35 | : null, 36 | )), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/full_description.txt: -------------------------------------------------------------------------------- 1 |

Merkmale

2 |
    3 |
  • Moderner und benutzerfreundlicher Interface
  • 4 |
5 |

Wecker

6 |
    7 |
  • Anpassbare Zeitpläne (täglich, wöchentlich, bestimmte Wochentage, bestimmte Daten, Datumsbereich)
  • 8 |
  • Anpassbare Melodie, ansteigende Lautstärke und Vibrationen
  • 9 |
  • Anpassbare Schlummerdauer und maximale Schlummeranzahl
  • 10 |
  • Wecker-Aufgaben (Matheaufgaben, Text neu eingeben, Sequenz, weitere folgen)
  • 11 |
  • Wecker filtern (alle, heute, morgen, pausiert, deaktiviert, abgeschlossen)
  • 12 |
13 |

Uhr

14 |
    15 |
  • Anpassbare Anzeige der Uhrzeit
  • 16 |
  • Weltuhren mit relativer Zeitdifferenz
  • 17 |
  • Suchen und hinzufügen von Städten
  • 18 |
19 |

Timer

20 |
    21 |
  • Anpassbare Melodie, ansteigende Lautstärke und Vibrationen
  • 22 |
  • Timer-Voreinstellungen
  • 23 |
  • Timer filtern (alle, aktiv, pausiert, gestoppt)
  • 24 |
25 |

Stoppuhr

26 |
    27 |
  • Rundenverlauf mit Rundenzeiten und vergangenen Zeiten
  • 28 |
  • Vergleich von Runden
  • 29 |
30 |

Darstellung

31 |
    32 |
  • Material You Thema
  • 33 |
  • Stark anpassbare Farbthemen
  • 34 |
  • Stark anpassbare Stilthemen
  • 35 |
36 | -------------------------------------------------------------------------------- /lib/common/utils/date_time.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/time.dart'; 2 | import 'package:clock_app/timer/types/time_duration.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | extension DateTimeUtils on DateTime { 6 | double toHours() => hour + minute / 60.0 + second / 3600.0; 7 | TimeOfDay toTimeOfDay() => TimeOfDay(hour: hour, minute: minute); 8 | TimeDuration toTimeDuration() => 9 | TimeDuration(hours: hour, minutes: minute, seconds: second); 10 | Time getTime() => Time(hour: hour, minute: minute, second: second); 11 | DateTime addTimeDuration(TimeDuration duration) => 12 | add(Duration(seconds: duration.inSeconds)); 13 | static DateTime fromNow(Duration duration) => DateTime.now().add(duration); 14 | static Time getTimeFromNow(Duration duration) => 15 | Time.fromDateTime(fromNow(duration)); 16 | 17 | bool isToday() { 18 | final now = DateTime.now(); 19 | return year == now.year && month == now.month && day == now.day; 20 | } 21 | 22 | bool isTomorrow() { 23 | final tomorrow = DateTime.now().add(const Duration(days: 1)); 24 | return year == tomorrow.year && 25 | month == tomorrow.month && 26 | day == tomorrow.day; 27 | } 28 | 29 | String toIso8601Date() => toIso8601String().substring(0, 10); 30 | } 31 | -------------------------------------------------------------------------------- /fastlane/metadata/android/uk/full_description.txt: -------------------------------------------------------------------------------- 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 |
Зовнішній вигляд 31 |
    32 |
  • Теми Material You
  • 33 |
  • Налаштовувані кольорові теми
  • 34 |
  • Налаштовуваніі теми стилю
  • 35 |
36 | -------------------------------------------------------------------------------- /lib/settings/types/setting_link.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/settings/types/setting_enable_condition.dart'; 2 | import 'package:clock_app/settings/types/setting_item.dart'; 3 | import 'package:clock_app/settings/utils/description.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class SettingPageLink extends SettingItem { 7 | final Widget screen; 8 | final IconData? icon; 9 | 10 | SettingPageLink( 11 | String name, 12 | String Function(BuildContext) getLocalizedName, 13 | this.screen, { 14 | String Function(BuildContext) getDescription = defaultDescription, 15 | this.icon, 16 | List searchTags = const [], 17 | List enableConditions = const [], 18 | }) : super(name, getLocalizedName, getDescription, searchTags, 19 | enableConditions); 20 | 21 | @override 22 | SettingPageLink copy() { 23 | return SettingPageLink( 24 | name, 25 | getLocalizedName, 26 | screen, 27 | icon: icon, 28 | getDescription: getDescription, 29 | searchTags: searchTags, 30 | enableConditions: enableConditions, 31 | ); 32 | } 33 | 34 | @override 35 | dynamic valueToJson() { 36 | return null; 37 | } 38 | 39 | @override 40 | void loadValueFromJson(dynamic value) { 41 | return; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/notifications/logic/foreground_task.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_foreground_task/flutter_foreground_task.dart'; 2 | 3 | void initForegroundTask() { 4 | FlutterForegroundTask.init( 5 | androidNotificationOptions: AndroidNotificationOptions( 6 | channelId: 'foreground_service', 7 | channelName: 'Foreground Service Notification', 8 | channelDescription: 9 | 'This notification appears when the foreground service is running.', 10 | channelImportance: NotificationChannelImportance.LOW, 11 | priority: NotificationPriority.LOW, 12 | iconData: const NotificationIconData( 13 | resType: ResourceType.drawable, 14 | resPrefix: ResourcePrefix.ic, 15 | name: 'alarm_icon', 16 | ), 17 | // buttons: [ 18 | // const NotificationButton(id: 'sendButton', text: 'Send'), 19 | // const NotificationButton(id: 'testButton', text: 'Test'), 20 | // ], 21 | ), 22 | iosNotificationOptions: const IOSNotificationOptions( 23 | showNotification: true, 24 | playSound: false, 25 | ), 26 | foregroundTaskOptions: const ForegroundTaskOptions( 27 | interval: 1000 * 60, 28 | isOnceEvent: false, 29 | autoRunOnBoot: true, 30 | allowWakeLock: true, 31 | allowWifiLock: true, 32 | ), 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /lib/common/widgets/list/animated_reorderable_list/animation/size_animation.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/list/animated_reorderable_list/animation/provider/animation_effect.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class SizeAnimation extends AnimationEffect { 5 | static const double beginValue = 0.0; 6 | static const double endValue = 1.0; 7 | static const double alignmentValue = 0.0; 8 | final double? begin; 9 | final double? end; 10 | final Axis? axis; 11 | final double? axisAlignment; 12 | 13 | SizeAnimation( 14 | {super.delay, 15 | super.duration, 16 | super.curve, 17 | this.begin, 18 | this.end, 19 | this.axis, 20 | this.axisAlignment}); 21 | 22 | @override 23 | Widget build(BuildContext context, Widget child, Animation animation, 24 | EffectEntry entry, Duration totalDuration) { 25 | final Animation sizeFactor = buildAnimation(entry, totalDuration, 26 | begin: begin ?? beginValue, end: end ?? endValue) 27 | .animate(animation); 28 | return Align( 29 | child: SizeTransition( 30 | sizeFactor: sizeFactor, 31 | axis: axis ?? Axis.horizontal, 32 | axisAlignment: axisAlignment ?? alignmentValue, 33 | child: child, 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/settings/widgets/color_setting_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/card_container.dart'; 2 | import 'package:clock_app/common/widgets/fields/color_field.dart'; 3 | import 'package:clock_app/settings/types/setting.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class ColorSettingCard extends StatefulWidget { 7 | const ColorSettingCard( 8 | {super.key, 9 | required this.setting, 10 | this.showAsCard = false, 11 | this.onChanged}); 12 | 13 | final ColorSetting setting; 14 | final bool showAsCard; 15 | final void Function(Color)? onChanged; 16 | 17 | @override 18 | State createState() => _ColorSettingCardState(); 19 | } 20 | 21 | class _ColorSettingCardState extends State { 22 | @override 23 | Widget build(BuildContext context) { 24 | ColorField toggleCard = ColorField( 25 | name: widget.setting.displayName(context), 26 | value: widget.setting.value, 27 | enableOpacity: widget.setting.enableOpacity, 28 | onChange: (value) { 29 | setState(() { 30 | widget.setting.setValue(context, value); 31 | }); 32 | 33 | widget.onChanged?.call(widget.setting.value); 34 | }, 35 | ); 36 | 37 | return widget.showAsCard ? CardContainer(child: toggleCard) : toggleCard; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/settings/widgets/switch_setting_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/card_container.dart'; 2 | import 'package:clock_app/common/widgets/fields/switch_field.dart'; 3 | import 'package:clock_app/settings/types/setting.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class SwitchSettingCard extends StatefulWidget { 7 | final SwitchSetting setting; 8 | final bool showAsCard; 9 | final void Function(bool)? onChanged; 10 | 11 | const SwitchSettingCard( 12 | {super.key, 13 | required this.setting, 14 | this.showAsCard = false, 15 | this.onChanged}); 16 | 17 | @override 18 | State createState() => _SwitchSettingCardState(); 19 | } 20 | 21 | class _SwitchSettingCardState extends State { 22 | @override 23 | Widget build(BuildContext context) { 24 | SwitchField switchCard = SwitchField( 25 | name: widget.setting.displayName(context), 26 | value: widget.setting.value, 27 | description: widget.setting.displayDescription(context), 28 | onChanged: (value) { 29 | setState(() { 30 | widget.setting.setValue(context, value); 31 | }); 32 | widget.onChanged?.call(widget.setting.value); 33 | }, 34 | ); 35 | 36 | return widget.showAsCard ? CardContainer(child: switchCard) : switchCard; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/developer/data/log_list_filters.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/types/alarm_event.dart'; 2 | import 'package:clock_app/common/types/list_filter.dart'; 3 | import 'package:clock_app/common/utils/date_time.dart'; 4 | import 'package:clock_app/developer/types/log.dart'; 5 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 6 | import 'package:logger/logger.dart'; 7 | 8 | final List> logListFilters = [ 9 | ListFilterSelect((context) => AppLocalizations.of(context)!.dateFilterGroup, [ 10 | ListFilter((context) => AppLocalizations.of(context)!.todayFilter, 11 | (log) => log.dateTime.isToday()), 12 | ListFilter((context) => AppLocalizations.of(context)!.tomorrowFilter, 13 | (log) => log.dateTime.isTomorrow()), 14 | ]), 15 | ListFilterMultiSelect( 16 | (context) => AppLocalizations.of(context)!.logTypeFilterGroup, [ 17 | ListFilter((context) => "Debug", (log) => log.level == Level.debug), 18 | ListFilter((context) => "Trace", (log) => log.level == Level.trace), 19 | ListFilter((context) => "Info", (log) => log.level == Level.info), 20 | ListFilter((context) => "Warning", (log) => log.level == Level.warning), 21 | ListFilter((context) => "Error", (log) => log.level == Level.error), 22 | ListFilter((context) => "Fatal", (log) => log.level == Level.fatal), 23 | ]), 24 | ]; 25 | -------------------------------------------------------------------------------- /lib/timer/data/timer_list_filters.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/list_filter.dart'; 2 | import 'package:clock_app/common/types/tag.dart'; 3 | import 'package:clock_app/common/utils/list_storage.dart'; 4 | import 'package:clock_app/timer/types/timer.dart'; 5 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 6 | 7 | final List> timerListFilters = [ 8 | ListFilterSelect( 9 | (context) => AppLocalizations.of(context)!.stateFilterGroup, [ 10 | ListFilter( 11 | (context) => AppLocalizations.of(context)!.runningTimerFilter, 12 | (timer) => timer.isRunning, 13 | ), 14 | ListFilter( 15 | (context) => AppLocalizations.of(context)!.pausedTimerFilter, 16 | (timer) => timer.isPaused, 17 | ), 18 | ListFilter( 19 | (context) => AppLocalizations.of(context)!.stoppedTimerFilter, 20 | (timer) => timer.isStopped, 21 | ), 22 | ]), 23 | // 24 | DynamicListFilterMultiSelect( 25 | (context) => AppLocalizations.of(context)!.tagsSetting, () { 26 | final tags = loadListSync("tags"); 27 | return tags.map((tag) { 28 | return ListFilter( 29 | (context) => tag.name, 30 | (timer) => timer.tags.any((element) => element.id == tag.id), 31 | id: tag.id, 32 | ); 33 | }).toList(); 34 | }), 35 | ]; 36 | -------------------------------------------------------------------------------- /lib/timer/widgets/timer_duration_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/timer/types/time_duration.dart'; 2 | import 'package:clock_app/timer/types/timer.dart'; 3 | import 'package:clock_app/timer/widgets/duration_picker.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class TimerDurationPicker extends StatefulWidget { 7 | const TimerDurationPicker({super.key, required this.timer}); 8 | 9 | final ClockTimer timer; 10 | 11 | @override 12 | State createState() => _TimerDurationPickerState(); 13 | } 14 | 15 | class _TimerDurationPickerState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | ThemeData theme = Theme.of(context); 19 | TextTheme textTheme = theme.textTheme; 20 | 21 | return GestureDetector( 22 | onTap: () async { 23 | TimeDuration? newTimeDuration = await showDurationPicker( 24 | context, 25 | initialTimeDuration: widget.timer.duration, 26 | ); 27 | if (newTimeDuration == null) return; 28 | setState(() { 29 | widget.timer.setDuration(newTimeDuration); 30 | }); 31 | }, 32 | child: Text(widget.timer.duration.toString(), 33 | style: textTheme.displayLarge?.copyWith( 34 | fontSize: widget.timer.remainingSeconds > 3600 ? 48 : 56)), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/theme/data/default_style_themes.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/theme/types/style_theme.dart'; 2 | 3 | List defaultStyleThemes = [ 4 | StyleTheme( 5 | name: 'Paper', 6 | shadowElevation: 1, 7 | shadowOpacity: 0.2, 8 | shadowBlurRadius: 1, 9 | shadowSpreadRadius: 0, 10 | borderRadius: 16, 11 | borderWidth: 0, 12 | isDefault: true, 13 | ), 14 | StyleTheme( 15 | name: 'Industrial', 16 | shadowElevation: 1, 17 | shadowOpacity: 0.2, 18 | shadowBlurRadius: 1, 19 | shadowSpreadRadius: 0, 20 | borderRadius: 0, 21 | borderWidth: 0, 22 | isDefault: true, 23 | ), 24 | StyleTheme( 25 | name: 'Minimal', 26 | shadowElevation: 0, 27 | shadowOpacity: 0, 28 | shadowBlurRadius: 0, 29 | shadowSpreadRadius: 0, 30 | borderRadius: 16, 31 | borderWidth: 0, 32 | isDefault: true, 33 | ), 34 | StyleTheme( 35 | name: 'Outline', 36 | shadowElevation: 0, 37 | shadowOpacity: 0, 38 | shadowBlurRadius: 0, 39 | shadowSpreadRadius: 0, 40 | borderRadius: 16, 41 | borderWidth: 1, 42 | isDefault: true, 43 | ), 44 | StyleTheme( 45 | name: 'Retro', 46 | shadowElevation: 1, 47 | shadowOpacity: 0.1, 48 | shadowBlurRadius: 2, 49 | shadowSpreadRadius: 1, 50 | borderRadius: 4, 51 | borderWidth: 0, 52 | isDefault: true, 53 | ), 54 | ]; 55 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ru-RU/full_description.txt: -------------------------------------------------------------------------------- 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 |
Внешний вид 31 |
    32 |
  • Темы Material You
  • 33 |
  • Широкие возможности настройки цветовых тем
  • 34 |
  • Широкие возможности настройки тем стиля
  • 35 |
36 | -------------------------------------------------------------------------------- /fastlane/metadata/android/vi/full_description.txt: -------------------------------------------------------------------------------- 1 |

Tính năng

2 |
    3 |
  • Giao diện hiện đại và dễ sử dụng
  • 4 |
5 |

Báo thức

6 |
    7 |
  • Lịch trình có thể tùy chỉnh (hàng ngày, hàng tuần, các ngày cụ thể trong tuần, ngày cụ thể, phạm vi ngày)
  • 8 |
  • Định cấu hình giai điệu, tăng âm lượng và rung
  • 9 |
  • Định cấu hình thời lượng hoãn và thời gian hoãn tối đa
  • 10 |
  • Nhiệm vụ báo thức (bài toán, gõ lại văn bản, trình tự, nhiều nội dung khác sắp tới)
  • 11 |
  • Bộ lọc báo thức (tất cả, hôm nay, ngày mai, đã hoãn, đã tắt, đã hoàn thành)
  • 12 |
13 |

Đồng hồ

14 |
    15 |
  • Hiển thị đồng hồ có thể tùy chỉnh
  • 16 |
  • Đồng hồ thế giới có chênh lệch thời gian tương đối
  • 17 |
  • Tìm kiếm và thêm thành phố
  • 18 |
19 |

Bộ hẹn giờ

20 |
    21 |
  • Định cấu hình giai điệu, tăng âm lượng và rung
  • 22 |
  • Cài đặt trước bộ hẹn giờ
  • 23 |
  • Lọc bộ hẹn giờ (tất cả, đang chạy, đã tạm dừng, đã dừng)
  • 24 |
25 |

Đồng hồ bấm giờ

26 |
    27 |
  • Lịch sử vòng chạy với thời gian vòng chạy và thời gian đã trôi qua
  • 28 |
  • So sánh vòng
  • 29 |
Diện mạo 31 |
    32 |
  • Chủ đề của Material You
  • 33 |
  • Chủ đề màu sắc có khả năng tùy chỉnh cao
  • 34 |
  • Chủ đề phong cách có khả năng tùy chỉnh cao
  • 35 |
36 | -------------------------------------------------------------------------------- /fastlane/metadata/android/tr-TR/full_description.txt: -------------------------------------------------------------------------------- 1 |

Özellikler

2 |
    3 |
  • Modern ve kullanımı kolay arayüz
  • 4 |
5 |

Alarm

6 |
    7 |
  • Özelleştirilebilir programlar (günlük, haftalık, haftanın belirli günleri, belirli tarihler, tarih aralığı)
  • 8 |
  • Melodiyi, artan ses seviyesini ve titreşimleri yapılandırma
  • 9 |
  • Erteleme uzunluğunu ve maksimum erteleme sayısını yapılandırma
  • 10 |
  • Görev tanımlı alarmlar (matematik problemleri, metni yeniden yazma, sıralama, dahası gelecek)
  • 11 |
  • Alarmları filtreleme (tümü, bugün, yarın, ertelendi, devre dışı bırakıldı, tamamlandı)
  • 12 |
13 |

Saat

14 |
    15 |
  • Özelleştirilebilir saat ekranı
  • 16 |
  • Göreceli zaman farkı olan dünya saatleri
  • 17 |
  • Şehirleri ara ve ekle
  • 18 |
19 |

Zamanlayıcı

20 |
    21 |
  • Melodiyi, artan ses seviyesini ve titreşimleri yapılandırma
  • 22 |
  • Zamanlayıcı ön ayarları
  • 23 |
  • Zamanlayıcıları filtreleme (tümü, çalışıyor, duraklatıldı, durduruldu)
  • 24 |
25 |

Kronometre

26 |
    27 |
  • Tur süreleri ve geçen sürelerle birlikte tur geçmişi
  • 28 |
  • Tur karşılaştırmaları
  • 29 |
Görünüm 31 |
    32 |
  • Materyal You temaları
  • 33 |
  • Son derece özelleştirilebilir renk temaları
  • 34 |
  • Son derece özelleştirilebilir tarz temaları
  • 35 |
36 | -------------------------------------------------------------------------------- /lib/alarm/widgets/try_alarm_task_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/alarm/screens/try_alarm_task_screen.dart'; 2 | import 'package:clock_app/alarm/types/alarm_task.dart'; 3 | import 'package:clock_app/common/widgets/card_container.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class TryAlarmTaskButton extends StatelessWidget { 7 | const TryAlarmTaskButton({super.key, required this.alarmTask}); 8 | 9 | final AlarmTask alarmTask; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | ThemeData theme = Theme.of(context); 14 | ColorScheme colorScheme = theme.colorScheme; 15 | TextTheme textTheme = theme.textTheme; 16 | 17 | return CardContainer( 18 | color: colorScheme.primary, 19 | onTap: () { 20 | Navigator.push( 21 | context, 22 | MaterialPageRoute( 23 | builder: (context) => TryAlarmTaskScreen(alarmTask: alarmTask), 24 | ), 25 | ); 26 | }, 27 | child: SizedBox( 28 | width: double.infinity, 29 | child: Center( 30 | child: Padding( 31 | padding: const EdgeInsets.all(16.0), 32 | child: Text("Try Out", 33 | style: textTheme.titleMedium?.copyWith( 34 | color: colorScheme.onPrimary, 35 | )), 36 | ), 37 | ), 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/settings/widgets/date_setting_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/widgets/card_container.dart'; 2 | import 'package:clock_app/common/widgets/fields/date_picker_field.dart'; 3 | import 'package:clock_app/settings/types/setting.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class DateSettingCard extends StatefulWidget { 7 | final DateTimeSetting setting; 8 | final bool showAsCard; 9 | final void Function(List)? onChanged; 10 | 11 | const DateSettingCard({ 12 | super.key, 13 | required this.setting, 14 | this.showAsCard = false, 15 | this.onChanged, 16 | }); 17 | 18 | @override 19 | State createState() => _DateSettingCardState(); 20 | } 21 | 22 | class _DateSettingCardState extends State { 23 | @override 24 | Widget build(BuildContext context) { 25 | Widget input = DatePickerField( 26 | title: widget.setting.displayName(context), 27 | description: widget.setting.displayDescription(context), 28 | value: widget.setting.value, 29 | rangeOnly: widget.setting.rangeOnly, 30 | onChanged: (value) { 31 | setState(() { 32 | widget.setting.setValue(context, value); 33 | }); 34 | widget.onChanged?.call(widget.setting.value); 35 | }, 36 | ); 37 | 38 | return widget.showAsCard ? CardContainer(child: input) : input; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fastlane/metadata/android/fr-FR/full_description.txt: -------------------------------------------------------------------------------- 1 |

Fonctionnalités

2 |
    3 |
  • Interface moderne et facile à utiliser
  • 4 |
5 |

Alarmes

6 |
    7 |
  • Programmes personnalisables (quotidiens, hebdomadaires, jours spécifiques, dates spécifiques, plage de dates)
  • 8 |
  • Configurer la mélodie, l'augmentation du volume et les vibrations
  • 9 |
  • Configurer la durée et le nombre maximal de répétitions
  • 10 |
  • Tâches d'alarme (problèmes mathématiques, retapez du texte, séquence, etc.)
  • 11 |
  • Filtrer les alarmes (toutes, aujourd'hui, demain, répétées, désactivées, terminées)
  • 12 |
13 |

Horloge

14 |
    15 |
  • Affichage de l'horloge personnalisable
  • 16 |
  • Horloges mondiales avec décalage horaire relatif
  • 17 |
  • Rechercher et ajouter des villes
  • 18 |
19 |

Minuterie

20 |
    21 |
  • Configurer la mélodie, l'augmentation du volume et les vibrations
  • 22 |
  • Préréglages de minuterie
  • 23 |
  • Filtrer les minuteurs (tous, en cours d'exécution, en pause, arrêtés)
  • 24 |
25 |

Chronomètre

26 |
    27 |
  • Historique des tours avec temps du tour et temps écoulés
  • 28 |
  • Comparaisons de tours
  • 29 |
Apparence 31 |
    32 |
  • Thèmes Material You
  • 33 |
  • Thèmes de couleurs personnalisables
  • 34 |
  • Thèmes de style personnalisables
  • 35 |
36 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/281.txt: -------------------------------------------------------------------------------- 1 | Changes since 0.5.1 2 | 3 | 🚀 Features 4 | 5 | * Added option to select directory for ringtones (random ringtone will be selected from the directory each time) 6 | * Added multiselect for lists 7 | * Added option to shuffle alarm ringtone 8 | * Added backup and restore for alarms, timers, themes etc. 9 | * Added numpad input for timers 10 | * Added option to reduce volume while solving alarm tasks 11 | * Added quick home screen actions for alarms and timers 12 | * Added option to start ringtone at random position 13 | * Added background service to keep app alive 14 | * Added analog clock to clock tab 15 | * Added memory (card matching) task 16 | 17 | ✨ Enhancements 18 | 19 | * Made alarm tasks reorderable 20 | * Added better logging system 21 | * Added alarm labels to alarm notifications 22 | 23 | 🐛 Fixes 24 | 25 | * Fixed non-deletable items getting deleted by list actions 26 | * Fixed range weekly schedule not working 27 | * Fixed system navigation bar color 28 | * Fixed database for cities 29 | * Fixed skipped alarms being visible to the system 30 | * Fixed foreground notification foreground type 31 | * Fixed date picker being stuck in the past for range alarms 32 | * Fixed minutes not appearing when 0 33 | * Fixed sound still playing after dismissing alarm in some cases 34 | * Fixed data persisting even after uninstalling app (disabled auto backup) 35 | 36 | 37 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/282.txt: -------------------------------------------------------------------------------- 1 | Changes since 0.5.1 2 | 3 | 🚀 Features 4 | 5 | * Added option to select directory for ringtones (random ringtone will be selected from the directory each time) 6 | * Added multiselect for lists 7 | * Added option to shuffle alarm ringtone 8 | * Added backup and restore for alarms, timers, themes etc. 9 | * Added numpad input for timers 10 | * Added option to reduce volume while solving alarm tasks 11 | * Added quick home screen actions for alarms and timers 12 | * Added option to start ringtone at random position 13 | * Added background service to keep app alive 14 | * Added analog clock to clock tab 15 | * Added memory (card matching) task 16 | 17 | ✨ Enhancements 18 | 19 | * Made alarm tasks reorderable 20 | * Added better logging system 21 | * Added alarm labels to alarm notifications 22 | 23 | 🐛 Fixes 24 | 25 | * Fixed non-deletable items getting deleted by list actions 26 | * Fixed range weekly schedule not working 27 | * Fixed system navigation bar color 28 | * Fixed database for cities 29 | * Fixed skipped alarms being visible to the system 30 | * Fixed foreground notification foreground type 31 | * Fixed date picker being stuck in the past for range alarms 32 | * Fixed minutes not appearing when 0 33 | * Fixed sound still playing after dismissing alarm in some cases 34 | * Fixed data persisting even after uninstalling app (disabled auto backup) 35 | 36 | 37 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/283.txt: -------------------------------------------------------------------------------- 1 | Changes since 0.5.1 2 | 3 | 🚀 Features 4 | 5 | * Added option to select directory for ringtones (random ringtone will be selected from the directory each time) 6 | * Added multiselect for lists 7 | * Added option to shuffle alarm ringtone 8 | * Added backup and restore for alarms, timers, themes etc. 9 | * Added numpad input for timers 10 | * Added option to reduce volume while solving alarm tasks 11 | * Added quick home screen actions for alarms and timers 12 | * Added option to start ringtone at random position 13 | * Added background service to keep app alive 14 | * Added analog clock to clock tab 15 | * Added memory (card matching) task 16 | 17 | ✨ Enhancements 18 | 19 | * Made alarm tasks reorderable 20 | * Added better logging system 21 | * Added alarm labels to alarm notifications 22 | 23 | 🐛 Fixes 24 | 25 | * Fixed non-deletable items getting deleted by list actions 26 | * Fixed range weekly schedule not working 27 | * Fixed system navigation bar color 28 | * Fixed database for cities 29 | * Fixed skipped alarms being visible to the system 30 | * Fixed foreground notification foreground type 31 | * Fixed date picker being stuck in the past for range alarms 32 | * Fixed minutes not appearing when 0 33 | * Fixed sound still playing after dismissing alarm in some cases 34 | * Fixed data persisting even after uninstalling app (disabled auto backup) 35 | 36 | 37 | -------------------------------------------------------------------------------- /fastlane/metadata/android/es-ES/full_description.txt: -------------------------------------------------------------------------------- 1 |

Funciones

2 |
    3 |
  • Interfaz moderna y fácil de usar
  • 4 |
5 |

Alarmas

6 |
    7 |
  • Horarios personalizables (diarios, semanales, días específicos de la semana, fechas específicas, rango de fechas)
  • 8 |
  • Configura la melodía, el aumento del volumen y las vibraciones
  • 9 |
  • Configurar la duración de la repetición y las repeticiones máximas
  • 10 |
  • Tareas de alarma (problemas matemáticos, volver a escribir texto, secuencia, más por venir)
  • 11 |
  • Filtrar alarmas (todas, hoy, mañana, pospuestas, desactivadas, completadas)
  • 12 |
13 |

Reloj

14 |
    15 |
  • Pantalla de reloj personalizable
  • 16 |
  • Relojes mundiales con diferencia horaria relativa
  • 17 |
  • Buscar y añadir ciudades
  • 18 |
19 |

Temporizador

20 |
    21 |
  • Configura la melodía, el aumento del volumen y las vibraciones
  • 22 |
  • Ajustes preestablecidos del temporizador
  • 23 |
  • Temporizadores de filtro (todos, en ejecución, en pausa, detenidos)
  • 24 |
25 |

Cronómetro

26 |
    27 |
  • Historial de vueltas con tiempos de vuelta y tiempos transcurridos
  • 28 |
  • Comparaciones de vueltas
  • 29 |
Apariencia 31 |
    32 |
  • Temas Material You
  • 33 |
  • Temas de color altamente personalizables
  • 34 |
  • Temas de estilo altamente personalizables
  • 35 |
36 | -------------------------------------------------------------------------------- /fastlane/metadata/android/pl-PL/full_description.txt: -------------------------------------------------------------------------------- 1 |

Funkcje

2 |
    3 |
  • Nowoczesny i łatwy w użyciu interfejs
  • 4 |
5 |

Alarmy

6 |
    7 |
  • Konfigurowalne harmonogramy (dzienny, tygodniowy, na określone dni tygodnia, na określone daty, zakres dat)
  • 8 |
  • Konfiguracja melodii, rosnącej głośności i wibracji
  • 9 |
  • Konfiguracja długości drzemki i maksymalnej liczby drzemek
  • 10 |
  • Zadania pobudkowe (działania matematyczne, przepisywanie tekstu, sekwencja, kolejne w przyszłości)
  • 11 |
  • Filtrowanie alarmów (wszystkie, dzisiejsze, jutrzejsze, odłożone, wyłączone, zakończone)
  • 12 |
13 |

Zegar

14 |
    15 |
  • Konfigurowalny wyświetlanie zegara
  • 16 |
  • Zegary światowe ze względną różnicą czasu
  • 17 |
  • Wyszukiwanie i dodawanie miast
  • 18 |
19 |

Czasomierz

20 |
    21 |
  • Konfiguracja melodii, rosnącej głośności i wibracji
  • 22 |
  • Wstępne ustawienia czasomierza
  • 23 |
  • Filtrowanie ustawionych minutników (wszystkie, uruchomione, wstrzymane, zatrzymane)
  • 24 |
25 |

Stoper

26 |
    27 |
  • Historia okrążeń z czasami okrążeń i czasami, które łącznie upłynęły przy danych okrążeniach
  • 28 |
  • Porównania okrążeń
  • 29 |
Wygląd 31 |
    32 |
  • Motywy Material You
  • 33 |
  • Wysoce konfigurowalne motywy kolorystyczne
  • 34 |
  • Wysoce konfigurowalne motywy stylów
  • 35 |
36 | -------------------------------------------------------------------------------- /lib/common/widgets/fields/select_field/field_cards/audio_field_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:clock_app/common/types/file_item.dart'; 2 | import 'package:clock_app/common/types/select_choice.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class AudioFieldCard extends StatelessWidget { 6 | const AudioFieldCard({super.key, required this.title, required this.choice}); 7 | 8 | final String title; 9 | final SelectChoice choice; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Row( 14 | children: [ 15 | Expanded( 16 | flex: 999, 17 | child: Column( 18 | crossAxisAlignment: CrossAxisAlignment.start, 19 | children: [ 20 | Text( 21 | title, 22 | style: Theme.of(context).textTheme.headlineMedium, 23 | ), 24 | const SizedBox(height: 4.0), 25 | Text( 26 | choice.value.name, 27 | style: Theme.of(context).textTheme.bodyMedium, 28 | maxLines: 1, 29 | overflow: TextOverflow.ellipsis, 30 | softWrap: false, 31 | ), 32 | ], 33 | ), 34 | ), 35 | Icon( 36 | Icons.keyboard_arrow_down_rounded, 37 | color: Theme.of(context).colorScheme.onBackground.withOpacity(0.6), 38 | ) 39 | ], 40 | ); 41 | } 42 | } 43 | --------------------------------------------------------------------------------