├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ │ ├── privacy_policy.html │ │ │ │ └── privacy_policy_en.html │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── iHTCboy │ │ │ │ │ └── iPomodoros │ │ │ │ │ ├── AppWebviewAvtivity.kt │ │ │ │ │ ├── DeviceUtils.kt │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ ├── app_icon.png │ │ │ │ ├── app_share_icon.png │ │ │ │ └── launch_background.xml │ │ │ │ ├── layout │ │ │ │ └── webview_layout.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── values-en-rUS │ │ │ │ └── strings.xml │ │ │ │ ├── values-en │ │ │ │ └── strings.xml │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ ├── values-zh-rHK │ │ │ │ └── strings.xml │ │ │ │ ├── values-zh-rTW │ │ │ │ └── strings.xml │ │ │ │ ├── values-zh │ │ │ │ └── strings.xml │ │ │ │ └── values │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ ├── fonts │ │ ├── ChakraPetch-Bold.ttf │ │ ├── ChakraPetch-Light.ttf │ │ ├── ChakraPetch-Regular.ttf │ │ ├── ChakraPetch-SemiBold.ttf │ │ ├── MaShanZheng-Regular.ttf │ │ └── NotoSansTC-Bold.otf │ ├── images │ │ └── app_logo.png │ └── musics │ │ ├── Afternoon.mp3 │ │ ├── Birds.mp3 │ │ ├── Campfire.mp3 │ │ ├── Cowbell.mp3 │ │ ├── Happiness.mp3 │ │ ├── Morning.mp3 │ │ ├── Ring.mp3 │ │ ├── RiverStream.mp3 │ │ ├── SeaWaves.mp3 │ │ ├── SummerNight.mp3 │ │ ├── Thunderstorm.mp3 │ │ ├── Ticking.mp3 │ │ ├── Vintage.mp3 │ │ └── WhiteNoise.mp3 ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── flutter_export_environment.sh │ ├── Podfile │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon-1024.jpg │ │ │ ├── icon-120.png │ │ │ ├── icon-152.png │ │ │ ├── icon-167.png │ │ │ ├── icon-180.png │ │ │ ├── icon-40.png │ │ │ ├── icon-58.png │ │ │ ├── icon-60.png │ │ │ ├── icon-76.png │ │ │ ├── icon-80.png │ │ │ └── icon-87.png │ │ ├── Contents.json │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── FlutterNativePlugin.swift │ │ ├── Info.plist │ │ ├── Resource │ │ ├── Images │ │ │ └── App-share-Icon.png │ │ └── files │ │ │ └── iHTCboyApp.json │ │ ├── Runner-Bridging-Header.h │ │ ├── en.lproj │ │ ├── InfoPlist.strings │ │ └── Main.strings │ │ ├── iPomodoro │ │ ├── CommonDefine.swift │ │ ├── IAppleServiceUtil.swift │ │ ├── ITAdvancelDetailViewController.swift │ │ ├── ITCommonAPI.swift │ │ ├── TableHeaderView.swift │ │ └── TableHeaderView.xib │ │ ├── zh-Hans.lproj │ │ ├── InfoPlist.strings │ │ ├── LaunchScreen.strings │ │ └── Main.strings │ │ └── zh-Hant.lproj │ │ ├── InfoPlist.strings │ │ ├── LaunchScreen.strings │ │ └── Main.strings ├── lib │ ├── common │ │ ├── channel │ │ │ └── native_method_channel.dart │ │ ├── constant │ │ │ └── app_colors.dart │ │ └── utils │ │ │ ├── audio_utils.dart │ │ │ ├── config_storage.dart │ │ │ ├── database_utils.dart │ │ │ ├── device_utils.dart │ │ │ ├── notification_utils.dart │ │ │ └── time_utils.dart │ ├── config │ │ └── app_config.dart │ ├── generated │ │ ├── intl │ │ │ ├── messages_all.dart │ │ │ ├── messages_en.dart │ │ │ └── messages_zh.dart │ │ └── l10n.dart │ ├── l10n │ │ ├── intl_en.arb │ │ └── intl_zh.arb │ ├── main.dart │ ├── model │ │ └── countdown_model.dart │ └── ui │ │ ├── page │ │ ├── app_about_page.dart │ │ ├── brightness_settings.dart │ │ ├── countdown_page.dart │ │ ├── countdown_settings.dart │ │ ├── language_settings.dart │ │ ├── me_page.dart │ │ ├── pomodoro_page.dart │ │ ├── pomodoro_settings.dart │ │ ├── theme_style.dart │ │ ├── timer_page.dart │ │ └── timer_settings.dart │ │ └── widget │ │ ├── countdown_edit_picker.dart │ │ ├── cupertino_alert.dart │ │ ├── custom_picker.dart │ │ ├── privacy_policy_dialog.dart │ │ ├── time_dialog.dart │ │ └── tips_dialog.dart ├── linux │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ │ ├── CMakeLists.txt │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ └── generated_plugins.cmake │ ├── main.cc │ ├── my_application.cc │ └── my_application.h ├── macos │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Podfile │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_512.png │ │ │ └── app_icon_64.png │ │ ├── Base.lproj │ │ └── MainMenu.xib │ │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ │ ├── DebugProfile.entitlements │ │ ├── Info.plist │ │ ├── MainFlutterWindow.swift │ │ └── Release.entitlements ├── pubspec.yaml ├── test │ └── widget_test.dart ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ ├── Icon-512.png │ │ ├── Icon-maskable-192.png │ │ └── Icon-maskable-512.png │ ├── index.html │ └── manifest.json └── windows │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake │ └── runner │ ├── CMakeLists.txt │ ├── Runner.rc │ ├── flutter_window.cpp │ ├── flutter_window.h │ ├── main.cpp │ ├── resource.h │ ├── resources │ └── app_icon.ico │ ├── runner.exe.manifest │ ├── utils.cpp │ ├── utils.h │ ├── win32_window.cpp │ └── win32_window.h ├── gen └── GradleException.groovy ├── logo.png └── screenshot ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.png ├── 06.png └── 07.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.lock 4 | *.log 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Visual Studio Code related 20 | .vscode/ 21 | 22 | # Flutter/Dart/Pub related 23 | **/doc/api/ 24 | .dart_tool/ 25 | .flutter-plugins 26 | .packages 27 | .pub-cache/ 28 | .pub/ 29 | build/ 30 | 31 | # Android related 32 | **/android/**/gradle-wrapper.jar 33 | **/android/.gradle 34 | **/android/captures/ 35 | **/android/gradlew 36 | **/android/gradlew.bat 37 | **/android/local.properties 38 | **/android/**/GeneratedPluginRegistrant.java 39 | 40 | # iOS/XCode related 41 | **/ios/**/*.mode1v3 42 | **/ios/**/*.mode2v3 43 | **/ios/**/*.moved-aside 44 | **/ios/**/*.pbxuser 45 | **/ios/**/*.perspectivev3 46 | **/ios/**/*sync/ 47 | **/ios/**/.sconsign.dblite 48 | **/ios/**/.tags* 49 | **/ios/**/.vagrant/ 50 | **/ios/**/DerivedData/ 51 | **/ios/**/Icon? 52 | **/ios/**/Pods/ 53 | **/ios/**/.symlinks/ 54 | **/ios/**/profile 55 | **/ios/**/xcuserdata 56 | **/ios/.generated/ 57 | **/ios/Flutter/App.framework 58 | **/ios/Flutter/Flutter.framework 59 | **/ios/Flutter/Generated.xcconfig 60 | **/ios/Flutter/app.flx 61 | **/ios/Flutter/app.zip 62 | **/ios/Flutter/flutter_assets/ 63 | **/ios/ServiceDefinitions.json 64 | **/ios/Runner/GeneratedPluginRegistrant.* 65 | 66 | # Exceptions to above rules. 67 | !**/ios/**/default.mode1v3 68 | !**/ios/**/default.mode2v3 69 | !**/ios/**/default.pbxuser 70 | !**/ios/**/default.perspectivev3 71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 72 | 73 | 74 | 75 | # See https://www.dartlang.org/guides/libraries/private-files 76 | 77 | # Files and directories created by pub 78 | .dart_tool/ 79 | .packages 80 | .pub/ 81 | build/ 82 | # If you're building an application, you may want to check-in your pubspec.lock 83 | pubspec.lock 84 | 85 | # Directory created by dartdoc 86 | # If you don't generate documentation locally you can remove this line. 87 | doc/api/ 88 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # 用户隐私政策 2 | 3 | 注:以下《隐私政策》协议为:个人开发者 iHTCboy,下文用“我们”代称。 4 | 5 | 您在使用我们的服务时,我们可能会收集和使用您的相关信息。 6 | 我们希望通过本《隐私政策》向您说明,在使用我们的服务时,我们如何收集、使用、储存和分享这些信息,以及我们为您提供的访问、更新、控制和保护这些信息的方式。 7 | 本《隐私政策》与您所使用的服务息息相关,希望您仔细阅读,在需要时,按照本《隐私政策》的指引,作出您认为适当的选择。 8 | 本《隐私政策》中涉及的相关技术词汇,我们尽量以简明扼要的表述,并提供进一步说明的链接,以便您的理解。 9 | 您使用或继续使用我们的服务,即意味着同意我们按照本《隐私政策》收集、使用、储存和分享您的相关信息。 如对本《隐私政策》或相关事宜有任何问题,请通过 iHTCdevelop@gmail.com 与我们联系。 10 | 11 | ### 我们可能收集的信息 12 | 13 | 我们提供服务时,可能会收集、储存和使用下列与您有关的信息。如果您不提供相关信息,可能无法享受我们提供的某些服务,或者无法达到相关服务拟达到的效果。 14 | 15 | ### 您提供的信息 16 | 17 | 您在使用我们的服务时,向我们提供的相关个人信息,例如电子邮件或评论内容等; 18 | 您通过我们的服务向其他方提供的分享,以及您使用我们的服务时所储存的信息。 19 | 20 | ### 其他方分享的您的信息 21 | 22 | 其他方使用我们的服务时所提供有关您的共享信息。 23 | 24 | ### 我们获取的您的信息 25 | 26 | 您使用服务时我们可能收集如下信息: 27 | 日志信息,指您使用我们的服务时,系统可能通过cookies或其他方式自动采集的技术信息,包括: 28 | 设备或软件信息,例如您的移动设备、网页浏览器或用于接入我们服务的其他程序所提供的配置信息、您的IP地址和移动设备所用的版本和设备识别码; 29 | 修改系统的权限在使用我们服务时,例如您需要调节应用内的屏幕亮度时,需要访问提供修改系统的权限; 30 | 推送的权限,只会用于番茄计时时,应用进入后台时,进行本地推送提示功能。 31 | 32 | ### 我们可能如何使用信息 33 | 34 | 我们可能将在向您提供服务的过程之中所收集的信息用作下列用途: 35 | 1、向您提供服务; 36 | 2、帮助我们设计新服务,改善我们现有服务; 37 | 3、让您参与有关我们产品和服务的调查。 38 | 4、在我们提供服务时,用于身份验证、客户服务、安全防范、诈骗监测、存档和备份用途,确保我们向您提供的产品和服务的安全性; 39 | 40 | 为了让您有更好的体验、改善我们的服务或您同意的其他用途,在符合相关法律法规的前提下,我们可能将通过某一项服务所收集的信息,以汇集信息或者个性化的方式,用于我们的其他服务。例如,在您使用我们的一项服务时所收集的信息,可能在另一服务中用于向您提供特定内容,或向您展示与您相关的、非普遍推送的信息。如果我们在相关服务中提供了相应选项,您也可以授权我们将该服务所提供和储存的信息用于我们的其他服务。 41 | 我们将尽一切可能采取适当的技术手段,保证您可以访问、更新和更正自己的注册信息或使用我们的服务时提供的其他个人信息。 42 | 43 | ### 信息安全 44 | 45 | 我们仅在本《隐私政策》所述目的所必需的期间和法律法规要求的时限内保留您的个人信息。 我们使用各种安全技术和程序,以防信息的丢失、不当使用、未经授权阅览或披露。例如,在某些服务中,我们将利用加密技术(例如SSL)来保护您提供的个人信息。但请您理解,由于技术的限制以及可能存在的各种恶意手段,在互联网行业,即便竭尽所能加强安全措施,也不可能始终保证信息百分之百的安全。您需要了解,您接入我们的服务所用的系统和通讯网络,有可能因我们可控范围外的因素而出现问题。 46 | 47 | ### 您分享的信息 48 | 49 | 我们的多项服务,可让您不仅与自己的社交网络,也与使用该服务的所有用户公开分享您的相关信息,例如,您在我们的服务中所上传或发布的信息(包括您公开的个人信息、您建立的任务)、您对其他人上传或发布的信息作出的回应,以及包括与这些信息有关的位置数据和日志信息。使用我们服务的其他用户也有可能分享与您有关的信息(包括位置数据和日志信息)。特别是,我们的社交媒体服务,是专为使您与世界各地的用户共享信息而设计,您可以使共享信息实时、广泛地传递。只要您不删除共享信息,有关信息会一直留存在公共领域;即使您删除共享信息,有关信息仍可能由其他用户或不受我们控制的非关联第三方独立地缓存、复制或储存,或由其他用户或该等第三方在公共领域保存。 50 | 因此,请您谨慎考虑通过我们的服务分享、发布和交流的信息内容。在一些情况下,您可通过我们某些服务的隐私设定来控制有权浏览您共享信息的用户范围。 51 | 52 | ### 隐私政策的适用例外 53 | 54 | 我们的服务可能包括或链接至第三方提供的社交媒体或其他服务(包括网站)。例如: 55 | 您利用 “分享”键将某些内容分享的服务,或您利用第三方连线服务登录我们的服务。这些功能可能会收集您的相关信息(包括您的日志信息),并可能在您的电脑装置cookies,从而正常运行上述功能; 56 | 我们通过广告或我们服务的其他方式向您提供链接,使您可以接入第三方的服务或网站。 57 | 该等第三方社交媒体或其他服务可能由相关的第三方或我们运营。您使用该等第三方的社交媒体服务或其他服务(包括您向该等第三方提供的任何个人信息),须受该第三方的服务条款及隐私政策(而非《通用服务条款》或本《隐私政策》)约束,您需要仔细阅读其条款。本《隐私政策》仅适用于我们所收集的信息,并不适用于任何第三方提供的服务或第三方的信息使用规则,我们对任何第三方使用由您提供的信息不承担任何责任。 58 | 59 | ### 未成年人使用我们的服务 60 | 61 | 我们鼓励父母或监护人指导未满十八岁的未成年人使用我们的服务。我们建议未成年人鼓励他们的父母或监护人阅读本《隐私政策》,并建议未成年人在提交的个人信息之前寻求父母或监护人的同意和指导。 62 | 63 | ### 隐私政策的适用范围 64 | 65 | 除某些特定服务外,我们所有的服务均适用本《隐私政策》。这些特定服务将适用特定的隐私政策。针对某些特定服务的特定隐私政策,将更具体地说明我们在该等服务中如何使用您的信息。该特定服务的隐私政策构成本《隐私政策》的一部分。如相关特定服务的隐私政策与本《隐私政策》有不一致之处,适用该特定服务的隐私政策。 66 | 请您注意,本《隐私政策》不适用于以下情况: 67 | 通过我们的服务而接入的第三方服务(包括任何第三方网站)收集的信息; 68 | 通过在我们服务中进行广告服务的其他公司或机构所收集的信息。 69 | 70 | ### 变更 71 | 我们可能适时修订本《隐私政策》的条款,该等修订构成本《隐私政策》的一部分。如该等修订造成您在本《隐私政策》下权利的实质减少,我们将在修订生效前通过在主页上显著位置提示或向您发送电子邮件或以其他方式通知您。在该种情况下,若您继续使用我们的服务,即表示同意受经修订的本《隐私政策》的约束。 72 | 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iPomodoro-Flutter 2 | 3 | logo.png 4 | 5 | iPomodoro(爱番茄)。🍅 番茄工作法是一种时间管理法方法,在上世纪八十年代由Francesco Cirillo创立。 该方法使用一个定时器来分割出一个一般为25分钟的工作时间和5分钟的休息时间,而那些时间段被称为pomodori,为意大利语单词pomodoro之复数。 6 | 7 | 8 | ## iPomodoro(爱番茄🍅) 9 | 爱番茄是一个简单和有效的番茄工作法的应用,灵感来自 iOS app `我要当学霸` 和 macOS app `Promodoro Timer`,这2个App已经下架多年了,所以,想以此为基础,开发Android/iOS/macOS版本,并且开源,所有平台暂定免费下载,计划内置打赏机制,iOS/macOS版本不定时收费1人民币(苹果开发账号费)。 10 | 11 | 12 | ## 简介 13 | 14 | - 分心?❌ 15 | - 拖延?❌ 16 | - 高效?✅ 17 | - 专注?✅ 18 | 19 | iPomodoro(爱番茄) 20 | 21 | 【功能简介】 22 | 番茄时间管理和学习规划,妈妈再也不用担心我的学习啦!不再分心!不再拖延!高效!专注!,让大家在学习时可以更加专注也可以快速和简单的学习get! 23 | 24 | 【三大特点】 25 | 1、番茄学习模式,使用番茄工作法学习,让你劳逸结合! 26 | 2、计时学习模式,按照设定的时长学习,想学多久就学多久! 27 | 3、定时任务模式,倒数日、任务记录,每日学习任务! 28 | 29 | 杜绝学习没有目标!满足你对学习的求知欲望! 30 | 31 | 32 | **番茄学习** 33 | - 使用番茄工作法学习 34 | 35 | **计时学习** 36 | - 按照设定的时长学习 37 | 38 | 请不要 39 | 放弃治疗! 40 | 好好学习 41 | 你还有救! 42 | 43 | 44 | ### 下载&安装 45 | 46 | 1、商店安装 47 | 48 | | 已上架的商店 | 下载地址 | 备注 | 49 | |--------|---|---| 50 | | 苹果商店 | [https://apps.apple.com/cn/app/ipomodoro/id1439666929](https://apps.apple.com/cn/app/ipomodoro/id1439666929) | 可供下载 | 51 | | 谷歌商店 | [https://play.google.com/store/apps/details?id=com.iHTCboy.iPomodoros](https://play.google.com/store/apps/details?id=com.iHTCboy.iPomodoros) | 可供下载 | 52 | | ~~华为商店~~ | [https://appgallery.huawei.com/#/app/C103911977](https://appgallery.huawei.com/#/app/C103911977) | 不合规被下架 | 53 | | ~~小米商店~~ | [http://app.xiaomi.com/detail/1341005](http://app.xiaomi.com/detail/1341005) | 不合规被下架 | 54 | | ~~酷安商店~~ | [https://www.coolapk.com/apk/282769](https://www.coolapk.com/apk/282769) | 不合规被下架 | 55 | | APK下载 | [https://github.com/iHTCboy/iPomodoro-Flutter/releases](https://github.com/iHTCboy/iPomodoro-Flutter/releases) | 可供下载 | 56 | 57 | > 注:因为苹果开发者账号需要 ¥688 年费,所以 App Store下载收费1元。介意的朋友可以下载本项目代码在 macOS 系统编译安装。 58 | 59 | 60 | 2、编译安装 61 | iOS app 因为苹果开发者账号需要 ¥688 年费,所以 AppStore 为付费下载,请见谅。你可以下载本项目代码在macOS系统编译安装。 62 | 63 | 64 | ### 应用截图 65 | 66 | | ![](screenshot/01.png) | ![](screenshot/02.png) | 67 | | ----- | ----- | 68 | | ![](screenshot/03.png) | ![](screenshot/04.png) | 69 | | ![](screenshot/05.png) | ![](screenshot/06.png) | 70 | | ![](screenshot/07.png) | | 71 | 72 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | -------------------------------------------------------------------------------- /app/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: 135454af32477f815a7525073027a3ff9eff1bfd 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 135454af32477f815a7525073027a3ff9eff1bfd 17 | base_revision: 135454af32477f815a7525073027a3ff9eff1bfd 18 | - platform: android 19 | create_revision: 135454af32477f815a7525073027a3ff9eff1bfd 20 | base_revision: 135454af32477f815a7525073027a3ff9eff1bfd 21 | - platform: ios 22 | create_revision: 135454af32477f815a7525073027a3ff9eff1bfd 23 | base_revision: 135454af32477f815a7525073027a3ff9eff1bfd 24 | - platform: linux 25 | create_revision: 135454af32477f815a7525073027a3ff9eff1bfd 26 | base_revision: 135454af32477f815a7525073027a3ff9eff1bfd 27 | - platform: macos 28 | create_revision: 135454af32477f815a7525073027a3ff9eff1bfd 29 | base_revision: 135454af32477f815a7525073027a3ff9eff1bfd 30 | - platform: web 31 | create_revision: 135454af32477f815a7525073027a3ff9eff1bfd 32 | base_revision: 135454af32477f815a7525073027a3ff9eff1bfd 33 | - platform: windows 34 | create_revision: 135454af32477f815a7525073027a3ff9eff1bfd 35 | base_revision: 135454af32477f815a7525073027a3ff9eff1bfd 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # iPomodoro 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /app/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | def localProperties = new Properties() 9 | def localPropertiesFile = rootProject.file('local.properties') 10 | if (localPropertiesFile.exists()) { 11 | localPropertiesFile.withReader('UTF-8') { reader -> 12 | localProperties.load(reader) 13 | } 14 | } 15 | 16 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 17 | if (flutterVersionCode == null) { 18 | flutterVersionCode = '1' 19 | } 20 | 21 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 22 | if (flutterVersionName == null) { 23 | flutterVersionName = '1.0' 24 | } 25 | 26 | def keystoreProperties = new Properties() 27 | def keystorePropertiesFile = rootProject.file('key.properties') 28 | if (keystorePropertiesFile.exists()) { 29 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 30 | } 31 | 32 | 33 | android { 34 | namespace = "com.iHTCboy.iPomodoros" 35 | compileSdkVersion 35 36 | 37 | sourceSets { 38 | main.java.srcDirs += 'src/main/kotlin' 39 | } 40 | 41 | lintOptions { 42 | disable 'InvalidPackage' 43 | } 44 | 45 | defaultConfig { 46 | applicationId "com.iHTCboy.iPomodoros" 47 | minSdkVersion 21 48 | targetSdkVersion 35 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | // Required when setting minSdkVersion to 20 or lower 52 | multiDexEnabled true 53 | } 54 | 55 | compileOptions { 56 | // Add these 3 lines inside [compileOptions] 57 | coreLibraryDesugaringEnabled true 58 | sourceCompatibility = JavaVersion.VERSION_21 59 | targetCompatibility = JavaVersion.VERSION_21 60 | } 61 | 62 | signingConfigs { 63 | release { 64 | keyAlias keystoreProperties['keyAlias'] 65 | keyPassword keystoreProperties['keyPassword'] 66 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null 67 | storePassword keystoreProperties['storePassword'] 68 | } 69 | } 70 | 71 | buildTypes { 72 | release { 73 | signingConfig signingConfigs.release 74 | ndk { 75 | //设置支持的SO库架构 76 | abiFilters 'arm64-v8a' 77 | //debugSymbolLevel 'SYMBOL_TABLE' 78 | } 79 | } 80 | debug { 81 | signingConfig signingConfigs.debug 82 | ndk { 83 | //设置支持的SO库架构 84 | abiFilters 'arm64-v8a', 'x86', 'x86_64' 85 | } 86 | } 87 | } 88 | } 89 | 90 | flutter { 91 | source '../..' 92 | } 93 | 94 | dependencies { 95 | coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' 96 | implementation 'androidx.appcompat:appcompat:1.7.0' 97 | implementation "me.leolin:ShortcutBadger:1.1.22@aar" 98 | } 99 | -------------------------------------------------------------------------------- /app/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | ## Flutter wrapper 2 | -keep class io.flutter.app.** { *; } 3 | -keep class io.flutter.plugin.** { *; } 4 | -keep class io.flutter.util.** { *; } 5 | -keep class io.flutter.view.** { *; } 6 | -keep class io.flutter.** { *; } 7 | -keep class io.flutter.plugins.** { *; } 8 | -dontwarn io.flutter.embedding.** 9 | # Please add these rules to your existing keep rules in order to suppress warnings. 10 | # This is generated automatically by the Android Gradle plugin. 11 | -dontwarn com.google.android.play.core.splitcompat.SplitCompatApplication -------------------------------------------------------------------------------- /app/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 34 | 37 | 38 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/android/app/src/main/assets/privacy_policy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 用户隐私政策 6 | 7 | 8 |

用户隐私政策

9 |

注:以下《隐私政策》协议为:个人开发者 iHTCboy,下文用“我们”代称。

10 |

您在使用我们的服务时,我们可能会收集和使用您的相关信息。 11 |
我们希望通过本《隐私政策》向您说明,在使用我们的服务时,我们如何收集、使用、储存和分享这些信息,以及我们为您提供的访问、更新、控制和保护这些信息的方式。 12 |
本《隐私政策》与您所使用的服务息息相关,希望您仔细阅读,在需要时,按照本《隐私政策》的指引,作出您认为适当的选择。 13 |
本《隐私政策》中涉及的相关技术词汇,我们尽量以简明扼要的表述,并提供进一步说明的链接,以便您的理解。 14 |
您使用或继续使用我们的服务,即意味着同意我们按照本《隐私政策》收集、使用、储存和分享您的相关信息。 15 | 如对本《隐私政策》或相关事宜有任何问题,请通过 iHTCdevelop@gmail.com 与我们联系。

16 | 17 |

我们可能收集的信息

18 |

我们提供服务时,可能会收集、储存和使用下列与您有关的信息。如果您不提供相关信息,可能无法享受我们提供的某些服务,或者无法达到相关服务拟达到的效果。 19 |

20 |

您提供的信息

21 | 22 |

您在使用我们的服务时,向我们提供的相关个人信息,例如电子邮件或评论内容等; 23 |
您通过我们的服务向其他方提供的分享,以及您使用我们的服务时所储存的信息。 24 |

25 | 26 |

其他方分享的您的信息

27 | 28 |

其他方使用我们的服务时所提供有关您的共享信息。 29 |

30 | 31 |

我们获取的您的信息

32 |

您使用服务时我们可能收集如下信息: 33 |
日志信息,指您使用我们的服务时,系统可能通过cookies或其他方式自动采集的技术信息,包括: 34 |
设备或软件信息,例如您的移动设备、网页浏览器或用于接入我们服务的其他程序所提供的配置信息、您的IP地址和移动设备所用的版本和设备识别码; 35 |
修改系统的权限在使用我们服务时,例如您需要调节应用内的屏幕亮度时,需要访问提供修改系统的权限; 36 |
推送的权限,只会用于番茄计时时,应用进入后台时,进行本地推送提示功能。 37 |

38 | 39 |

我们可能如何使用信息

40 | 41 |

我们可能将在向您提供服务的过程之中所收集的信息用作下列用途: 42 |
1、向您提供服务; 43 |
2、帮助我们设计新服务,改善我们现有服务; 44 |
3、让您参与有关我们产品和服务的调查。 45 |
4、在我们提供服务时,用于身份验证、客户服务、安全防范、诈骗监测、存档和备份用途,确保我们向您提供的产品和服务的安全性; 46 |

47 |

48 | 为了让您有更好的体验、改善我们的服务或您同意的其他用途,在符合相关法律法规的前提下,我们将尽一切可能采取适当的技术手段,保证您可以访问、更新和更正自己的注册信息或使用我们的服务时提供的其他个人信息。 49 |

50 | 51 |

信息安全

52 |

我们仅在本《隐私政策》所述目的所必需的期间和法律法规要求的时限内保留您的个人信息。 53 | 我们使用各种安全技术和程序,以防信息的丢失、不当使用、未经授权阅览或披露。例如,在某些服务中,我们将利用加密技术(例如SSL)来保护您提供的个人信息。但请您理解,由于技术的限制以及可能存在的各种恶意手段,在互联网行业,即便竭尽所能加强安全措施,也不可能始终保证信息百分之百的安全。您需要了解,您接入我们的服务所用的系统和通讯网络,有可能因我们可控范围外的因素而出现问题。 54 |

55 | 56 |

您分享的信息

57 | 58 |

59 | 我们的多项服务,可让您不仅与自己的社交网络,也与使用该服务的所有用户公开分享您的相关信息,例如,您在我们的服务中所上传或发布的信息(包括您公开的个人信息、您建立的任务)、您对其他人上传或发布的信息作出的回应,以及包括与这些信息有关的位置数据和日志信息。使用我们服务的其他用户也有可能分享与您有关的信息(包括位置数据和日志信息)。特别是,我们的社交媒体服务,是专为使您与世界各地的用户共享信息而设计,您可以使共享信息实时、广泛地传递。只要您不删除共享信息,有关信息会一直留存在公共领域;即使您删除共享信息,有关信息仍可能由其他用户或不受我们控制的非关联第三方独立地缓存、复制或储存,或由其他用户或该等第三方在公共领域保存。 60 |
因此,请您谨慎考虑通过我们的服务分享、发布和交流的信息内容。在一些情况下,您可通过我们某些服务的隐私设定来控制有权浏览您共享信息的用户范围。 61 |

62 | 63 |

隐私政策的适用例外

64 | 65 |

我们的服务可能包括或链接至第三方提供的社交媒体或其他服务(包括网站)。例如: 66 |
您利用 67 | “分享”键将某些内容分享的服务,或您利用第三方连线服务登录我们的服务。这些功能可能会收集您的相关信息(包括您的日志信息),并可能在您的电脑装置cookies,从而正常运行上述功能; 68 |
我们通过广告或我们服务的其他方式向您提供链接,使您可以接入第三方的服务或网站。 69 |
该等第三方社交媒体或其他服务可能由相关的第三方或我们运营。您使用该等第三方的社交媒体服务或其他服务(包括您向该等第三方提供的任何个人信息),须受该第三方的服务条款及隐私政策(而非《通用服务条款》或本《隐私政策》)约束,您需要仔细阅读其条款。本《隐私政策》仅适用于我们所收集的信息,并不适用于任何第三方提供的服务或第三方的信息使用规则,我们对任何第三方使用由您提供的信息不承担任何责任。 70 |

71 | 72 |

未成年人使用我们的服务

73 | 74 |

我们鼓励父母或监护人指导未满十八岁的未成年人使用我们的服务。我们建议未成年人鼓励他们的父母或监护人阅读本《隐私政策》,并建议未成年人在提交的个人信息之前寻求父母或监护人的同意和指导。 75 |

76 | 77 |

隐私政策的适用范围

78 | 79 |

80 | 除某些特定服务外,我们所有的服务均适用本《隐私政策》。这些特定服务将适用特定的隐私政策。针对某些特定服务的特定隐私政策,将更具体地说明我们在该等服务中如何使用您的信息。该特定服务的隐私政策构成本《隐私政策》的一部分。如相关特定服务的隐私政策与本《隐私政策》有不一致之处,适用该特定服务的隐私政策。 81 |
请您注意,本《隐私政策》不适用于以下情况: 82 |
通过我们的服务而接入的第三方服务(包括任何第三方网站)收集的信息; 83 |
通过在我们服务中进行广告服务的其他公司或机构所收集的信息。 84 |

85 |

变更

86 | 87 |

88 | 我们可能适时修订本《隐私政策》的条款,该等修订构成本《隐私政策》的一部分。如该等修订造成您在本《隐私政策》下权利的实质减少,我们将在修订生效前通过在主页上显著位置提示或向您发送电子邮件或以其他方式通知您。在该种情况下,若您继续使用我们的服务,即表示同意受经修订的本《隐私政策》的约束。 89 |

90 | 91 | -------------------------------------------------------------------------------- /app/android/app/src/main/kotlin/com/iHTCboy/iPomodoros/AppWebviewAvtivity.kt: -------------------------------------------------------------------------------- 1 | package com.iHTCboy.iPomodoros 2 | 3 | import android.os.Build 4 | import android.os.Bundle 5 | import android.view.WindowManager 6 | import android.webkit.WebView 7 | import androidx.appcompat.app.AppCompatActivity 8 | import androidx.core.content.ContextCompat 9 | 10 | class AppWebviewAvtivity : AppCompatActivity() { 11 | //定义变量 12 | private var myWebView: WebView? = null 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | val intent = this.getIntent() 17 | val fileUrl = intent.getStringExtra("fileUrl") as kotlin.String 18 | setContentView(R.layout.webview_layout) 19 | myWebView = findViewById(R.id.webView) as WebView 20 | // 设置与Js交互的权限 21 | // myWebView!!.settings.javaScriptEnabled = true 22 | // //文本编码 23 | // myWebView!!.settings.defaultTextEncodingName = "utf-8" 24 | // //设置DOM存储已启用(注释后文本显示变成js代码) 25 | // myWebView!!.settings.domStorageEnabled = true 26 | // 设置允许JS弹窗 27 | //myWebView.settings.javaScriptCanOpenWindowsAutomatically = true 28 | // 先载入JS代码 29 | // 格式规定为:file:///android_asset/文件名.html 30 | myWebView!!.loadUrl(fileUrl) 31 | // mWebView!!.loadData(resources.getString(R.string.privacy_policy), "text/html", "base64") 32 | } 33 | 34 | // private fun setupStatusBar() { 35 | // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 36 | // //需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色 37 | // window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) 38 | // window.statusBarColor = ContextCompat.getColor(this, R.color.colorPrimaryDark) 39 | // } 40 | // } 41 | } -------------------------------------------------------------------------------- /app/android/app/src/main/kotlin/com/iHTCboy/iPomodoros/DeviceUtils.kt: -------------------------------------------------------------------------------- 1 | package com.iHTCboy.iPomodoros 2 | import android.os.Build 3 | import java.lang.reflect.Method 4 | 5 | object DeviceUtils { 6 | //emuiApiLevel>0 即华为系统 7 | //判断是否是华为系统 官网提供 8 | val isEMUI: Boolean 9 | get() { 10 | //emuiApiLevel>0 即华为系统 11 | var emuiApiLevel: Int = 0 12 | try { 13 | val cls = Class.forName("android.os.SystemProperties") 14 | val method: Method = cls.getDeclaredMethod("get", *arrayOf>(String::class.java)) 15 | emuiApiLevel = (method.invoke(cls, arrayOf("ro.build.hw_emui_api_level")) as String).toInt() 16 | } catch (e: Exception) { 17 | e.printStackTrace() 18 | } 19 | return emuiApiLevel > 0 20 | }//这个字符串可以自己定义,例如判断华为就填写huawei,魅族就填写meizu 21 | 22 | //判官是否是小米系统 官网提供 23 | val isMIUI: Boolean 24 | get() { 25 | val manufacturer: String = Build.MANUFACTURER 26 | //这个字符串可以自己定义,例如判断华为就填写huawei,魅族就填写meizu 27 | if ("xiaomi".equals(manufacturer, ignoreCase = true)) { 28 | return true 29 | } 30 | return false 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/drawable/app_icon.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable/app_share_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/drawable/app_share_icon.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/layout/webview_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/values-en-rUS/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | iPomodoro 4 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values-en/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | iPomodoro 4 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values-zh-rHK/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 愛蕃茄 4 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values-zh-rTW/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 愛蕃茄 4 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 爱番茄 4 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #DC5C5D 4 | #D74A49 5 | #4F97E0 6 | 7 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | iPomodoro 4 | 5 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 23 | 28 | 29 | -------------------------------------------------------------------------------- /app/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /app/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /app/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Feb 27 15:19:12 CST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip 7 | 8 | -------------------------------------------------------------------------------- /app/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "8.4.2" apply false 22 | id "org.jetbrains.kotlin.android" version "1.9.20" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /app/assets/fonts/ChakraPetch-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/fonts/ChakraPetch-Bold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/ChakraPetch-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/fonts/ChakraPetch-Light.ttf -------------------------------------------------------------------------------- /app/assets/fonts/ChakraPetch-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/fonts/ChakraPetch-Regular.ttf -------------------------------------------------------------------------------- /app/assets/fonts/ChakraPetch-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/fonts/ChakraPetch-SemiBold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/MaShanZheng-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/fonts/MaShanZheng-Regular.ttf -------------------------------------------------------------------------------- /app/assets/fonts/NotoSansTC-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/fonts/NotoSansTC-Bold.otf -------------------------------------------------------------------------------- /app/assets/images/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/images/app_logo.png -------------------------------------------------------------------------------- /app/assets/musics/Afternoon.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Afternoon.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Birds.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Birds.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Campfire.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Campfire.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Cowbell.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Cowbell.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Happiness.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Happiness.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Morning.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Morning.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Ring.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Ring.mp3 -------------------------------------------------------------------------------- /app/assets/musics/RiverStream.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/RiverStream.mp3 -------------------------------------------------------------------------------- /app/assets/musics/SeaWaves.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/SeaWaves.mp3 -------------------------------------------------------------------------------- /app/assets/musics/SummerNight.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/SummerNight.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Thunderstorm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Thunderstorm.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Ticking.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Ticking.mp3 -------------------------------------------------------------------------------- /app/assets/musics/Vintage.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/Vintage.mp3 -------------------------------------------------------------------------------- /app/assets/musics/WhiteNoise.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/assets/musics/WhiteNoise.mp3 -------------------------------------------------------------------------------- /app/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /app/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /app/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /app/ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/htc/Documents/Programing/Flutter/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/HTC/Documents/Programing/Flutter/iPomodoro-Flutter/app" 5 | export "COCOAPODS_PARALLEL_CODE_SIGN=true" 6 | export "FLUTTER_TARGET=lib/main.dart" 7 | export "FLUTTER_BUILD_DIR=build" 8 | export "FLUTTER_BUILD_NAME=4.0.0" 9 | export "FLUTTER_BUILD_NUMBER=240825" 10 | export "DART_OBFUSCATION=false" 11 | export "TRACK_WIDGET_CREATION=false" 12 | export "TREE_SHAKE_ICONS=true" 13 | export "PACKAGE_CONFIG=/Users/HTC/Documents/Programing/Flutter/iPomodoro-Flutter/app/.dart_tool/package_config.json" 14 | -------------------------------------------------------------------------------- /app/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /app/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | 11 | // flutter与原生桥接 12 | let controller = self.window.rootViewController as! FlutterViewController 13 | FlutterNativePlugin.shared.flutterController = controller 14 | FlutterNativePlugin.register(with: self.registrar(forPlugin: "FlutterNativePlugin")!) 15 | 16 | //push 17 | if #available(iOS 10.0, *) { 18 | UNUserNotificationCenter.current().delegate = self 19 | } 20 | 21 | // flutter插件通道代理 22 | GeneratedPluginRegistrant.register(with: self) 23 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 24 | } 25 | } 26 | 27 | // 28 | //FlutterViewController* controller = 29 | //(FlutterViewController*)self.window.rootViewController; 30 | //FlutterMethodChannel* channel = 31 | //[FlutterMethodChannel methodChannelWithName:@"io.baizi.flutter_open_native" 32 | // binaryMessenger:controller]; 33 | //[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { 34 | // if ([@"open_webview" isEqualToString:call.method]) { // 修改了方法名 35 | // UIViewController *vc = [[UIViewController alloc] init]; // 使用最简单的viewcontroller 36 | // vc.view.backgroundColor = [UIColor whiteColor]; // 不设置背景颜色,会出现空白,并且掉帧情 37 | // UINavigationController* navigationController = 38 | // [[UINavigationController alloc] initWithRootViewController:vc]; 39 | // navigationController.navigationBar.topItem.title = @"浏览器"; 40 | // [controller presentViewController:navigationController animated:YES completion:nil];// 增加动画,否则不容易看出来变化 41 | // } else { 42 | // result(FlutterMethodNotImplemented); 43 | // } 44 | //}]; 45 | -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "icon-40.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "icon-60.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon-58.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "icon-87.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon-80.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "icon-120.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon-120.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "icon-180.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "idiom" : "ipad", 53 | "size" : "20x20", 54 | "scale" : "1x" 55 | }, 56 | { 57 | "size" : "20x20", 58 | "idiom" : "ipad", 59 | "filename" : "icon-40.png", 60 | "scale" : "2x" 61 | }, 62 | { 63 | "idiom" : "ipad", 64 | "size" : "29x29", 65 | "scale" : "1x" 66 | }, 67 | { 68 | "size" : "29x29", 69 | "idiom" : "ipad", 70 | "filename" : "icon-58.png", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "40x40", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "size" : "40x40", 80 | "idiom" : "ipad", 81 | "filename" : "icon-80.png", 82 | "scale" : "2x" 83 | }, 84 | { 85 | "idiom" : "ipad", 86 | "size" : "76x76", 87 | "filename" : "icon-76.png", 88 | "scale" : "1x" 89 | }, 90 | { 91 | "size" : "76x76", 92 | "idiom" : "ipad", 93 | "filename" : "icon-152.png", 94 | "scale" : "2x" 95 | }, 96 | { 97 | "size" : "83.5x83.5", 98 | "idiom" : "ipad", 99 | "filename" : "icon-167.png", 100 | "scale" : "2x" 101 | }, 102 | { 103 | "size" : "1024x1024", 104 | "idiom" : "ios-marketing", 105 | "filename" : "icon-1024.jpg", 106 | "scale" : "1x" 107 | } 108 | ], 109 | "info" : { 110 | "version" : 1, 111 | "author" : "xcode" 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-1024.jpg -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-120.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-152.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-167.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-180.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-58.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-76.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-80.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-87.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "LaunchImage@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "LaunchImage@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /app/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | iPomodoro 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | iPomodoro 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(FLUTTER_BUILD_NUMBER) 27 | LSRequiresIPhoneOS 28 | 29 | UIApplicationSupportsIndirectInputEvents 30 | 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | UIMainStoryboardFile 34 | Main 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | UIInterfaceOrientationPortraitUpsideDown 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/ios/Runner/Resource/Images/App-share-Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/ios/Runner/Resource/Images/App-share-Icon.png -------------------------------------------------------------------------------- /app/ios/Runner/Resource/files/iHTCboyApp.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "issue_title": "Apps", 4 | "issue_subtitle": "开发者应用", 5 | "issue_list": [ 6 | { 7 | "title": "iCoder", 8 | "url": "https://itunes.apple.com/cn/app/iLeetCoder/id1458259471?l=zh&ls=1&mt=8", 9 | "author": "一款精心的算法题目学习App,迅速找到工作" 10 | }, 11 | { 12 | "title": "iTer", 13 | "url": "https://itunes.apple.com/us/app/italker-it/id1224934068?l=zh&ls=1&mt=8", 14 | "author": "10000+ IT企业题库,为升职面试准备" 15 | }, 16 | { 17 | "title": "爱五笔", 18 | "url": "https://itunes.apple.com/cn/app/iWuBi/id1459028801?l=zh&ls=1&mt=8", 19 | "author": "五笔学习App,支持86版和98版/简体和繁体" 20 | }, 21 | { 22 | "title": "iEnglish", 23 | "url": "https://itunes.apple.com/cn/app/iEnglish/id1236558125?l=zh&ls=1&mt=8", 24 | "author": "初学者必备词汇,3000入门单词和词汇分类学习" 25 | }, 26 | { 27 | "title": "SecurityNote", 28 | "url": "https://itunes.apple.com/cn/app/mi-ji-yu-zhong-bu-tong-ji/id925021570?l=zh&mt=8", 29 | "author": "简单简洁简明简便的生活小密记" 30 | } 31 | ] 32 | }, 33 | { 34 | "issue_title": "开源项目", 35 | "issue_subtitle": "GitHub", 36 | "issue_list": [ 37 | { 38 | "title": "OneMindMap", 39 | "url": "https://github.com/iHTCboy/OneMindMap/blob/master/README.md", 40 | "author": "一张思维导图的知识" 41 | }, 42 | { 43 | "title": "iTalker", 44 | "url": "https://github.com/iHTCboy/iTalker", 45 | "author": "IT学习、求职面试必备,IT面试基础必备试题指南" 46 | }, 47 | { 48 | "title": "English", 49 | "url": "https://github.com/iHTCboy/iEnglish", 50 | "author": "初学者必备词汇,3000入门单词和词汇分类学习" 51 | }, 52 | { 53 | "title": "iWuBi", 54 | "url": "https://github.com/iHTCboy/iWuBi", 55 | "author": "五笔输入法知识的学习App,方便初学者学习和快速查询拆字等" 56 | }, 57 | { 58 | "title": "iLeetcode-iOS", 59 | "url": "https://github.com/iHTCboy/iLeetcode-iOS", 60 | "author": "一款IT工程师们提供算法知识充电的应用" 61 | }, 62 | { 63 | "title": "FullScreenBrowser", 64 | "url": "https://github.com/iHTCboy/FullScreenBrowser", 65 | "author": "一个超简单的全屏浏览器,真实无边" 66 | }, 67 | { 68 | "title": "SecurityNote", 69 | "url": "https://github.com/iHTCboy/SecurityNote", 70 | "author": "超级简单和好用的笔记事本App" 71 | }, 72 | { 73 | "title": "CampusOfGLUT", 74 | "url": "https://github.com/iHTCboy/CampusOfGLUT", 75 | "author": "桂林理工大学——校园通App" 76 | }, 77 | { 78 | "title": "GLUTCloud", 79 | "url": "https://github.com/iHTCboy/GLUTCloud", 80 | "author": "桂林理工大学云图——桂工导航App" 81 | }, 82 | { 83 | "title": "GLUTJW", 84 | "url": "https://github.com/iHTCboy/GLUTJWStuderForiPhone", 85 | "author": "桂林理工大学教务系统-学生版" 86 | } 87 | ] 88 | } 89 | ] 90 | -------------------------------------------------------------------------------- /app/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /app/ios/Runner/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by HTC on 2021/2/23. 6 | 7 | */ 8 | -------------------------------------------------------------------------------- /app/ios/Runner/en.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/ios/Runner/iPomodoro/ITCommonAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ITCommonAPI.swift 3 | // iTalker 4 | // 5 | // Created by HTC on 2017/4/23. 6 | // Copyright © 2017年 ihtc.cc @iHTCboy. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MessageUI 11 | 12 | 13 | class ITCommonAPI: NSObject { 14 | 15 | static let shared = ITCommonAPI() 16 | private override init() {} //This prevents others from using the default '()' initializer for this class. 17 | 18 | } 19 | 20 | // update 21 | extension ITCommonAPI 22 | { 23 | 24 | } 25 | 26 | extension ITCommonAPI : MFMailComposeViewControllerDelegate 27 | { 28 | func sendEmail(recipients: Array, subject: String, messae: String, vc: UIViewController) { 29 | if MFMailComposeViewController.canSendMail() { 30 | let mail = MFMailComposeViewController() 31 | mail.mailComposeDelegate = self 32 | mail.setToRecipients(recipients) 33 | mail.setSubject(subject) 34 | mail.setMessageBody(messae, isHTML: false) 35 | vc.present(mail, animated: true, completion: nil) 36 | } else { 37 | // show failure alert 38 | } 39 | } 40 | 41 | func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { 42 | controller.dismiss(animated: true) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/ios/Runner/iPomodoro/TableHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableHeaderView.swift 3 | // iTalker 4 | // 5 | // Created by HTC on 2019/4/24. 6 | // Copyright © 2019 ihtc.cc @iHTCboy. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TableHeaderView: UIView { 12 | 13 | @IBOutlet var contentView: UIView! 14 | @IBOutlet weak var titleLbl: UILabel! 15 | @IBOutlet weak var subtitleLbl: UILabel! 16 | 17 | override init(frame: CGRect) { 18 | super.init(frame: frame) 19 | setupUI() 20 | } 21 | 22 | required init?(coder aDecoder: NSCoder) { 23 | super.init(coder: aDecoder) 24 | setupUI() 25 | } 26 | 27 | private func setupUI() { 28 | Bundle.main.loadNibNamed("TableHeaderView", owner: self, options: nil) 29 | addSubview(contentView) 30 | contentView.frame = self.frame 31 | contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 32 | } 33 | 34 | class func initView(title: String, subtitle: String, height: CGFloat) -> TableHeaderView { 35 | let hview = TableHeaderView.init(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: height)) 36 | hview.titleLbl.text = title 37 | hview.subtitleLbl.text = subtitle 38 | if UIDevice.current.userInterfaceIdiom == .pad { 39 | hview.titleLbl.font = UIFont.systemFont(ofSize: 17) 40 | hview.subtitleLbl.font = UIFont.systemFont(ofSize: 14) 41 | } 42 | return hview 43 | } 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /app/ios/Runner/iPomodoro/TableHeaderView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/ios/Runner/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by HTC on 2021/2/23. 6 | 7 | */ 8 | 9 | 10 | "CFBundleName" = "爱番茄"; 11 | "CFBundleDisplayName" = "爱番茄"; 12 | -------------------------------------------------------------------------------- /app/ios/Runner/zh-Hans.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UILabel"; text = "iPomodoro"; ObjectID = "XSp-Ly-PkP"; */ 3 | "XSp-Ly-PkP.text" = "爱番茄"; 4 | -------------------------------------------------------------------------------- /app/ios/Runner/zh-Hans.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/ios/Runner/zh-Hant.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by HTC on 2021/2/23. 6 | 7 | */ 8 | 9 | 10 | "CFBundleName" = "愛蕃茄"; 11 | "CFBundleDisplayName" = "愛蕃茄"; 12 | -------------------------------------------------------------------------------- /app/ios/Runner/zh-Hant.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UILabel"; text = "iPomodoro"; ObjectID = "XSp-Ly-PkP"; */ 3 | "XSp-Ly-PkP.text" = "愛蕃茄"; 4 | -------------------------------------------------------------------------------- /app/ios/Runner/zh-Hant.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/lib/common/channel/native_method_channel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | 3 | 4 | //调用原生方法 5 | class NativeChannel { 6 | 7 | static Future invokeMethod(String method) async { 8 | const platform = const MethodChannel('iPomodoro'); 9 | var result; 10 | try { 11 | result = await platform.invokeMethod(method); 12 | return Future.value(result); 13 | } on PlatformException catch (e) { 14 | return Future.error(e.toString()); 15 | } 16 | } 17 | 18 | static Future requestReview() async { 19 | const platform = const MethodChannel('iPomodoro'); 20 | var result; 21 | try { 22 | result = await platform.invokeMethod('requestReview'); 23 | return Future.value(result); 24 | } on PlatformException catch (e) { 25 | return Future.error(e.toString()); 26 | } 27 | } 28 | 29 | static Future gotoStoreReview() async { 30 | const platform = const MethodChannel('iPomodoro'); 31 | var result; 32 | try { 33 | result = await platform.invokeMethod('gotoStoreReview'); 34 | return Future.value(result); 35 | } on PlatformException catch (e) { 36 | return Future.error(e.toString()); 37 | } 38 | } 39 | 40 | static Future shareApp(String url, String content) async { 41 | const platform = const MethodChannel('iPomodoro'); 42 | var result; 43 | try { 44 | result = await platform.invokeMethod('shareApp', {'url': url, 'content': content}); 45 | return Future.value(result); 46 | } on PlatformException catch (e) { 47 | return Future.error(e.toString()); 48 | } 49 | } 50 | 51 | static Future emailConnect(String appname, String email) async { 52 | const platform = const MethodChannel('iPomodoro'); 53 | var result; 54 | try { 55 | result = await platform.invokeMethod('email', {'appname': appname, 'email': email}); 56 | return Future.value(result); 57 | } on PlatformException catch (e) { 58 | return Future.error(e.toString()); 59 | } 60 | } 61 | 62 | static Future moreLearn() async { 63 | const platform = const MethodChannel('iPomodoro'); 64 | var result; 65 | try { 66 | result = await platform.invokeMethod('more'); 67 | return Future.value(result); 68 | } on PlatformException catch (e) { 69 | return Future.error(e.toString()); 70 | } 71 | } 72 | 73 | static Future appVersion() async { 74 | const platform = const MethodChannel('iPomodoro'); 75 | var result; 76 | try { 77 | result = await platform.invokeMethod('version'); 78 | return Future.value(result); 79 | } on PlatformException catch (e) { 80 | return Future.error(e.toString()); 81 | } 82 | } 83 | 84 | static Future timeZone() async { 85 | const platform = const MethodChannel('iPomodoro'); 86 | var result; 87 | try { 88 | result = await platform.invokeMethod('timeZone'); 89 | return Future.value(result); 90 | } on PlatformException catch (e) { 91 | return Future.error(e.toString()); 92 | } 93 | } 94 | 95 | static Future changeBadgeNumber(int badgeNumber) async { 96 | const platform = const MethodChannel('iPomodoro'); 97 | var result; 98 | try { 99 | result = await platform.invokeMethod('badgeNumber', {'badgeNumber': badgeNumber}); 100 | return Future.value(result); 101 | } on PlatformException catch (e) { 102 | return Future.error(e.toString()); 103 | } 104 | } 105 | 106 | static Future idleTimerDisabled(bool idDisabled) async { 107 | const platform = const MethodChannel('iPomodoro'); 108 | var result; 109 | try { 110 | result = await platform.invokeMethod('idleTimer', {'idleTimer': idDisabled}); 111 | return Future.value(result); 112 | } on PlatformException catch (e) { 113 | return Future.error(e.toString()); 114 | } 115 | } 116 | 117 | static Future changeBrightness(String brightness, {String getBrightness="0"}) async { 118 | const platform = const MethodChannel('iPomodoro'); 119 | var result; 120 | try { 121 | result = await platform.invokeMethod('brightness', {'brightness': brightness, 'getBrightness': getBrightness}); 122 | return Future.value(result); 123 | } on PlatformException catch (e) { 124 | return Future.error(e.toString()); 125 | } 126 | } 127 | 128 | static Future openPrivacyView(String languageCode) async { 129 | const platform = const MethodChannel('iPomodoro'); 130 | var result; 131 | try { 132 | result = await platform.invokeMethod('privacy_policy', {'languageCode': languageCode}); 133 | return Future.value(result); 134 | } on PlatformException catch (e) { 135 | return Future.error(e.toString()); 136 | } 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /app/lib/common/constant/app_colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppColors { 4 | //主色 5 | static const Color PRIMARY_MAIN_COLOR = const Color(0xFFD74A49); 6 | static const Color PRIMARY_SUB_COLOR = const Color(0xFFDC5C5D); 7 | static const Color TIMER_MAIN_COLOR = const Color(0xFF4F97E0); 8 | static const Color TIMER_SUB_COLOR = const Color(0xFF579DE5); 9 | static const Color COUNTDOWN_MAIN_COLOR = const Color(0xFFFF8900); 10 | static const Color COUNTDOWN_SUB_COLOR = const Color(0xFFFF9F40); 11 | static const Color ME_MAIN_COLOR = const Color(0xFF007C21); 12 | static const Color ME_SUB_COLOR = const Color(0xFF248F40); 13 | 14 | static bool isDarkMode(BuildContext context){ 15 | return Theme.of(context).brightness == Brightness.dark; 16 | } 17 | } -------------------------------------------------------------------------------- /app/lib/common/utils/audio_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:audioplayers/audioplayers.dart'; 2 | 3 | // https://pub.dev/packages/audioplayers/example 4 | class AudioPlayerUtil { 5 | static AudioPlayer player = AudioPlayer(); 6 | AudioPlayer audioPlayer = AudioPlayer(); 7 | final AudioContext audioContext = AudioContext( 8 | iOS: AudioContextIOS( 9 | category: AVAudioSessionCategory.playback, 10 | options: [ 11 | AVAudioSessionOptions.defaultToSpeaker, 12 | AVAudioSessionOptions.allowAirPlay, 13 | AVAudioSessionOptions.allowBluetooth, 14 | AVAudioSessionOptions.allowBluetoothA2DP, 15 | AVAudioSessionOptions.mixWithOthers, 16 | ], 17 | ), 18 | android: AudioContextAndroid( 19 | isSpeakerphoneOn: true, 20 | stayAwake: true, 21 | contentType: AndroidContentType.music, 22 | usageType: AndroidUsageType.media, 23 | audioFocus: AndroidAudioFocus.gain, 24 | ), 25 | ); 26 | 27 | static playAudio(url) { 28 | if (url == null) { 29 | return player.resume(); 30 | } else { 31 | return player.play(AssetSource(url)); 32 | } 33 | } 34 | 35 | static stopAudio() { 36 | return player.stop(); 37 | } 38 | setCache(url) { 39 | AudioPlayer.global.setGlobalAudioContext(audioContext); 40 | audioPlayer.setPlayerMode(PlayerMode.lowLatency); 41 | return audioPlayer.setSource(AssetSource(url)); 42 | } 43 | 44 | play(url) { 45 | if (url == null) { 46 | if (audioPlayer.state == PlayerState.playing) { 47 | return; 48 | } 49 | return audioPlayer.resume(); 50 | } else { 51 | return audioPlayer.play(AssetSource(url)); 52 | } 53 | } 54 | 55 | seek(duration) { 56 | return audioPlayer.seek(duration); 57 | } 58 | 59 | loop(bool isLoop) { 60 | audioPlayer.setReleaseMode(isLoop ? ReleaseMode.loop : ReleaseMode.stop); 61 | } 62 | 63 | stop() { 64 | return audioPlayer.stop(); 65 | } 66 | 67 | pause() { 68 | return audioPlayer.pause(); 69 | } 70 | 71 | release() { 72 | return audioPlayer.release(); 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /app/lib/common/utils/config_storage.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class AppStorage { 4 | 5 | static const String K_STRING_POMODORO_HOURS = "k_string_pomodoro_hours"; 6 | static const String K_STRING_POMODORO_MINUTES = "k_string_pomodoro_minutes"; 7 | static const String K_STRING_POMODORO_BREAK_SHORT = "k_string_pomodoro_break_short"; 8 | static const String K_STRING_POMODORO_BREAK_LONG = "k_string_pomodoro_break_long"; 9 | static const String K_STRING_POMODORO_BREAK_LONG_DELAY = "k_string_pomodoro_break_long_delay"; 10 | static const String K_STRING_POMODORO_NOTIFICATION = "k_string_pomodoro_notification"; 11 | static const String K_STRING_POMODORO_TICKING_SOUND = "k_string_pomodoro_tick_sound"; 12 | static const String K_STRING_POMODORO_ALARM_SOUND = "k_string_pomodoro_alarm_sound"; 13 | static const String K_STRING_POMODORO_TITLE_BAR_COLOR = "k_string_pomodoro_title_bar_color"; 14 | static const String K_STRING_POMODORO_BACKGROUND_COLOR = "k_string_pomodoro_background_color"; 15 | static const String K_STRING_TIMER_HOURS = "k_string_timer_hours"; 16 | static const String K_STRING_TIMER_MINUTES = "k_string_timer_minutes"; 17 | static const String K_STRING_TIMER_NOTIFICATION = "k_string_timer_notification"; 18 | static const String K_STRING_TIMER_TICKING_SOUND = "k_string_timer_tick_sound"; 19 | static const String K_STRING_TIMER_ALARM_SOUND = "k_string_timer_alarm_sound"; 20 | static const String K_STRING_TIMER_TITLE_BAR_COLOR = "k_string_timer_title_bar_color"; 21 | static const String K_STRING_TIMER_BACKGROUND_COLOR = "k_string_timer_background_color"; 22 | static const String K_STRING_COUNTDOWN_ORDER_INDEX = "k_string_countdown_order_idex"; 23 | static const String K_STRING_COUNTDOWN_TITLE_BAR_COLOR = "k_string_countdown_title_bar_color"; 24 | static const String K_STRING_COUNTDOWN_BACKGROUND_COLOR = "k_string_countdown_background_color"; 25 | static const String K_STRING_LANGUAGE_SETTINGS = "k_string_language_settings"; 26 | static const String K_STRING_PRIVACY_SHOW_TIPS = "k_string_privacy_show_tips"; 27 | 28 | 29 | static Future setInt(String key, int value) async { 30 | final prefs = await SharedPreferences.getInstance(); 31 | bool status = await prefs.setInt(key, value); 32 | return status; 33 | } 34 | 35 | static Future setBool(String key, bool value) async { 36 | final prefs = await SharedPreferences.getInstance(); 37 | bool status = await prefs.setBool(key, value); 38 | return status; 39 | } 40 | 41 | static Future setString(String key, String value) async { 42 | final prefs = await SharedPreferences.getInstance(); 43 | bool status = await prefs.setString(key, value); 44 | return status; 45 | } 46 | 47 | static Future getInt(String key) async { 48 | final prefs = await SharedPreferences.getInstance(); 49 | int? result = prefs.getInt(key); 50 | return result; 51 | } 52 | 53 | static Future getBool(String key) async { 54 | final prefs = await SharedPreferences.getInstance(); 55 | bool? result = prefs.getBool(key); 56 | return result; 57 | } 58 | 59 | static Future getString(String key) async { 60 | final prefs = await SharedPreferences.getInstance(); 61 | String? result = prefs.getString(key); 62 | return result; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /app/lib/common/utils/database_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:sqflite/sqflite.dart'; 3 | import 'package:path/path.dart'; 4 | 5 | class DataBaseUtils { 6 | static Database _database = openDatabase("") as Database; 7 | 8 | ///创建数据库db 9 | static db_createDb(String dbName, int vers, String dbTables) async { 10 | //获取数据库路径 11 | var databasesPath = await getDatabasesPath(); 12 | String path = join(databasesPath, dbName); 13 | debugPrint("DataBase:$path ,version:$vers"); 14 | //打开数据库 15 | _database = await openDatabase(path, 16 | version: vers, 17 | onUpgrade: (Database db, int oldVersion, int newVersion) async { 18 | //数据库升级,只回调一次 19 | debugPrint("数据库需要升级!旧版:$oldVersion,新版:$newVersion"); 20 | }, onCreate: (Database db, int vers) async { 21 | // print('创建数据库表'); 22 | //创建表,只回调一次 23 | await db.execute(dbTables); 24 | await db.close(); 25 | }); 26 | } 27 | 28 | static Future getCurrentDatabase(String dbName) async { 29 | if (!_database.isOpen) { 30 | // _database = null; 31 | var databasesPath = await getDatabasesPath(); 32 | String path = join(databasesPath, dbName); 33 | _database = await openDatabase(path); 34 | } 35 | return _database; 36 | } 37 | 38 | ///增(事务方式) 39 | static db_add(String dbName, String sql) async { 40 | //获取数据库路径 41 | var databasesPath = await getDatabasesPath(); 42 | String path = join(databasesPath, dbName); 43 | Database db = await openDatabase(path); 44 | 45 | await db.transaction((txn) async { 46 | int count = await txn.rawInsert(sql); 47 | }); 48 | await db.close(); 49 | } 50 | 51 | /// 插入 52 | static Future db_insert(String dbName, String table, Map values) async { 53 | //获取数据库路径 54 | var databasesPath = await getDatabasesPath(); 55 | String path = join(databasesPath, dbName); 56 | Database db = await openDatabase(path); 57 | 58 | int id = await db.insert(table, values); 59 | await db.close(); 60 | return id; //返回最后插入的记录ID 61 | } 62 | /* 63 | int id0 = await db.insert('Test', {'name': 'another', 'value': '18', 'num': '456.7'}); 64 | int id1 = await db.rawInsert('INSERT INTO Test(name, value, num) VALUES("some name", 1234, 456.789)'); 65 | int id2 = await db.rawInsert('INSERT INTO Test(name, value, num) VALUES(?, ?, ?)', ['another', 12345678, 3.1416]); 66 | */ 67 | 68 | ///删 69 | static Future db_delete(String dbName, String sql, List arg) async { 70 | var databasesPath = await getDatabasesPath(); 71 | String path = join(databasesPath, dbName); 72 | Database db = await openDatabase(path); 73 | 74 | int count = await db.rawDelete(sql, arg); 75 | await db.close(); 76 | return count; //返回受影响的的数量,即删除的条目数量 77 | } 78 | 79 | ///改 80 | static Future db_update(String dbName, String sql, List arg) async { 81 | var databasesPath = await getDatabasesPath(); 82 | String path = join(databasesPath, dbName); 83 | Database db = await openDatabase(path); 84 | 85 | int count = await db.rawUpdate(sql, arg); //修改条件,对应参数值 86 | await db.close(); 87 | return count; //返回受影响的的数量 88 | } 89 | 90 | ///查条数 91 | static Future db_getQueryNum(String dbName, String sql) async { 92 | var databasesPath = await getDatabasesPath(); 93 | String path = join(databasesPath, dbName); 94 | Database db = await openDatabase(path); 95 | 96 | int? count = Sqflite.firstIntValue(await db.rawQuery(sql)); 97 | await db.close(); 98 | return count ?? 0; 99 | } 100 | 101 | ///查全部 102 | static Future> db_query(String dbName, String sql) async { 103 | var databasesPath = await getDatabasesPath(); 104 | String path = join(databasesPath, dbName); 105 | Database db = await openDatabase(path); 106 | List list = await db.rawQuery(sql); 107 | 108 | await db.close(); 109 | return list; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/lib/common/utils/device_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:io' show Platform; 3 | 4 | class DeviceUtils { 5 | static double get_size( 6 | BuildContext context, double small, double normal, double pad) { 7 | double width = MediaQuery.of(context).size.width; 8 | double height = MediaQuery.of(context).size.height; 9 | bool isSmall = width < 400 || height < 400; 10 | bool isPad = (width > 480 && height > 1000) || ((height > 480 && width > 1000)); 11 | return isSmall ? small : (isPad ? pad : normal); 12 | } 13 | 14 | static double scale_width( 15 | BuildContext context, double small, double normal, double pad) { 16 | double width = MediaQuery.of(context).size.width; 17 | double height = MediaQuery.of(context).size.height; 18 | if(width > height) { 19 | width = height; 20 | } 21 | return width * get_size(context, small, normal, pad); 22 | } 23 | 24 | static double scale_height( 25 | BuildContext context, double small, double normal, double pad) { 26 | double width = MediaQuery.of(context).size.width; 27 | double height = MediaQuery.of(context).size.height; 28 | if(width > height) { 29 | height = width; 30 | } 31 | return height * get_size(context, small, normal, pad); 32 | } 33 | 34 | static String languageCode() { 35 | String languageCode = Platform.localeName.split('_')[0]; 36 | return languageCode; 37 | } 38 | 39 | static String countryCode() { 40 | String countryCode = Platform.localeName.split('_')[1]; 41 | return countryCode; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/lib/common/utils/notification_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 3 | import '../../main.dart'; 4 | import 'package:timezone/timezone.dart' as tz; 5 | 6 | class NotificationUtils { 7 | static showNotification(int id, String title, String body, {int badgeNumber=1, String payload=""}) async { 8 | var android = new AndroidNotificationDetails( 9 | 'channel id', 'channel NAME', 10 | priority: Priority.high, importance: Importance.max); 11 | var iOS = DarwinNotificationDetails(badgeNumber: badgeNumber); 12 | var macOS = DarwinNotificationDetails(badgeNumber: badgeNumber); 13 | var platform = NotificationDetails(android: android, iOS: iOS, macOS: macOS); 14 | await flutterLocalNotificationsPlugin.show(id, title, body, platform, payload: payload); 15 | // await flutterLocalNotificationsPlugin.show( 16 | // 0, 'plain title', 'plain body', platform, 17 | // payload: 'item x'); 18 | } 19 | 20 | static Future addScheduleNotification(int id, String title, String body, int seconds) async { 21 | // await flutterLocalNotificationsPlugin.zonedSchedule( 22 | // id, 23 | // title, 24 | // body, 25 | // tz.TZDateTime.now(tz.local).add(Duration(seconds: seconds)), 26 | // const NotificationDetails( 27 | // android: AndroidNotificationDetails('your channel id', 'your channel name')), 28 | // androidAllowWhileIdle: true, 29 | // uiLocalNotificationDateInterpretation: 30 | // UILocalNotificationDateInterpretation.absoluteTime); 31 | 32 | await flutterLocalNotificationsPlugin.zonedSchedule( 33 | id, 34 | title, 35 | body, 36 | tz.TZDateTime.now(tz.local).add(Duration(seconds: seconds)), 37 | const NotificationDetails( 38 | android: AndroidNotificationDetails( 39 | 'full screen channel id', 'full screen channel name', 40 | channelDescription: 'full screen channel description', 41 | priority: Priority.max, 42 | importance: Importance.max, 43 | fullScreenIntent: false)), 44 | androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle); 45 | } 46 | 47 | 48 | static Future cancelNotification(int id) async { 49 | await flutterLocalNotificationsPlugin.cancel(id); 50 | } 51 | 52 | static Future cancelAllNotifications() async { 53 | await flutterLocalNotificationsPlugin.cancelAll(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/lib/common/utils/time_utils.dart: -------------------------------------------------------------------------------- 1 | 2 | enum TimerStateMode { 3 | start, 4 | timing, 5 | pause, 6 | stop, 7 | } 8 | 9 | enum PomodoroMode { 10 | stop, 11 | timing, 12 | breaktime, 13 | } 14 | 15 | class TimeUtils { 16 | static List calculateDate(int secoonds) { 17 | int hours = 0; 18 | int seconds = secoonds % 60; 19 | int minutes = (secoonds / 60).floor(); 20 | if (minutes >= 60) { 21 | hours = (minutes / 60).floor(); 22 | minutes = minutes % 60; 23 | } 24 | List time = [ 25 | hours, 26 | minutes > 9 ? minutes.toString() : '0$minutes', 27 | seconds > 9 ? seconds.toString() : '0$seconds' 28 | ]; 29 | return time; 30 | } 31 | 32 | static String get_formatted_date(DateTime date) { 33 | String formattedDate = 34 | "${date.year.toString()}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')} ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}"; 35 | return formattedDate; 36 | } 37 | 38 | static int get_difference_day(DateTime date) { 39 | //当前日期 40 | final now = DateTime.now(); 41 | //比较相差的天数 42 | final difference = date.difference(now).inDays; 43 | return difference; 44 | } 45 | } -------------------------------------------------------------------------------- /app/lib/config/app_config.dart: -------------------------------------------------------------------------------- 1 | 2 | class AppConfig { 3 | static const AppName = "iPomodoro"; 4 | static const AppAppleId = "1439666929"; 5 | static const AppPackageName = "com.iHTCboy.iPomodoro"; 6 | static const AppPackageNameTwo = "com.iHTCboy.iPomodoros"; 7 | static const AppAppStoreUrl = "https://apps.apple.com/cn/app/ipomodoro/id1439666929"; 8 | static const AppAppStoreReviewAction = "&action=write-review"; 9 | static const AppPlayStoreUrl = "https://play.google.com/store/apps/details?id=" + AppPackageNameTwo; 10 | static const AppGitHubUrl = "https://github.com/iHTCboy/iPomodoro-Flutter"; 11 | static const AppLicenseUrl = "https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/master/LICENSE"; 12 | static const kiHTCboyUrl = "https://ihtcboy.com"; 13 | static const kiHTCboyer = "https://apps.apple.com/cn/developer/iHTCboy/id914453386"; 14 | static const kEmail = "iHTCdevelop@gmail.com"; 15 | } -------------------------------------------------------------------------------- /app/lib/generated/intl/messages_all.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that looks up messages for specific locales by 3 | // delegating to the appropriate library. 4 | 5 | // Ignore issues from commonly used lints in this file. 6 | // ignore_for_file:implementation_imports, file_names, unnecessary_new 7 | // ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering 8 | // ignore_for_file:argument_type_not_assignable, invalid_assignment 9 | // ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases 10 | // ignore_for_file:comment_references 11 | 12 | import 'dart:async'; 13 | 14 | import 'package:flutter/foundation.dart'; 15 | import 'package:intl/intl.dart'; 16 | import 'package:intl/message_lookup_by_library.dart'; 17 | import 'package:intl/src/intl_helpers.dart'; 18 | 19 | import 'messages_en.dart' as messages_en; 20 | import 'messages_zh.dart' as messages_zh; 21 | 22 | typedef Future LibraryLoader(); 23 | Map _deferredLibraries = { 24 | 'en': () => new SynchronousFuture(null), 25 | 'zh': () => new SynchronousFuture(null), 26 | }; 27 | 28 | MessageLookupByLibrary? _findExact(String localeName) { 29 | switch (localeName) { 30 | case 'en': 31 | return messages_en.messages; 32 | case 'zh': 33 | return messages_zh.messages; 34 | default: 35 | return null; 36 | } 37 | } 38 | 39 | /// User programs should call this before using [localeName] for messages. 40 | Future initializeMessages(String localeName) { 41 | var availableLocale = Intl.verifiedLocale( 42 | localeName, (locale) => _deferredLibraries[locale] != null, 43 | onFailure: (_) => null); 44 | if (availableLocale == null) { 45 | return new SynchronousFuture(false); 46 | } 47 | var lib = _deferredLibraries[availableLocale]; 48 | lib == null ? new SynchronousFuture(false) : lib(); 49 | initializeInternalMessageLookup(() => new CompositeMessageLookup()); 50 | messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); 51 | return new SynchronousFuture(true); 52 | } 53 | 54 | bool _messagesExistFor(String locale) { 55 | try { 56 | return _findExact(locale) != null; 57 | } catch (e) { 58 | return false; 59 | } 60 | } 61 | 62 | MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { 63 | var actualLocale = 64 | Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); 65 | if (actualLocale == null) return null; 66 | return _findExact(actualLocale); 67 | } 68 | -------------------------------------------------------------------------------- /app/lib/l10n/intl_zh.arb: -------------------------------------------------------------------------------- 1 | { 2 | "iPomodoro": "爱番茄", 3 | "pomodoro": "番茄钟", 4 | "countdown": "倒计时", 5 | "tasks": "定任务", 6 | "about_me": "关于我", 7 | "hours": "时", 8 | "minutes": "分", 9 | "days": "天", 10 | "pomodoro_push_tips": "番茄君提醒\uD83C\uDF45!", 11 | "break_time": "\uD83C\uDF4C 休息时间..", 12 | "learn_time": "\uD83C\uDF45 学习中..", 13 | "pomodoro_time": "\uD83C\uDF45 番茄学习", 14 | "give_up_button": "放弃", 15 | "start_button": "开始", 16 | "pause_button": "暂停", 17 | "continue_button": "继续", 18 | "tips_text": "提示", 19 | "pomodoro_give_up_tips": "确认要放弃当前\uD83C\uDF45番茄时间吗?", 20 | "pomodoro_no": "否(\uD83D\uDCAA)", 21 | "pomodoro_yes": "是(\uD83D\uDE2D)", 22 | "tips_come_on": "加油", 23 | "tips_congratulation": "恭喜", 24 | "pomodoro_next_times": "开始第{x_pomodoro}个\uD83C\uDF45番茄时间啦!", 25 | "pomodoro_next_break": "已经完成第{x_pomodoro}个番茄钟,休息一会,☕️补充能量吧️!", 26 | "pomodoro_ok": "好✊", 27 | "pomodoro_settings": "番茄设置", 28 | "pomodoro_duration": "每个番茄学习时间", 29 | "pomodoro_short_break_duration": "每个番茄休息时间(短)", 30 | "pomodoro_long_break_duration": "每个番茄休息时间(长)", 31 | "pomodoro_logn_break_delay": "超长休息时间个数", 32 | "pomodoro_minutes": "{pomodoro_time}分钟", 33 | "pomodoro_hours_minutes": "{pomodoro_hours}小时{pomodoro_minutes}分钟", 34 | "pomodoro_times": "{pomodoro_times}个番茄时间", 35 | "background_push_tips": "允许后台推送提醒", 36 | "play_clock_ticking_sound": "倒计时背景声", 37 | "alarm_sound": "倒计时结束铃声", 38 | "switch_on": "开", 39 | "switch_off": "关", 40 | "timer_push_tips": "计时君提醒⏳!", 41 | "timer_learn": "计时学习", 42 | "timer_learning": "⏳ 学习中..", 43 | "timer_learn_tips": "⌛ 倒计时学习", 44 | "timer_give_up_tips": "确认要放弃当前⏳倒计时吗?", 45 | "timer_congratulation_next": "当前⏳倒计时已经完成!是否继续下一个?", 46 | "timer_no": "否(\uD83D\uDE02)", 47 | "timer_continue": "继续(\uD83D\uDC4A)", 48 | "timer_settings": "倒计时设置", 49 | "timer_duration": "每个倒计时的时长", 50 | "countdown_tasks": "定时任务", 51 | "countdown_add": "添加新任务", 52 | "countdown_empty": "无任务", 53 | "countdown_delete_tips": "确认要删除“{title}”这个任务吗?", 54 | "countdown_settings": "定时任务设置", 55 | "countdown_tasks_sort": "任务列表的排序", 56 | "tips_no": "否", 57 | "tips_yes": "是", 58 | "tips_modify": "修改", 59 | "tips_delete": "删除", 60 | "tips_empty": "无", 61 | "date_format": "{year}年{month}月{day}日 {hour}:{minute} {weekday}", 62 | "tips_sort_id_asc": "按新增日期升序", 63 | "tips_sort_id_desc": "按新增日期降序", 64 | "tips_sort_date_asc": "按任务日期升序", 65 | "tips_sort_date_desc": "按任务日期降序", 66 | "tips_sort_modify_asc": "按修改日期升序", 67 | "tips_sort_modify_desc": "按修改日期降序", 68 | "tips_unknown": "未知", 69 | "tips_monday": "周一", 70 | "tips_tuesday": "周二", 71 | "tips_wednesday": "周三", 72 | "tips_thursday": "周四", 73 | "tips_friday": "周五", 74 | "tips_saturday": "周六", 75 | "tips_sunday": "周日", 76 | "tips_app_about": "关于应用", 77 | "tips_app_desc": "番茄时间管理和学习规划,妈妈再也不用担心我的学习啦!不再分心!不再拖延!高效!专注!,让大家在学习时可以更加专注也可以快速和简单的学习get! \n \n1、番茄学习模式,使用番茄工作法学习,让你劳逸结合!\n2、计时学习模式,按照设定的时长学习,想学多久就学多久!\n3、定时任务模式,倒数日、任务记录,每日学习任务!杜绝学习没有目标!满足你对学习的求知欲望!", 78 | "tips_app_share_textd": "Hello, 爱番茄(iPomodoro)! 这是一款番茄时间管理规划的App,不再分心!不再拖延!高效!专注!学习必备的好工具哦!iOS下载:{AppStoreUrl},Android 下载:Google Play Store", 79 | "tips_task": "任务", 80 | "tips_task_name": "任务名称", 81 | "tips_task_time": "任务时间", 82 | "tips_task_tags": "任务备注", 83 | "tips_task_empty": "'任务名字和时间不能为空!'", 84 | "tips_save": "保存", 85 | "tips_cancel": "取消", 86 | "tips_confirm": "确认", 87 | "tips_select_time": "选择时间", 88 | "set_screen_brightness": "设置屏幕亮度", 89 | "set_screen_brightness_desc": "以便番茄时间时节省电量", 90 | "set_app_review": "应用内评分", 91 | "set_app_review_desc": "欢迎给{AppName}打评分!", 92 | "set_appstore_review": "去商店评分", 93 | "set_appstore_review_desc": "欢迎给{AppName}写评论!", 94 | "set_share_friend": "分享给好友", 95 | "set_share_friend_desc": "与身边的好友一起学习!", 96 | "set_feedback": "反馈和建议", 97 | "set_feedback_desc": "欢迎提需求或bug问题", 98 | "set_email_connect": "邮件联系", 99 | "set_email_connect_desc": "如有问题欢迎来信", 100 | "set_privacy_policy": "隐私条款", 101 | "set_privacy_policy_desc": "用户使用服务协议", 102 | "set_open_source": "开源地址", 103 | "set_open_source_desc": "现已开放代码,欢迎关注", 104 | "set_focus": "更多关注", 105 | "set_focus_desc": "欢迎访问作者博客", 106 | "set_recommend": "更多推荐", 107 | "set_recommend_desc": "更多开发者内容推荐", 108 | "set_localizetion": "设置显示语言", 109 | "set_localizetion_desc": "更改App的语言", 110 | "privacy_policy_tips": "需要同意《用户隐私政策协议》才能继续使用,点击可查看协议内容;点击“同意”按钮表示同意隐私协议继续使用;如不同意,请点击“拒绝”退出应用。", 111 | "privacy_policy_agree": "同意", 112 | "privacy_policy_reject": "拒绝", 113 | "theme_style_title": "页面颜色设置", 114 | "theme_style_title_bar_color": "选择导航栏颜色", 115 | "theme_style_title_background_color": "选择背景颜色", 116 | "theme_style_default_color": "还原为默认颜色", 117 | "theme_style_save_color": "保存当前更改" 118 | } -------------------------------------------------------------------------------- /app/lib/model/countdown_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:iPomodoro/common/utils/database_utils.dart'; 3 | import 'package:iPomodoro/common/utils/time_utils.dart'; 4 | import 'package:iPomodoro/generated/l10n.dart'; 5 | 6 | const String K_Pomodoro_Database = 'pomodoro.db'; 7 | const String K_Countdown_DB_Table = 'countdown_tasks'; 8 | 9 | enum QueryType { 10 | shard, //占位用 11 | idAsc, 12 | idDesc, 13 | dateAsc, 14 | dateDesc, 15 | modifyAsc, 16 | modifyDesc, 17 | } 18 | 19 | extension QueryTypeExt on QueryType { 20 | 21 | static const Map values = { 22 | QueryType.idAsc: 'id asc', 23 | QueryType.idDesc: 'id desc', 24 | QueryType.dateAsc: 'date asc', 25 | QueryType.dateDesc: 'date desc', 26 | QueryType.modifyAsc: 'modify_date asc', 27 | QueryType.modifyDesc: 'modify_date desc', 28 | }; 29 | 30 | static const Map types = { 31 | 0: QueryType.idAsc, 32 | 1: QueryType.idDesc, 33 | 2: QueryType.dateAsc, 34 | 3: QueryType.dateDesc, 35 | 4: QueryType.modifyAsc, 36 | 5: QueryType.modifyDesc, 37 | }; 38 | 39 | String get value => (values[this] ?? 'id asc'); 40 | 41 | List get getValues => values.values.toList(); 42 | 43 | Map get getTypes => types; 44 | } 45 | 46 | class CountdownModel { 47 | int itemId = 0; 48 | String title = ''; 49 | DateTime date = DateTime.now(); 50 | DateTime modify_date = DateTime.now(); //修改日期 51 | String notes = ''; 52 | int push = 0; //是否定时推送通知 53 | 54 | CountdownModel(this.title, this.date, this.notes, 55 | {this.itemId = 0, this.push = 0, DateTime? modify_date}) 56 | : modify_date = modify_date?? DateTime.now(); 57 | 58 | CountdownModel.fromJson(Map json) { 59 | this.itemId = json['id'] ?? 0; 60 | this.title = json['title']; 61 | this.date = DateTime.fromMillisecondsSinceEpoch(json['date']); 62 | this.modify_date = DateTime.fromMillisecondsSinceEpoch(json['modify_date']); 63 | this.notes = json['notes']; 64 | this.push = json['push'] ?? 0; 65 | } 66 | 67 | Map toJsonMap() { 68 | Map map = new Map(); 69 | map["title"] = title; 70 | map["date"] = date.millisecondsSinceEpoch; 71 | map["notes"] = notes; 72 | map["push"] = push; 73 | map["modify_date"] = modify_date.millisecondsSinceEpoch; 74 | return map; 75 | } 76 | 77 | String date_string(BuildContext context) { 78 | String weekday = get_weekday_string(context, date.weekday); 79 | String formattedDate = S.of(context).date_format('${date.year.toString()}', 80 | '${date.month.toString().padLeft(2, '0')}', 81 | '${date.day.toString().padLeft(2, '0')}', 82 | '${date.hour.toString().padLeft(2, '0')}', 83 | '${date.minute.toString().padLeft(2, '0')}', 84 | '${weekday}'); 85 | return formattedDate; 86 | } 87 | 88 | int countdown_day() { 89 | return TimeUtils.get_difference_day(date); 90 | } 91 | 92 | static String get_weekday_string(BuildContext context, int weekday) { 93 | String day = S.of(context).tips_unknown; 94 | switch (weekday) { 95 | case 1: 96 | day = S.of(context).tips_monday; 97 | break; 98 | case 2: 99 | day = S.of(context).tips_tuesday; 100 | break; 101 | case 3: 102 | day = S.of(context).tips_wednesday; 103 | break; 104 | case 4: 105 | day = S.of(context).tips_thursday; 106 | break; 107 | case 5: 108 | day = S.of(context).tips_friday; 109 | break; 110 | case 6: 111 | day = S.of(context).tips_saturday; 112 | break; 113 | case 7: 114 | day = S.of(context).tips_sunday; 115 | break; 116 | } 117 | return day; 118 | } 119 | 120 | /// 数据库相关操作 121 | 122 | static init_database() { 123 | DataBaseUtils.db_createDb(K_Pomodoro_Database, 1, 124 | 'CREATE TABLE ${K_Countdown_DB_Table}(id INTEGER PRIMARY KEY, title TEXT, date INTEGER, notes TEXT, push INTEGER, modify_date INTEGER)'); 125 | } 126 | 127 | static Future query_all_data(QueryType queryType) async { 128 | String order_query = queryType.value; 129 | List data = await DataBaseUtils.db_query(K_Pomodoro_Database, 130 | 'SELECT * FROM ${K_Countdown_DB_Table} order by ${order_query}'); 131 | return data; 132 | } 133 | 134 | static Future insert_data(CountdownModel model) async { 135 | int id = await DataBaseUtils.db_insert( 136 | K_Pomodoro_Database, K_Countdown_DB_Table, model.toJsonMap()); 137 | return id; 138 | //DataBaseUtils.db_add(K_Pomodoro_Database, "INSERT INTO ${K_Countdown_DB_Table}(title, date, notes, push) VALUES('${model.title}', ${model.date.millisecondsSinceEpoch}, '${model.notes}', ${model.push})"); 139 | } 140 | 141 | static Future update_data(CountdownModel model) async { 142 | 143 | //返回受影响的的数量 144 | int count = await DataBaseUtils.db_update( 145 | K_Pomodoro_Database, 146 | 'UPDATE ${K_Countdown_DB_Table} SET title = ?, date = ?, notes = ?, push = ?, modify_date = ? WHERE id = ?', 147 | [ 148 | model.title, 149 | model.date.millisecondsSinceEpoch, 150 | model.notes, 151 | model.push, 152 | model.modify_date.millisecondsSinceEpoch, 153 | model.itemId 154 | ]); 155 | return count; 156 | } 157 | 158 | static Future delete_data(CountdownModel model) async { 159 | //返回受影响的的数量,即删除的条目数量 160 | int count = await DataBaseUtils.db_delete(K_Pomodoro_Database, 161 | 'DELETE FROM ${K_Countdown_DB_Table} WHERE id = ?', [model.itemId]); 162 | return count; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /app/lib/ui/page/app_about_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:iPomodoro/common/constant/app_colors.dart'; 4 | import 'package:iPomodoro/common/utils/device_utils.dart'; 5 | import 'package:iPomodoro/config/app_config.dart'; 6 | import 'package:iPomodoro/common/channel/native_method_channel.dart'; 7 | import 'package:iPomodoro/generated/l10n.dart'; 8 | 9 | class AppAbout extends StatefulWidget { 10 | @override 11 | _AppAboutState createState() => _AppAboutState(); 12 | } 13 | 14 | class _AppAboutState extends State { 15 | String version = ''; 16 | 17 | String getCurrentYear() { 18 | var date = DateTime.now().toString(); 19 | var dateParse = DateTime.parse(date); 20 | var formattedDate = "${dateParse.year}"; 21 | return formattedDate.toString(); 22 | } 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | 28 | NativeChannel.appVersion().then((value) { 29 | print(value); 30 | if (value is String) { 31 | setState(() { 32 | version = value; 33 | }); 34 | } 35 | }); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return Scaffold( 41 | appBar: AppBar( 42 | title: Text(S.of(context).tips_app_about, style: TextStyle(color: Colors.white)), 43 | foregroundColor: Colors.white, 44 | backgroundColor: AppColors.ME_SUB_COLOR, systemOverlayStyle: SystemUiOverlayStyle.light, 45 | ), 46 | body: Container( 47 | width: double.infinity, 48 | height: double.infinity, 49 | padding: EdgeInsets.all(20), 50 | child: Column( 51 | mainAxisAlignment: MainAxisAlignment.start, 52 | crossAxisAlignment: CrossAxisAlignment.center, 53 | children: [ 54 | Container( 55 | // padding: EdgeInsets.fromLTRB(10, 30, 10, 20), 56 | width: DeviceUtils.scale_width(context, 0.25, 0.3, 0.4), 57 | child: Image.asset("assets/images/app_logo.png", 58 | fit: BoxFit.contain), 59 | ), 60 | Text( 61 | "${AppConfig.AppName}", 62 | style: TextStyle( 63 | fontSize: DeviceUtils.get_size(context, 20, 23, 25), 64 | fontWeight: FontWeight.bold), 65 | ), 66 | Text( 67 | "v ${version}", 68 | style: TextStyle( 69 | color: AppColors.isDarkMode(context) ? Colors.white24 : Colors.black54, 70 | fontSize: DeviceUtils.get_size(context, 14, 15, 18), 71 | ), 72 | ), 73 | Expanded( 74 | child: Column( 75 | mainAxisAlignment: MainAxisAlignment.center, 76 | children: [ 77 | Text( 78 | S.of(context).tips_app_desc, 79 | style: TextStyle(color: AppColors.isDarkMode(context) ? Colors.white38 : Colors.black54), 80 | ), 81 | ], 82 | )), 83 | Text( 84 | "Copyright © 2021-${getCurrentYear()} iHTCboy", 85 | style: TextStyle(color: Colors.black45), 86 | ), 87 | ], 88 | ), 89 | ), 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/lib/ui/page/brightness_settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:iPomodoro/common/channel/native_method_channel.dart'; 4 | import 'package:iPomodoro/common/constant/app_colors.dart'; 5 | import 'package:iPomodoro/generated/l10n.dart'; 6 | 7 | class BrightnessSettings extends StatefulWidget { 8 | @override 9 | _BrightnessSettingsState createState() => _BrightnessSettingsState(); 10 | } 11 | 12 | class _BrightnessSettingsState extends State { 13 | 14 | double _sliderValue = 0.0; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | NativeChannel.changeBrightness("0.5", getBrightness: "1").then((value) { 20 | if (value != null) { 21 | setState(() { 22 | _sliderValue = value; 23 | }); 24 | } 25 | }); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | appBar: AppBar( 32 | title: Text(S.of(context).set_screen_brightness, style: TextStyle(color: Colors.white)), 33 | foregroundColor: Colors.white, 34 | backgroundColor: AppColors.ME_SUB_COLOR, systemOverlayStyle: SystemUiOverlayStyle.light, 35 | ), 36 | body: Container( 37 | width: double.infinity, 38 | height: double.infinity, 39 | padding: EdgeInsets.all(20), 40 | child: Row( 41 | children: [ 42 | Icon(Icons.lightbulb_outline, color: Colors.grey,), 43 | Expanded( 44 | child: Slider( 45 | value: _sliderValue, 46 | onChanged: (data) { 47 | // print('change:$data'); 48 | setState(() { 49 | _sliderValue = data; 50 | }); 51 | }, 52 | onChangeStart: (data) { 53 | // print('start:$data'); 54 | }, 55 | onChangeEnd: (data) { 56 | // print('end:$data'); 57 | NativeChannel.changeBrightness(data.toStringAsFixed(1)); 58 | }, 59 | min: 0.0, 60 | max: 1.0, 61 | divisions: 10, 62 | label: '${_sliderValue.toStringAsFixed(1)}', 63 | activeColor: Colors.green, 64 | inactiveColor: Colors.grey, 65 | ), 66 | ), 67 | Icon(Icons.lightbulb, color: Colors.amber,), 68 | ], 69 | ), 70 | ), 71 | ); 72 | } 73 | } -------------------------------------------------------------------------------- /app/lib/ui/page/countdown_settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:iPomodoro/common/constant/app_colors.dart'; 4 | import 'package:iPomodoro/common/utils/config_storage.dart'; 5 | import 'package:iPomodoro/common/utils/device_utils.dart'; 6 | import 'package:iPomodoro/generated/l10n.dart'; 7 | import 'package:iPomodoro/ui/page/theme_style.dart'; 8 | import 'package:iPomodoro/ui/widget/custom_picker.dart'; 9 | 10 | class CountdownSettingsPage extends StatefulWidget { 11 | @override 12 | _CountdownSettingsPageState createState() => _CountdownSettingsPageState(); 13 | } 14 | 15 | class _CountdownSettingsPageState extends State { 16 | int _order_index = 0; 17 | String _order_key = ''; 18 | List sort_list = []; 19 | late Color titleBarColor = AppColors.COUNTDOWN_MAIN_COLOR; 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | _init_storage(); 25 | _set_color(); 26 | } 27 | 28 | void _init_storage() { 29 | 30 | AppStorage.getInt(AppStorage.K_STRING_COUNTDOWN_ORDER_INDEX).then((value) { 31 | setState(() { 32 | sort_list = [ 33 | S.of(context).tips_sort_id_asc, 34 | S.of(context).tips_sort_id_desc, 35 | S.of(context).tips_sort_date_asc, 36 | S.of(context).tips_sort_date_desc, 37 | S.of(context).tips_sort_modify_asc, 38 | S.of(context).tips_sort_modify_desc 39 | ]; 40 | 41 | _order_index = value ?? 0; 42 | _order_key = sort_list[_order_index]; 43 | }); 44 | }); 45 | } 46 | 47 | void _set_color() { 48 | AppStorage.getInt(AppStorage.K_STRING_COUNTDOWN_TITLE_BAR_COLOR) 49 | .then((value) { 50 | setState(() { 51 | titleBarColor = 52 | value != null ? Color(value) : AppColors.COUNTDOWN_MAIN_COLOR; 53 | }); 54 | }); 55 | } 56 | 57 | @override 58 | Widget build(BuildContext context) { 59 | return Scaffold( 60 | appBar: AppBar( 61 | title: Text(S.of(context).countdown_settings, style: TextStyle(color: Colors.white)), 62 | foregroundColor: Colors.white, 63 | backgroundColor: titleBarColor, systemOverlayStyle: SystemUiOverlayStyle.light, 64 | ), 65 | body: ListView( 66 | children: [ 67 | ListTile( 68 | leading: Text( 69 | '⛓', 70 | style: TextStyle( 71 | fontSize: DeviceUtils.get_size(context, 25, 30, 35)), 72 | ), 73 | title: Text(S.of(context).countdown_tasks_sort, 74 | style: TextStyle( 75 | fontSize: DeviceUtils.get_size(context, 17, 19, 22))), 76 | trailing: Container( 77 | height: double.infinity, 78 | width: DeviceUtils.get_size(context, 130, 140, 200), 79 | child: Row( 80 | mainAxisAlignment: MainAxisAlignment.end, 81 | crossAxisAlignment: CrossAxisAlignment.center, 82 | children: [ 83 | Text('${_order_key}', 84 | style: TextStyle( 85 | color: AppColors.TIMER_SUB_COLOR, 86 | fontSize: 87 | DeviceUtils.get_size(context, 14, 15, 18))), 88 | Icon(Icons.chevron_right, color: Colors.grey), 89 | ], 90 | )), 91 | onTap: _pressed_pomodoro_item, 92 | ), 93 | Divider(height: 1), 94 | ListTile( 95 | leading: Text( 96 | '⚙️', 97 | style: TextStyle( 98 | fontSize: DeviceUtils.get_size(context, 25, 30, 35)), 99 | ), 100 | title: Text(S.of(context).theme_style_title, 101 | style: TextStyle( 102 | fontSize: DeviceUtils.get_size(context, 17, 19, 22))), 103 | trailing: Container( 104 | height: double.infinity, 105 | width: DeviceUtils.get_size(context, 120, 120, 180), 106 | child: Row( 107 | mainAxisAlignment: MainAxisAlignment.end, 108 | crossAxisAlignment: CrossAxisAlignment.center, 109 | children: [ 110 | Icon(Icons.chevron_right, color: Colors.grey), 111 | ], 112 | )), 113 | onTap: _pressed_theme_style, 114 | ), 115 | Divider(height: 1), 116 | ], 117 | ), 118 | ); 119 | } 120 | 121 | void _pressed_pomodoro_item() { 122 | CustomPicker().show(context, sort_list, _order_index, (position) { 123 | setState(() { 124 | _order_index = position; 125 | _order_key = sort_list[position]; 126 | }); 127 | }, looping: false).then((value) { 128 | setState(() { 129 | _order_index = value; 130 | _order_key = sort_list[value]; 131 | }); 132 | AppStorage.setInt(AppStorage.K_STRING_COUNTDOWN_ORDER_INDEX, value); 133 | }); 134 | } 135 | 136 | void _pressed_theme_style() { 137 | Navigator.push( 138 | context, 139 | MaterialPageRoute( 140 | builder: (context) => ThemeStyleSettingsPage(pageType: ThemeStylePageType.Countdown), 141 | ), 142 | ).then((value) { 143 | _set_color(); 144 | }); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /app/lib/ui/page/language_settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:iPomodoro/common/constant/app_colors.dart'; 4 | import 'package:iPomodoro/common/utils/config_storage.dart'; 5 | import 'package:iPomodoro/common/utils/device_utils.dart'; 6 | import 'package:iPomodoro/generated/l10n.dart'; 7 | 8 | class LanguageSettings extends StatefulWidget { 9 | @override 10 | _LanguageSettingsState createState() => _LanguageSettingsState(); 11 | } 12 | 13 | class _LanguageSettingsState extends State { 14 | String groupValue = 'en'; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | _init_storage(); 20 | } 21 | 22 | void _init_storage() { 23 | AppStorage.getString(AppStorage.K_STRING_LANGUAGE_SETTINGS).then((value) { 24 | setState(() { 25 | //String languageCode = DeviceUtils.languageCode(); 26 | groupValue = value ?? 'en'; 27 | }); 28 | }); 29 | } 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return Scaffold( 34 | appBar: AppBar( 35 | title: Text(S.of(context).set_localizetion, style: TextStyle(color: Colors.white)), 36 | foregroundColor: Colors.white, 37 | backgroundColor: AppColors.ME_MAIN_COLOR, systemOverlayStyle: SystemUiOverlayStyle.light, 38 | ), 39 | body: ListView( 40 | children: [ 41 | RadioListTile( 42 | title: Text('中文'), 43 | value: 'zh', 44 | groupValue: groupValue, 45 | onChanged: _changed, 46 | ), 47 | Divider(height: 1), 48 | RadioListTile( 49 | title: Text('English'), 50 | value: 'en', 51 | groupValue: groupValue, 52 | onChanged: _changed), 53 | ], 54 | ), 55 | ); 56 | } 57 | 58 | void _changed(value) { 59 | if (value != null) { 60 | AppStorage.setString(AppStorage.K_STRING_LANGUAGE_SETTINGS, value); 61 | setState(() { 62 | groupValue = value; 63 | if (value == "zh") S.load(Locale('zh', '')); 64 | if (value == "en") S.load(Locale('en', 'US')); 65 | }); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/lib/ui/widget/cupertino_alert.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AlertView { 5 | static Future show(BuildContext context, String title, String content, 6 | {String cancelText='', String confirmText='OK', 7 | Color cancelTextColor=Colors.blue, Color confirmTextColor=Colors.red }) async { 8 | 9 | List actions = []; 10 | if(cancelText.isNotEmpty) { 11 | actions.add(CupertinoButton( 12 | //不能用IconButton 13 | child: Text(cancelText, 14 | style: TextStyle( 15 | color: cancelTextColor, 16 | ),), 17 | onPressed: () { 18 | Navigator.pop(context, false); //要自己dismiss 19 | })); 20 | } 21 | if(confirmText.isNotEmpty) { 22 | actions.add(CupertinoButton( 23 | child: Text(confirmText, 24 | style: TextStyle( 25 | color: confirmTextColor, 26 | ), 27 | ), 28 | onPressed: () { 29 | Navigator.pop(context, true); 30 | })); 31 | } 32 | 33 | bool ans = await showCupertinoDialog( 34 | context: context, 35 | builder: (BuildContext ctx) { 36 | return CupertinoAlertDialog( 37 | title: Text(title), 38 | content: Text(content), 39 | actions: actions); 40 | }); 41 | return ans; 42 | } 43 | } -------------------------------------------------------------------------------- /app/lib/ui/widget/custom_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:iPomodoro/generated/l10n.dart'; 4 | 5 | class CustomPicker { 6 | Future show(BuildContext context, List contentList, int selectItem, 7 | onSelectedItemChanged(int position), 8 | {bool looping = true, String title=''}) async { 9 | 10 | int? positionItem = await showModalBottomSheet( 11 | enableDrag: false, 12 | isDismissible: false, 13 | context: context, 14 | builder: (context) { 15 | int oldPosition = selectItem; 16 | int tempPosition = oldPosition; 17 | return Container( 18 | height: 250, 19 | child: Column( 20 | children: [ 21 | Container( 22 | child: Row( 23 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 24 | children: [ 25 | CupertinoButton( 26 | child: Text(S.of(context).tips_cancel), 27 | onPressed: () { 28 | Navigator.of(context).pop(oldPosition); 29 | }, 30 | ), 31 | Text(title, style: TextStyle(fontSize: 18, color: Colors.black87)), 32 | CupertinoButton( 33 | child: Text(S.of(context).tips_confirm), 34 | onPressed: () { 35 | Navigator.of(context).pop(tempPosition); 36 | }, 37 | ), 38 | ], 39 | ), 40 | ), 41 | Divider( 42 | height: 0, 43 | thickness: 1, 44 | ), 45 | Expanded( 46 | child: Container( 47 | child: CupertinoPicker( 48 | itemExtent: 35, 49 | magnification: 1.1, 50 | looping: looping, 51 | scrollController: FixedExtentScrollController(initialItem: selectItem), 52 | onSelectedItemChanged: (position) { 53 | tempPosition = position; 54 | onSelectedItemChanged(position); 55 | }, 56 | children: contentList.map((value) { 57 | return Text(value); 58 | }).toList(), 59 | ), 60 | ), 61 | ), 62 | ], 63 | ), 64 | ); 65 | }); 66 | 67 | return positionItem ?? 0; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/lib/ui/widget/privacy_policy_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:iPomodoro/generated/l10n.dart'; 3 | 4 | class PrivacyPolicyDialog { 5 | void showCustomDialog(BuildContext context, 6 | {@required Function textClickedFunction, 7 | @required Function cancelBtnFunction, 8 | @required Function agreeBtnFunction}) { 9 | showGeneralDialog( 10 | context: context, 11 | barrierDismissible: false, 12 | barrierLabel: 13 | MaterialLocalizations.of(context).modalBarrierDismissLabel, 14 | barrierColor: Colors.black45, 15 | transitionDuration: const Duration(milliseconds: 200), 16 | pageBuilder: (BuildContext buildContext, Animation animation, 17 | Animation secondaryAnimation) { 18 | return Material( 19 | type: MaterialType.transparency, 20 | child: Center( 21 | child: Container( 22 | padding: EdgeInsets.all(15), 23 | width: 280, 24 | height: 300, 25 | decoration: BoxDecoration( 26 | shape: BoxShape.rectangle, 27 | color: Colors.white, 28 | borderRadius: BorderRadius.circular(5), 29 | boxShadow: [ 30 | BoxShadow( 31 | color: Colors.black12, 32 | offset: Offset(0, 10), 33 | blurRadius: 10), 34 | ]), 35 | child: Column( 36 | children: [ 37 | Image.asset( 38 | "assets/images/app_logo.png", 39 | width: 50, 40 | height: 50, 41 | ), 42 | SizedBox( 43 | height: 15, 44 | ), 45 | Text( 46 | S.of(context).tips_text, 47 | style: TextStyle( 48 | fontSize: 22, 49 | fontWeight: FontWeight.bold, 50 | color: Colors.black87, 51 | decoration: TextDecoration.none), 52 | ), 53 | SizedBox( 54 | height: 15, 55 | ), 56 | InkWell( 57 | onTap: textClickedFunction, 58 | child: Text( 59 | S.of(context).privacy_policy_tips, 60 | style: TextStyle( 61 | fontSize: 14, 62 | color: Colors.black54, 63 | fontWeight: FontWeight.normal, 64 | decoration: TextDecoration.none), 65 | textAlign: TextAlign.center, 66 | ), 67 | ), 68 | SizedBox( 69 | height: 22, 70 | ), 71 | Row( 72 | mainAxisAlignment: MainAxisAlignment.spaceAround, 73 | children: [ 74 | TextButton( 75 | onPressed: () { 76 | Navigator.of(context).pop(); 77 | cancelBtnFunction(); 78 | }, 79 | child: Text( 80 | S.of(context).privacy_policy_reject, 81 | style: TextStyle(fontSize: 16, color: Colors.redAccent), 82 | )), 83 | TextButton( 84 | onPressed: () { 85 | Navigator.of(context).pop(); 86 | agreeBtnFunction(); 87 | }, 88 | child: Text( 89 | S.of(context).privacy_policy_agree, 90 | style: TextStyle(fontSize: 16), 91 | )), 92 | ], 93 | ), 94 | ], 95 | ), 96 | )), 97 | ); 98 | }); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /app/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.10) 3 | project(runner LANGUAGES CXX) 4 | 5 | # The name of the executable created for the application. Change this to change 6 | # the on-disk name of your application. 7 | set(BINARY_NAME "app") 8 | # The unique GTK application identifier for this application. See: 9 | # https://wiki.gnome.org/HowDoI/ChooseApplicationID 10 | set(APPLICATION_ID "com.iHTCboy.app") 11 | 12 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 13 | # versions of CMake. 14 | cmake_policy(SET CMP0063 NEW) 15 | 16 | # Load bundled libraries from the lib/ directory relative to the binary. 17 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 18 | 19 | # Root filesystem for cross-building. 20 | if(FLUTTER_TARGET_PLATFORM_SYSROOT) 21 | set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) 22 | set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) 23 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 24 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 25 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 26 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 27 | endif() 28 | 29 | # Define build configuration options. 30 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 31 | set(CMAKE_BUILD_TYPE "Debug" CACHE 32 | STRING "Flutter build mode" FORCE) 33 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 34 | "Debug" "Profile" "Release") 35 | endif() 36 | 37 | # Compilation settings that should be applied to most targets. 38 | # 39 | # Be cautious about adding new options here, as plugins use this function by 40 | # default. In most cases, you should add new options to specific targets instead 41 | # of modifying this function. 42 | function(APPLY_STANDARD_SETTINGS TARGET) 43 | target_compile_features(${TARGET} PUBLIC cxx_std_14) 44 | target_compile_options(${TARGET} PRIVATE -Wall -Werror) 45 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") 46 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") 47 | endfunction() 48 | 49 | # Flutter library and tool build rules. 50 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 51 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 52 | 53 | # System-level dependencies. 54 | find_package(PkgConfig REQUIRED) 55 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 56 | 57 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 58 | 59 | # Define the application target. To change its name, change BINARY_NAME above, 60 | # not the value here, or `flutter run` will no longer work. 61 | # 62 | # Any new source files that you add to the application should be added here. 63 | add_executable(${BINARY_NAME} 64 | "main.cc" 65 | "my_application.cc" 66 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 67 | ) 68 | 69 | # Apply the standard set of build settings. This can be removed for applications 70 | # that need different build settings. 71 | apply_standard_settings(${BINARY_NAME}) 72 | 73 | # Add dependency libraries. Add any application-specific dependencies here. 74 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 75 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 76 | 77 | # Run the Flutter tool portions of the build. This must not be removed. 78 | add_dependencies(${BINARY_NAME} flutter_assemble) 79 | 80 | # Only the install-generated bundle's copy of the executable will launch 81 | # correctly, since the resources must in the right relative locations. To avoid 82 | # people trying to run the unbundled copy, put it in a subdirectory instead of 83 | # the default top-level location. 84 | set_target_properties(${BINARY_NAME} 85 | PROPERTIES 86 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" 87 | ) 88 | 89 | # Generated plugin build rules, which manage building the plugins and adding 90 | # them to the application. 91 | include(flutter/generated_plugins.cmake) 92 | 93 | 94 | # === Installation === 95 | # By default, "installing" just makes a relocatable bundle in the build 96 | # directory. 97 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") 98 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 99 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 100 | endif() 101 | 102 | # Start with a clean build bundle directory every time. 103 | install(CODE " 104 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") 105 | " COMPONENT Runtime) 106 | 107 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 108 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 109 | 110 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 111 | COMPONENT Runtime) 112 | 113 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 114 | COMPONENT Runtime) 115 | 116 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 117 | COMPONENT Runtime) 118 | 119 | foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) 120 | install(FILES "${bundled_library}" 121 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 122 | COMPONENT Runtime) 123 | endforeach(bundled_library) 124 | 125 | # Fully re-copy the assets directory on each build to avoid having stale files 126 | # from a previous install. 127 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 128 | install(CODE " 129 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 130 | " COMPONENT Runtime) 131 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 132 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 133 | 134 | # Install the AOT library on non-Debug builds only. 135 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") 136 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 137 | COMPONENT Runtime) 138 | endif() 139 | -------------------------------------------------------------------------------- /app/linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.10) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | 12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 13 | # which isn't available in 3.10. 14 | function(list_prepend LIST_NAME PREFIX) 15 | set(NEW_LIST "") 16 | foreach(element ${${LIST_NAME}}) 17 | list(APPEND NEW_LIST "${PREFIX}${element}") 18 | endforeach(element) 19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 20 | endfunction() 21 | 22 | # === Flutter Library === 23 | # System-level dependencies. 24 | find_package(PkgConfig REQUIRED) 25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 28 | 29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 30 | 31 | # Published to parent scope for install step. 32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 36 | 37 | list(APPEND FLUTTER_LIBRARY_HEADERS 38 | "fl_basic_message_channel.h" 39 | "fl_binary_codec.h" 40 | "fl_binary_messenger.h" 41 | "fl_dart_project.h" 42 | "fl_engine.h" 43 | "fl_json_message_codec.h" 44 | "fl_json_method_codec.h" 45 | "fl_message_codec.h" 46 | "fl_method_call.h" 47 | "fl_method_channel.h" 48 | "fl_method_codec.h" 49 | "fl_method_response.h" 50 | "fl_plugin_registrar.h" 51 | "fl_plugin_registry.h" 52 | "fl_standard_message_codec.h" 53 | "fl_standard_method_codec.h" 54 | "fl_string_codec.h" 55 | "fl_value.h" 56 | "fl_view.h" 57 | "flutter_linux.h" 58 | ) 59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 60 | add_library(flutter INTERFACE) 61 | target_include_directories(flutter INTERFACE 62 | "${EPHEMERAL_DIR}" 63 | ) 64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 65 | target_link_libraries(flutter INTERFACE 66 | PkgConfig::GTK 67 | PkgConfig::GLIB 68 | PkgConfig::GIO 69 | ) 70 | add_dependencies(flutter flutter_assemble) 71 | 72 | # === Flutter tool backend === 73 | # _phony_ is a non-existent file to force this command to run every time, 74 | # since currently there's no way to get a full input/output list from the 75 | # flutter tool. 76 | add_custom_command( 77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 79 | COMMAND ${CMAKE_COMMAND} -E env 80 | ${FLUTTER_TOOL_ENVIRONMENT} 81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} 83 | VERBATIM 84 | ) 85 | add_custom_target(flutter_assemble DEPENDS 86 | "${FLUTTER_LIBRARY}" 87 | ${FLUTTER_LIBRARY_HEADERS} 88 | ) 89 | -------------------------------------------------------------------------------- /app/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | 12 | void fl_register_plugins(FlPluginRegistry* registry) { 13 | g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = 14 | fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); 15 | audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); 16 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 17 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 18 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 19 | } 20 | -------------------------------------------------------------------------------- /app/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /app/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | audioplayers_linux 7 | url_launcher_linux 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /app/linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /app/linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication { 11 | GtkApplication parent_instance; 12 | char** dart_entrypoint_arguments; 13 | }; 14 | 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 16 | 17 | // Implements GApplication::activate. 18 | static void my_application_activate(GApplication* application) { 19 | MyApplication* self = MY_APPLICATION(application); 20 | GtkWindow* window = 21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 22 | 23 | // Use a header bar when running in GNOME as this is the common style used 24 | // by applications and is the setup most users will be using (e.g. Ubuntu 25 | // desktop). 26 | // If running on X and not using GNOME then just use a traditional title bar 27 | // in case the window manager does more exotic layout, e.g. tiling. 28 | // If running on Wayland assume the header bar will work (may need changing 29 | // if future cases occur). 30 | gboolean use_header_bar = TRUE; 31 | #ifdef GDK_WINDOWING_X11 32 | GdkScreen* screen = gtk_window_get_screen(window); 33 | if (GDK_IS_X11_SCREEN(screen)) { 34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); 35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) { 36 | use_header_bar = FALSE; 37 | } 38 | } 39 | #endif 40 | if (use_header_bar) { 41 | GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 42 | gtk_widget_show(GTK_WIDGET(header_bar)); 43 | gtk_header_bar_set_title(header_bar, "app"); 44 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 46 | } else { 47 | gtk_window_set_title(window, "app"); 48 | } 49 | 50 | gtk_window_set_default_size(window, 1280, 720); 51 | gtk_widget_show(GTK_WIDGET(window)); 52 | 53 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 54 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 55 | 56 | FlView* view = fl_view_new(project); 57 | gtk_widget_show(GTK_WIDGET(view)); 58 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 59 | 60 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 61 | 62 | gtk_widget_grab_focus(GTK_WIDGET(view)); 63 | } 64 | 65 | // Implements GApplication::local_command_line. 66 | static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { 67 | MyApplication* self = MY_APPLICATION(application); 68 | // Strip out the first argument as it is the binary name. 69 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 70 | 71 | g_autoptr(GError) error = nullptr; 72 | if (!g_application_register(application, nullptr, &error)) { 73 | g_warning("Failed to register: %s", error->message); 74 | *exit_status = 1; 75 | return TRUE; 76 | } 77 | 78 | g_application_activate(application); 79 | *exit_status = 0; 80 | 81 | return TRUE; 82 | } 83 | 84 | // Implements GObject::dispose. 85 | static void my_application_dispose(GObject* object) { 86 | MyApplication* self = MY_APPLICATION(object); 87 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 88 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 89 | } 90 | 91 | static void my_application_class_init(MyApplicationClass* klass) { 92 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 93 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 94 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 95 | } 96 | 97 | static void my_application_init(MyApplication* self) {} 98 | 99 | MyApplication* my_application_new() { 100 | return MY_APPLICATION(g_object_new(my_application_get_type(), 101 | "application-id", APPLICATION_ID, 102 | "flags", G_APPLICATION_NON_UNIQUE, 103 | nullptr)); 104 | } 105 | -------------------------------------------------------------------------------- /app/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /app/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /app/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /app/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /app/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import audioplayers_darwin 9 | import flutter_local_notifications 10 | import path_provider_foundation 11 | import shared_preferences_foundation 12 | import sqflite_darwin 13 | import url_launcher_macos 14 | 15 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 16 | AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) 17 | FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) 18 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 19 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 20 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 21 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 22 | } 23 | -------------------------------------------------------------------------------- /app/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /app/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /app/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = app 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.iHTCboy.app 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.iHTCboy. All rights reserved. 15 | -------------------------------------------------------------------------------- /app/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /app/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /app/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /app/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: iPomodoro 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 4.0.2+250320 19 | 20 | environment: 21 | sdk: ^3.5.1 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | flutter_localizations: 27 | sdk: flutter 28 | 29 | # The following adds the Cupertino Icons font to your application. 30 | # Use with the CupertinoIcons class for iOS style icons. 31 | cupertino_icons: ^1.0.8 32 | shared_preferences: ^2.2.2 33 | flutter_slidable: ^3.1.1 34 | sqflite: ^2.3.0 35 | url_launcher: ^6.2.1 36 | flutter_local_notifications: ^19.0.0 37 | audioplayers: ^5.2.1 38 | flex_color_picker: ^3.5.1 39 | 40 | dev_dependencies: 41 | flutter_test: 42 | sdk: flutter 43 | 44 | # For information on the generic Dart part of this file, see the 45 | # following page: https://dart.dev/tools/pub/pubspec 46 | # The following section is specific to Flutter. 47 | flutter: 48 | 49 | # The following line ensures that the Material Icons font is 50 | # included with your application, so that you can use the icons in 51 | # the material Icons class. 52 | uses-material-design: true 53 | 54 | # To add assets to your application, add an assets section, like this: 55 | assets: 56 | - assets/images/ 57 | - assets/musics/ 58 | # - images/a_dot_burr.jpeg 59 | # - images/a_dot_ham.jpeg 60 | # An image asset can refer to one or more resolution-specific "variants", see 61 | # https://flutter.dev/assets-and-images/#resolution-aware. 62 | # For details regarding adding assets from package dependencies, see 63 | # https://flutter.dev/assets-and-images/#from-packages 64 | # To add custom fonts to your application, add a fonts section here, 65 | # in this "flutter" section. Each entry in this list should have a 66 | # "family" key with the font family name, and a "fonts" key with a 67 | # list giving the asset and other descriptors for the font. For 68 | # example: 69 | fonts: 70 | - family: ChakraPetch 71 | fonts: 72 | - asset: assets/fonts/ChakraPetch-Light.ttf 73 | - asset: assets/fonts/ChakraPetch-Regular.ttf 74 | - asset: assets/fonts/ChakraPetch-Bold.ttf 75 | - asset: assets/fonts/ChakraPetch-SemiBold.ttf 76 | # [Chakra Petch - Google Fonts](https://fonts.google.com/specimen/Chakra+Petch) 77 | - family: Ma_Shan_Zheng 78 | fonts: 79 | - asset: assets/fonts/MaShanZheng-Regular.ttf 80 | # [Ma Shan Zheng - Google Fonts](https://fonts.google.com/specimen/Ma+Shan+Zheng) 81 | - family: Noto_Sans_TC 82 | fonts: 83 | - asset: assets/fonts/NotoSansTC-Bold.otf 84 | # [ZCOOL KuaiLe - Google Fonts](https://fonts.google.com/specimen/Noto+Sans+TC) 85 | # For details regarding fonts from package dependencies, 86 | # see https://flutter.dev/custom-fonts/#from-packages 87 | flutter_intl: 88 | enabled: true 89 | -------------------------------------------------------------------------------- /app/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:iPomodoro/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /app/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/web/favicon.png -------------------------------------------------------------------------------- /app/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/web/icons/Icon-192.png -------------------------------------------------------------------------------- /app/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/web/icons/Icon-512.png -------------------------------------------------------------------------------- /app/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /app/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /app/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | app 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "short_name": "app", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /app/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /app/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.14) 3 | project(app LANGUAGES CXX) 4 | 5 | # The name of the executable created for the application. Change this to change 6 | # the on-disk name of your application. 7 | set(BINARY_NAME "app") 8 | 9 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 10 | # versions of CMake. 11 | cmake_policy(SET CMP0063 NEW) 12 | 13 | # Define build configuration option. 14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 15 | if(IS_MULTICONFIG) 16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 17 | CACHE STRING "" FORCE) 18 | else() 19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 20 | set(CMAKE_BUILD_TYPE "Debug" CACHE 21 | STRING "Flutter build mode" FORCE) 22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 23 | "Debug" "Profile" "Release") 24 | endif() 25 | endif() 26 | # Define settings for the Profile build mode. 27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 31 | 32 | # Use Unicode for all projects. 33 | add_definitions(-DUNICODE -D_UNICODE) 34 | 35 | # Compilation settings that should be applied to most targets. 36 | # 37 | # Be cautious about adding new options here, as plugins use this function by 38 | # default. In most cases, you should add new options to specific targets instead 39 | # of modifying this function. 40 | function(APPLY_STANDARD_SETTINGS TARGET) 41 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 42 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") 43 | target_compile_options(${TARGET} PRIVATE /EHsc) 44 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 45 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 46 | endfunction() 47 | 48 | # Flutter library and tool build rules. 49 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 50 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 51 | 52 | # Application build; see runner/CMakeLists.txt. 53 | add_subdirectory("runner") 54 | 55 | # Generated plugin build rules, which manage building the plugins and adding 56 | # them to the application. 57 | include(flutter/generated_plugins.cmake) 58 | 59 | 60 | # === Installation === 61 | # Support files are copied into place next to the executable, so that it can 62 | # run in place. This is done instead of making a separate bundle (as on Linux) 63 | # so that building and running from within Visual Studio will work. 64 | set(BUILD_BUNDLE_DIR "$") 65 | # Make the "install" step default, as it's required to run. 66 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) 67 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 68 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 69 | endif() 70 | 71 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 72 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") 73 | 74 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 75 | COMPONENT Runtime) 76 | 77 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 78 | COMPONENT Runtime) 79 | 80 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 81 | COMPONENT Runtime) 82 | 83 | if(PLUGIN_BUNDLED_LIBRARIES) 84 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 85 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 86 | COMPONENT Runtime) 87 | endif() 88 | 89 | # Fully re-copy the assets directory on each build to avoid having stale files 90 | # from a previous install. 91 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 92 | install(CODE " 93 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 94 | " COMPONENT Runtime) 95 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 96 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 97 | 98 | # Install the AOT library on non-Debug builds only. 99 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 100 | CONFIGURATIONS Profile;Release 101 | COMPONENT Runtime) 102 | -------------------------------------------------------------------------------- /app/windows/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.14) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") 12 | 13 | # === Flutter Library === 14 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") 15 | 16 | # Published to parent scope for install step. 17 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 18 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 19 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 20 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) 21 | 22 | list(APPEND FLUTTER_LIBRARY_HEADERS 23 | "flutter_export.h" 24 | "flutter_windows.h" 25 | "flutter_messenger.h" 26 | "flutter_plugin_registrar.h" 27 | "flutter_texture_registrar.h" 28 | ) 29 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") 30 | add_library(flutter INTERFACE) 31 | target_include_directories(flutter INTERFACE 32 | "${EPHEMERAL_DIR}" 33 | ) 34 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") 35 | add_dependencies(flutter flutter_assemble) 36 | 37 | # === Wrapper === 38 | list(APPEND CPP_WRAPPER_SOURCES_CORE 39 | "core_implementations.cc" 40 | "standard_codec.cc" 41 | ) 42 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") 43 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN 44 | "plugin_registrar.cc" 45 | ) 46 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") 47 | list(APPEND CPP_WRAPPER_SOURCES_APP 48 | "flutter_engine.cc" 49 | "flutter_view_controller.cc" 50 | ) 51 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") 52 | 53 | # Wrapper sources needed for a plugin. 54 | add_library(flutter_wrapper_plugin STATIC 55 | ${CPP_WRAPPER_SOURCES_CORE} 56 | ${CPP_WRAPPER_SOURCES_PLUGIN} 57 | ) 58 | apply_standard_settings(flutter_wrapper_plugin) 59 | set_target_properties(flutter_wrapper_plugin PROPERTIES 60 | POSITION_INDEPENDENT_CODE ON) 61 | set_target_properties(flutter_wrapper_plugin PROPERTIES 62 | CXX_VISIBILITY_PRESET hidden) 63 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) 64 | target_include_directories(flutter_wrapper_plugin PUBLIC 65 | "${WRAPPER_ROOT}/include" 66 | ) 67 | add_dependencies(flutter_wrapper_plugin flutter_assemble) 68 | 69 | # Wrapper sources needed for the runner. 70 | add_library(flutter_wrapper_app STATIC 71 | ${CPP_WRAPPER_SOURCES_CORE} 72 | ${CPP_WRAPPER_SOURCES_APP} 73 | ) 74 | apply_standard_settings(flutter_wrapper_app) 75 | target_link_libraries(flutter_wrapper_app PUBLIC flutter) 76 | target_include_directories(flutter_wrapper_app PUBLIC 77 | "${WRAPPER_ROOT}/include" 78 | ) 79 | add_dependencies(flutter_wrapper_app flutter_assemble) 80 | 81 | # === Flutter tool backend === 82 | # _phony_ is a non-existent file to force this command to run every time, 83 | # since currently there's no way to get a full input/output list from the 84 | # flutter tool. 85 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") 86 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) 87 | add_custom_command( 88 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 89 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} 90 | ${CPP_WRAPPER_SOURCES_APP} 91 | ${PHONY_OUTPUT} 92 | COMMAND ${CMAKE_COMMAND} -E env 93 | ${FLUTTER_TOOL_ENVIRONMENT} 94 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" 95 | windows-x64 $ 96 | VERBATIM 97 | ) 98 | add_custom_target(flutter_assemble DEPENDS 99 | "${FLUTTER_LIBRARY}" 100 | ${FLUTTER_LIBRARY_HEADERS} 101 | ${CPP_WRAPPER_SOURCES_CORE} 102 | ${CPP_WRAPPER_SOURCES_PLUGIN} 103 | ${CPP_WRAPPER_SOURCES_APP} 104 | ) 105 | -------------------------------------------------------------------------------- /app/windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | 12 | void RegisterPlugins(flutter::PluginRegistry* registry) { 13 | AudioplayersWindowsPluginRegisterWithRegistrar( 14 | registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); 15 | UrlLauncherWindowsRegisterWithRegistrar( 16 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 17 | } 18 | -------------------------------------------------------------------------------- /app/windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /app/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | audioplayers_windows 7 | url_launcher_windows 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | flutter_local_notifications_windows 12 | ) 13 | 14 | set(PLUGIN_BUNDLED_LIBRARIES) 15 | 16 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 17 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 18 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 21 | endforeach(plugin) 22 | 23 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 24 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 26 | endforeach(ffi_plugin) 27 | -------------------------------------------------------------------------------- /app/windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 37 | 38 | # Run the Flutter tool portions of the build. This must not be removed. 39 | add_dependencies(${BINARY_NAME} flutter_assemble) 40 | -------------------------------------------------------------------------------- /app/windows/runner/Runner.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | #include "resource.h" 5 | 6 | #define APSTUDIO_READONLY_SYMBOLS 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // 9 | // Generated from the TEXTINCLUDE 2 resource. 10 | // 11 | #include "winres.h" 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | #undef APSTUDIO_READONLY_SYMBOLS 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | // English (United States) resources 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Icon 51 | // 52 | 53 | // Icon with lowest ID value placed first to ensure application icon 54 | // remains consistent on all systems. 55 | IDI_APP_ICON ICON "resources\\app_icon.ico" 56 | 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Version 61 | // 62 | 63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) 64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0,0 67 | #endif 68 | 69 | #if defined(FLUTTER_VERSION) 70 | #define VERSION_AS_STRING FLUTTER_VERSION 71 | #else 72 | #define VERSION_AS_STRING "1.0.0" 73 | #endif 74 | 75 | VS_VERSION_INFO VERSIONINFO 76 | FILEVERSION VERSION_AS_NUMBER 77 | PRODUCTVERSION VERSION_AS_NUMBER 78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 79 | #ifdef _DEBUG 80 | FILEFLAGS VS_FF_DEBUG 81 | #else 82 | FILEFLAGS 0x0L 83 | #endif 84 | FILEOS VOS__WINDOWS32 85 | FILETYPE VFT_APP 86 | FILESUBTYPE 0x0L 87 | BEGIN 88 | BLOCK "StringFileInfo" 89 | BEGIN 90 | BLOCK "040904e4" 91 | BEGIN 92 | VALUE "CompanyName", "com.iHTCboy" "\0" 93 | VALUE "FileDescription", "app" "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "app" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2023 com.iHTCboy. All rights reserved." "\0" 97 | VALUE "OriginalFilename", "app.exe" "\0" 98 | VALUE "ProductName", "app" "\0" 99 | VALUE "ProductVersion", VERSION_AS_STRING "\0" 100 | END 101 | END 102 | BLOCK "VarFileInfo" 103 | BEGIN 104 | VALUE "Translation", 0x409, 1252 105 | END 106 | END 107 | 108 | #endif // English (United States) resources 109 | ///////////////////////////////////////////////////////////////////////////// 110 | 111 | 112 | 113 | #ifndef APSTUDIO_INVOKED 114 | ///////////////////////////////////////////////////////////////////////////// 115 | // 116 | // Generated from the TEXTINCLUDE 3 resource. 117 | // 118 | 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | #endif // not APSTUDIO_INVOKED 122 | -------------------------------------------------------------------------------- /app/windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | return true; 30 | } 31 | 32 | void FlutterWindow::OnDestroy() { 33 | if (flutter_controller_) { 34 | flutter_controller_ = nullptr; 35 | } 36 | 37 | Win32Window::OnDestroy(); 38 | } 39 | 40 | LRESULT 41 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 42 | WPARAM const wparam, 43 | LPARAM const lparam) noexcept { 44 | // Give Flutter, including plugins, an opportunity to handle window messages. 45 | if (flutter_controller_) { 46 | std::optional result = 47 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 48 | lparam); 49 | if (result) { 50 | return *result; 51 | } 52 | } 53 | 54 | switch (message) { 55 | case WM_FONTCHANGE: 56 | flutter_controller_->engine()->ReloadSystemFonts(); 57 | break; 58 | } 59 | 60 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 61 | } 62 | -------------------------------------------------------------------------------- /app/windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /app/windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.CreateAndShow(L"app", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /app/windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /app/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/app/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /app/windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | std::string utf8_string; 52 | if (target_length == 0 || target_length > utf8_string.max_size()) { 53 | return utf8_string; 54 | } 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /app/windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /app/windows/runner/win32_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_WIN32_WINDOW_H_ 2 | #define RUNNER_WIN32_WINDOW_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be 11 | // inherited from by classes that wish to specialize with custom 12 | // rendering and input handling 13 | class Win32Window { 14 | public: 15 | struct Point { 16 | unsigned int x; 17 | unsigned int y; 18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {} 19 | }; 20 | 21 | struct Size { 22 | unsigned int width; 23 | unsigned int height; 24 | Size(unsigned int width, unsigned int height) 25 | : width(width), height(height) {} 26 | }; 27 | 28 | Win32Window(); 29 | virtual ~Win32Window(); 30 | 31 | // Creates and shows a win32 window with |title| and position and size using 32 | // |origin| and |size|. New windows are created on the default monitor. Window 33 | // sizes are specified to the OS in physical pixels, hence to ensure a 34 | // consistent size to will treat the width height passed in to this function 35 | // as logical pixels and scale to appropriate for the default monitor. Returns 36 | // true if the window was created successfully. 37 | bool CreateAndShow(const std::wstring& title, 38 | const Point& origin, 39 | const Size& size); 40 | 41 | // Release OS resources associated with window. 42 | void Destroy(); 43 | 44 | // Inserts |content| into the window tree. 45 | void SetChildContent(HWND content); 46 | 47 | // Returns the backing Window handle to enable clients to set icon and other 48 | // window properties. Returns nullptr if the window has been destroyed. 49 | HWND GetHandle(); 50 | 51 | // If true, closing this window will quit the application. 52 | void SetQuitOnClose(bool quit_on_close); 53 | 54 | // Return a RECT representing the bounds of the current client area. 55 | RECT GetClientArea(); 56 | 57 | protected: 58 | // Processes and route salient window messages for mouse handling, 59 | // size change and DPI. Delegates handling of these to member overloads that 60 | // inheriting classes can handle. 61 | virtual LRESULT MessageHandler(HWND window, 62 | UINT const message, 63 | WPARAM const wparam, 64 | LPARAM const lparam) noexcept; 65 | 66 | // Called when CreateAndShow is called, allowing subclass window-related 67 | // setup. Subclasses should return false if setup fails. 68 | virtual bool OnCreate(); 69 | 70 | // Called when Destroy is called. 71 | virtual void OnDestroy(); 72 | 73 | private: 74 | friend class WindowClassRegistrar; 75 | 76 | // OS callback called by message pump. Handles the WM_NCCREATE message which 77 | // is passed when the non-client area is being created and enables automatic 78 | // non-client DPI scaling so that the non-client area automatically 79 | // responsponds to changes in DPI. All other messages are handled by 80 | // MessageHandler. 81 | static LRESULT CALLBACK WndProc(HWND const window, 82 | UINT const message, 83 | WPARAM const wparam, 84 | LPARAM const lparam) noexcept; 85 | 86 | // Retrieves a class instance pointer for |window| 87 | static Win32Window* GetThisFromHandle(HWND const window) noexcept; 88 | 89 | bool quit_on_close_ = false; 90 | 91 | // window handle for top level window. 92 | HWND window_handle_ = nullptr; 93 | 94 | // window handle for hosted content. 95 | HWND child_content_ = nullptr; 96 | }; 97 | 98 | #endif // RUNNER_WIN32_WINDOW_H_ 99 | -------------------------------------------------------------------------------- /gen/GradleException.groovy: -------------------------------------------------------------------------------- 1 | class GradleException { 2 | GradleException(java.lang.String string) { 3 | 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/logo.png -------------------------------------------------------------------------------- /screenshot/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/screenshot/01.png -------------------------------------------------------------------------------- /screenshot/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/screenshot/02.png -------------------------------------------------------------------------------- /screenshot/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/screenshot/03.png -------------------------------------------------------------------------------- /screenshot/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/screenshot/04.png -------------------------------------------------------------------------------- /screenshot/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/screenshot/05.png -------------------------------------------------------------------------------- /screenshot/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/screenshot/06.png -------------------------------------------------------------------------------- /screenshot/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iHTCboy/iPomodoro-Flutter/3a05ca4f01bc1f9bc1c1d8a9cb63da54876d6634/screenshot/07.png --------------------------------------------------------------------------------