├── .github ├── FUNDING.yml ├── actions │ └── setup_jdk │ │ └── action.yml └── workflows │ ├── release_for_android.yaml │ ├── release_for_appimage.yml │ ├── release_for_linux.yml │ └── release_for_windows.yml ├── .gitignore ├── .gitmodules ├── .metadata ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── XDYou-Poster.jpg ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── ic_launcher-playstore.png │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── github │ │ │ │ └── benderblog │ │ │ │ └── traintime_pda │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── model │ │ │ │ ├── ClassTableModels.kt │ │ │ │ └── ClassTableWidgetModels.kt │ │ │ │ └── widget │ │ │ │ └── classtable │ │ │ │ ├── ClassTableDataHolder.kt │ │ │ │ ├── ClassTableWidget.kt │ │ │ │ ├── ClassTableWidgetDataProvider.kt │ │ │ │ ├── ClassTableWidgetReceiver.kt │ │ │ │ └── ToggleDayAction.kt │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ └── splash.png │ │ │ ├── drawable-mdpi │ │ │ └── splash.png │ │ │ ├── drawable-v21 │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-xhdpi │ │ │ └── splash.png │ │ │ ├── drawable-xxhdpi │ │ │ └── splash.png │ │ │ ├── drawable-xxxhdpi │ │ │ └── splash.png │ │ │ ├── drawable │ │ │ ├── background.png │ │ │ ├── ic_classtable_error.xml │ │ │ ├── ic_classtable_no_course.xml │ │ │ ├── ic_classtable_refresh.xml │ │ │ ├── ic_next_day.xml │ │ │ ├── ic_prev_day.xml │ │ │ └── launch_background.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.webp │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.webp │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.webp │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.webp │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.webp │ │ │ ├── ic_launcher_foreground.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── values-night-v31 │ │ │ └── styles.xml │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ ├── values-v31 │ │ │ └── styles.xml │ │ │ ├── values-zh │ │ │ └── strings.xml │ │ │ ├── values │ │ │ ├── ic_launcher_background.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ ├── classtable_widget_config.xml │ │ │ └── network_security_config.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── Icon-App-iTunes-Background.png ├── Icon-App-iTunes.png ├── README.MD ├── art │ ├── CP1919.svg.vec │ ├── aboutRobots-icon.png │ ├── pda_classtable_empty.png │ ├── pda_empty_cover.jpg │ ├── pda_girl_default.png │ ├── pda_girl_default_ver1.png │ ├── pda_girl_default_ver2.png │ ├── pda_girl_reading.png │ ├── pda_girl_reading_ver1.png │ └── pda_girl_singing.png ├── captcha-solver-payment.tflite ├── captcha-solver-zfw.tflite ├── flutter_i18n │ ├── en_US.yaml │ ├── s2cfbb.py │ ├── s2tw.py │ ├── zh_CN.yaml │ └── zh_TW.yaml ├── guide │ ├── README.html │ └── img │ │ ├── 010.png │ │ ├── 011.png │ │ ├── 012.png │ │ ├── 013.png │ │ ├── 015.png │ │ ├── 016.png │ │ ├── 017.png │ │ ├── 021.png │ │ ├── 022.png │ │ ├── 023.png │ │ ├── 024.png │ │ ├── 026.png │ │ ├── 028.png │ │ ├── 029.png │ │ ├── 030.png │ │ ├── 031.png │ │ ├── 032.png │ │ ├── 034.png │ │ ├── 035.png │ │ ├── 037.png │ │ ├── 042.png │ │ ├── 043.png │ │ ├── 044.jpeg │ │ ├── 045.png │ │ ├── 046.png │ │ ├── 047.png │ │ ├── 052.png │ │ ├── 054.png │ │ ├── 055.png │ │ ├── 056.png │ │ ├── 057.png │ │ ├── 058.png │ │ ├── 059.jpeg │ │ ├── 060.jpeg │ │ ├── 061.png │ │ ├── 062.jpeg │ │ ├── 063.jpeg │ │ ├── 064.png │ │ ├── 066.png │ │ ├── 067.png │ │ ├── 068.png │ │ ├── 070.png │ │ ├── 071.jpg │ │ ├── 072.png │ │ └── 073.png ├── icon.png └── random │ ├── CP1919.svg │ ├── Credit-1.jpg │ ├── Credit-2.jpg │ ├── Ray.jpg │ ├── ZCWzy-MPL-License.jpg │ └── xdyou_girl.png ├── blobs ├── libtensorflowlite_c-linux.so ├── libtensorflowlite_c-macos.dylib └── libtensorflowlite_c-win.dll ├── devtools_options.yaml ├── doc └── 数据结构.md ├── fastlane └── metadata │ └── android │ ├── en-US │ ├── changelogs │ │ ├── 1.txt │ │ ├── 10.txt │ │ ├── 12.txt │ │ ├── 19.txt │ │ ├── 2.txt │ │ ├── 203.txt │ │ ├── 233.txt │ │ ├── 243.txt │ │ ├── 253.txt │ │ ├── 263.txt │ │ ├── 273.txt │ │ ├── 283.txt │ │ ├── 293.txt │ │ ├── 4.txt │ │ ├── 5.txt │ │ ├── 6.txt │ │ ├── 7.txt │ │ ├── 8.txt │ │ └── 9.txt │ ├── full_description.txt │ ├── images │ │ └── icon.png │ ├── short_description.txt │ └── title.txt │ └── zh-CN │ ├── changelogs │ ├── 1.txt │ ├── 10.txt │ ├── 12.txt │ ├── 19.txt │ ├── 2.txt │ ├── 203.txt │ ├── 233.txt │ ├── 243.txt │ ├── 253.txt │ ├── 263.txt │ ├── 273.txt │ ├── 283.txt │ ├── 293.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt ├── ios ├── .gitignore ├── ClasstableWidget │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── WidgetBackground.colorset │ │ │ └── Contents.json │ ├── ClasstableModel.swift │ ├── ClasstableWidget.swift │ ├── ClasstableWidgetBundle.swift │ ├── ColorList.swift │ ├── EventItem.swift │ ├── ExamModule.swift │ ├── ExperimentModel.swift │ ├── HexToColor.swift │ ├── Info.plist │ ├── IsTomorrowIntent.swift │ └── Localizable.xcstrings ├── ClasstableWidgetExtension.entitlements ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── PartnerShareExtension │ ├── Base.lproj │ │ └── MainInterface.storyboard │ ├── Info.plist │ ├── PartnerShareExtension.entitlements │ ├── ShareViewController.swift │ ├── en.lproj │ │ └── MainInterface.strings │ ├── zh-Hans.lproj │ │ └── MainInterface.strings │ └── zh-Hant.lproj │ │ └── MainInterface.strings ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── Runner │ ├── ApiImplementation.swift │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ ├── LaunchBackground.imageset │ │ │ ├── Contents.json │ │ │ └── xdyou_girl.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── xdyou_icon_handwritten_original.png │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── Runner-Bridging-Header.h │ ├── Runner.entitlements │ ├── SaveToGroupID.g.swift │ ├── en.lproj │ │ ├── LaunchScreen.strings │ │ └── Main.strings │ ├── zh-Hans.lproj │ │ ├── LaunchScreen.strings │ │ └── Main.strings │ └── zh-Hant.lproj │ │ ├── LaunchScreen.strings │ │ └── Main.strings └── RunnerTests │ └── RunnerTests.swift ├── lib ├── bridge │ └── save_to_groupid.g.dart ├── controller │ ├── classtable_controller.dart │ ├── exam_controller.dart │ ├── experiment_controller.dart │ └── theme_controller.dart ├── main.dart ├── model │ ├── home_arrangement.dart │ ├── home_arrangement.g.dart │ ├── message │ │ ├── message.dart │ │ └── message.g.dart │ ├── telephone.dart │ ├── toolbox_addresses.dart │ ├── xdu_planet │ │ ├── xdu_planet.dart │ │ └── xdu_planet.g.dart │ ├── xidian_ids │ │ ├── classtable.dart │ │ ├── classtable.g.dart │ │ ├── creative.dart │ │ ├── electricity.dart │ │ ├── electricity.g.dart │ │ ├── empty_classroom.dart │ │ ├── exam.dart │ │ ├── exam.g.dart │ │ ├── experiment.dart │ │ ├── experiment.g.dart │ │ ├── library.dart │ │ ├── library.g.dart │ │ ├── network_usage.dart │ │ ├── paid_record.dart │ │ ├── score.dart │ │ └── score.g.dart │ └── xidian_sport │ │ ├── punch.dart │ │ ├── score.dart │ │ └── sport_class.dart ├── page │ ├── classtable │ │ ├── arrangement_detail │ │ │ ├── arrangement_detail.dart │ │ │ ├── arrangement_detail_state.dart │ │ │ ├── arrangement_list.dart │ │ │ ├── course_detail_card.dart │ │ │ ├── custom_list_tile.dart │ │ │ ├── exam_detail_card.dart │ │ │ └── experiment_detail_card.dart │ │ ├── class_add │ │ │ ├── class_add_window.dart │ │ │ └── wheel_choser.dart │ │ ├── class_page │ │ │ ├── class_change_list.dart │ │ │ ├── classtable_page.dart │ │ │ ├── empty_classtable_page.dart │ │ │ ├── not_arranged_class_list.dart │ │ │ └── week_choice_view.dart │ │ ├── class_table_view │ │ │ ├── class_card.dart │ │ │ ├── class_organized_data.dart │ │ │ ├── class_table_view.dart │ │ │ └── classtable_date_row.dart │ │ ├── classtable.dart │ │ ├── classtable_constant.dart │ │ └── classtable_state.dart │ ├── electricity │ │ └── electricity_window.dart │ ├── empty_classroom │ │ ├── empty_classroom_search_window.dart │ │ └── empty_classroom_window.dart │ ├── exam │ │ ├── exam_info_card.dart │ │ ├── exam_info_window.dart │ │ └── not_arranged_info.dart │ ├── experiment │ │ ├── experiment_info_card.dart │ │ └── experiment_window.dart │ ├── homepage │ │ ├── home.dart │ │ ├── home_card_padding.dart │ │ ├── homepage.dart │ │ ├── info_widget │ │ │ ├── classtable_card.dart │ │ │ ├── electricity_card.dart │ │ │ ├── library_card.dart │ │ │ ├── school_card_info_card.dart │ │ │ └── schoolnet_card.dart │ │ ├── main_page_card.dart │ │ ├── notice_card │ │ │ ├── marquee_widget.dart │ │ │ ├── notice_card.dart │ │ │ ├── notice_list.dart │ │ │ └── notice_page.dart │ │ ├── refresh.dart │ │ ├── small_function_card.dart │ │ └── toolbox │ │ │ ├── empty_classroom_card.dart │ │ │ ├── exam_card.dart │ │ │ ├── experiment_card.dart │ │ │ ├── score_card.dart │ │ │ ├── sport_card.dart │ │ │ └── toolbox_card.dart │ ├── library │ │ ├── book_detail_card.dart │ │ ├── book_info_card.dart │ │ ├── book_place_card.dart │ │ ├── borrow_info_card.dart │ │ ├── borrow_list_window.dart │ │ ├── ebook_place_card.dart │ │ ├── library_window.dart │ │ └── search_book_window.dart │ ├── login │ │ ├── bottom_buttons.dart │ │ ├── jc_captcha.dart │ │ └── login_window.dart │ ├── public_widget │ │ ├── app_icon.dart │ │ ├── both_side_sheet.dart │ │ ├── captcha_input_dialog.dart │ │ ├── column_choose_dialog.dart │ │ ├── context_extension.dart │ │ ├── empty_list_view.dart │ │ ├── info_card.dart │ │ ├── public_widget.dart │ │ ├── re_x_card.dart │ │ ├── split_page_placeholder.dart │ │ ├── timeline_widget │ │ │ ├── flow_event_row.dart │ │ │ ├── timeline_title.dart │ │ │ └── timeline_widget.dart │ │ └── toast.dart │ ├── schoolcard │ │ └── school_card_window.dart │ ├── schoolnet │ │ ├── current_login_user_net_info.dart │ │ ├── data_row.dart │ │ ├── device_list.dart │ │ ├── help_guide.dart │ │ ├── ids_account_net_info.dart │ │ └── network_card_window.dart │ ├── score │ │ ├── score.dart │ │ ├── score_compose_card.dart │ │ ├── score_info_card.dart │ │ ├── score_page.dart │ │ ├── score_state.dart │ │ └── score_statics.dart │ ├── setting │ │ ├── about_page │ │ │ ├── about_page.dart │ │ │ ├── developer_widget.dart │ │ │ ├── easter_egg_page.dart │ │ │ └── link_widget.dart │ │ ├── dialogs │ │ │ ├── change_color_dialog.dart │ │ │ ├── change_localization_dialog.dart │ │ │ ├── change_swift_dialog.dart │ │ │ ├── electricity_account_dialog.dart │ │ │ ├── electricity_password_dialog.dart │ │ │ ├── experiment_password_dialog.dart │ │ │ ├── schoolnet_password_dialog.dart │ │ │ ├── sport_password_dialog.dart │ │ │ └── update_dialog.dart │ │ └── setting.dart │ ├── sport │ │ ├── punch_record_window.dart │ │ ├── sport_class_window.dart │ │ ├── sport_score_window.dart │ │ └── sport_window.dart │ ├── toolbox │ │ ├── toolbox_page.dart │ │ └── webview_list_tile.dart │ └── xdu_planet │ │ ├── comment_popout.dart │ │ ├── content_page.dart │ │ └── xdu_planet_page.dart ├── repository │ ├── experiment_session.dart │ ├── localization.dart │ ├── logger.dart │ ├── message_session.dart │ ├── network_session.dart │ ├── pick_file.dart │ ├── preference.dart │ ├── schoolnet_session.dart │ ├── xdu_planet_session.dart │ ├── xidian_ids │ │ ├── classtable_session.dart │ │ ├── creative_service_session.dart │ │ ├── ehall_session.dart │ │ ├── electricity_session.dart │ │ ├── empty_classroom_session.dart │ │ ├── exam_session.dart │ │ ├── ids_session.dart │ │ ├── jiaowu_service_session.dart │ │ ├── library_session.dart │ │ ├── personal_info_session.dart │ │ ├── school_card_session.dart │ │ └── score_session.dart │ └── xidian_sport_session.dart └── themes │ ├── color_seed.dart │ ├── default.dart │ ├── green.dart │ ├── orange.dart │ └── pink.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 └── packaging │ ├── appimage │ └── make_config.yaml │ └── watermeter.appdata.xml ├── pigeon_bridge ├── copyright_header.txt └── save_to_groupid.dart ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart └── 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 /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: http://afdian.net/a/benderblog # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | 15 | -------------------------------------------------------------------------------- /.github/actions/setup_jdk/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup Java SDK 2 | description: setup shared JDK environment for build use. 3 | 4 | runs: 5 | using: "composite" 6 | steps: 7 | - uses: actions/setup-java@v3 8 | with: 9 | distribution: temurin 10 | java-version: 17 11 | -------------------------------------------------------------------------------- /.github/workflows/release_for_android.yaml: -------------------------------------------------------------------------------- 1 | name: Release for Android 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - "v[0-9]+.[0-9]+.[0-9]+" 8 | 9 | env: 10 | PROPERTIES_PATH: "./android/key.properties" 11 | 12 | jobs: 13 | build_apk: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | 19 | - uses: actions/setup-java@v3 20 | with: 21 | distribution: temurin 22 | java-version: 17 23 | 24 | - name: Install Flutter 25 | run: | 26 | java -version 27 | git submodule update --init --recursive 28 | 29 | - name: Prepare Flutter Dependencies 30 | run: | 31 | .flutter/bin/flutter config --no-analytics 32 | .flutter/bin/flutter pub get 33 | 34 | - name: Signing APK 35 | run: | 36 | echo keyPassword=\${{ secrets.SIGNING_PASSWORD }} > ${{env.PROPERTIES_PATH}} 37 | echo storePassword=\${{ secrets.SIGNING_PASSWORD }} >> ${{env.PROPERTIES_PATH}} 38 | echo keyAlias=\${{ secrets.SIGNING_ALIAS }} >> ${{env.PROPERTIES_PATH}} 39 | echo storeFile=key.jks >> ${{env.PROPERTIES_PATH}} 40 | echo "${{ secrets.SIGNING_KEY }}" | base64 --decode > android/app/key.jks 41 | 42 | - name: Build APK 43 | run: | 44 | .flutter/bin/flutter build apk --split-per-abi 45 | .flutter/bin/flutter build appbundle 46 | 47 | - name: Release 48 | uses: softprops/action-gh-release@v1 49 | with: 50 | files: > 51 | build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk, 52 | build/app/outputs/flutter-apk/app-arm64-v8a-release.apk, 53 | build/app/outputs/flutter-apk/app-x86_64-release.apk 54 | prerelease: false 55 | tag_name: ${{ github.event.inputs.tag_name }} 56 | token: ${{ secrets.RELEASE_TOKEN }} 57 | -------------------------------------------------------------------------------- /.github/workflows/release_for_appimage.yml: -------------------------------------------------------------------------------- 1 | name: Release for Appimage 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - "v[0-9]+.[0-9]+.[0-9]+" 8 | 9 | jobs: 10 | build_deb: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | 16 | - name: Install build-essential 17 | run: | 18 | sudo apt update 19 | sudo apt install build-essential 20 | sudo apt install ninja-build 21 | sudo apt install -y libgtk-3-dev libfuse2 22 | wget -O appimagetool "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" 23 | chmod +x appimagetool 24 | mv appimagetool /usr/local/bin/ 25 | 26 | - name: Install Flutter 27 | run: | 28 | git submodule update --init --recursive 29 | 30 | - name: Prepare Flutter Dependencies 31 | run: | 32 | .flutter/bin/flutter config --no-analytics 33 | .flutter/bin/flutter pub get 34 | 35 | - name: Build Appimage 36 | run: | 37 | export PATH=$PATH:$PWD/.flutter/bin/ 38 | dart pub global activate fastforge 39 | export PATH=$PATH:$HOME/.pub-cache/bin 40 | fastforge package --platform=linux --targets=appimage 41 | 42 | - name: Find Executable 43 | run: | 44 | export dir=$(find ./ -name watermeter-*) 45 | cp $dir ./watermeter.Appimage 46 | 47 | - name: Upload artifact 48 | uses: actions/upload-artifact@v4 49 | with: 50 | name: Watermeter_Appimage 51 | path: watermeter.Appimage 52 | -------------------------------------------------------------------------------- /.github/workflows/release_for_linux.yml: -------------------------------------------------------------------------------- 1 | name: Release for Linux 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - "v[0-9]+.[0-9]+.[0-9]+" 8 | 9 | jobs: 10 | build_deb: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | 16 | - name: Install build-essential 17 | run: | 18 | sudo apt update 19 | sudo apt install build-essential 20 | sudo apt install ninja-build 21 | sudo apt install -y libgtk-3-dev 22 | java -version 23 | 24 | - name: Install Flutter 25 | run: | 26 | git submodule update --init --recursive 27 | 28 | - name: Prepare Flutter Dependencies 29 | run: | 30 | .flutter/bin/flutter config --no-analytics 31 | .flutter/bin/flutter pub get 32 | 33 | - name: Build APP 34 | run: | 35 | .flutter/bin/flutter build linux --release 36 | 37 | - name: Package Executable 38 | run: 7z a -r "../../../../../build/app/watermeter-linux-release-amd64.zip" * 39 | working-directory: build/linux/x64/release/bundle 40 | 41 | - name: Upload artifact 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: Watermeter_Linux 45 | path: build/app/watermeter-linux-release-amd64.zip 46 | 47 | 48 | - name: Release 49 | uses: softprops/action-gh-release@v1 50 | with: 51 | files: build/app/watermeter-linux-release-amd64.zip 52 | prerelease: false 53 | tag_name: ${{ github.event.inputs.tag_name }} 54 | token: ${{ secrets.RELEASE_TOKEN }} 55 | -------------------------------------------------------------------------------- /.github/workflows/release_for_windows.yml: -------------------------------------------------------------------------------- 1 | name: Release for Windows 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - "v[0-9]+.[0-9]+.[0-9]+" 8 | jobs: 9 | build_windows: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Install Flutter 14 | run: | 15 | git submodule update --init --recursive 16 | 17 | - name: Build for Windows 18 | run: | 19 | .flutter/bin/flutter.bat build windows --release 20 | 21 | - name: Package Executable 22 | run: 7z a -r -sse "..\..\..\..\..\build\app\watermeter-windows-release-amd64.zip" * 23 | working-directory: build\windows\x64\runner\Release 24 | 25 | - name: Upload artifact 26 | uses: actions/upload-artifact@v4 27 | with: 28 | name: Watermeter_Windows 29 | path: build/app/watermeter-windows-release-amd64.zip 30 | 31 | - name: Release 32 | uses: softprops/action-gh-release@v1 33 | with: 34 | files: build/app/watermeter-windows-release-amd64.zip 35 | prerelease: false 36 | tag_name: ${{ github.event.inputs.tag_name }} 37 | token: ${{ secrets.RELEASE_TOKEN }} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | pubspec.lock 37 | android/app/build/ 38 | android/app/.cxx 39 | 40 | # Web related 41 | lib/generated_plugin_registrant.dart 42 | 43 | # Symbolication related 44 | app.*.symbols 45 | 46 | # Obfuscation related 47 | app.*.map.json 48 | 49 | # Android Studio will place build artifacts here 50 | /android/app/debug 51 | /android/app/profile 52 | /android/app/release 53 | 54 | # fvm flutter sdk 55 | .fvm/flutter_sdk 56 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule ".flutter"] 2 | path = .flutter 3 | url = https://github.com/flutter/flutter.git 4 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "7482962148e8d758338d8a28f589f317e1e42ba4" 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: 7482962148e8d758338d8a28f589f317e1e42ba4 17 | base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4 18 | - platform: windows 19 | create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4 20 | base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "watermeter", 9 | "request": "launch", 10 | "type": "dart" 11 | }, 12 | { 13 | "name": "watermeter (profile mode)", 14 | "request": "launch", 15 | "type": "dart", 16 | "flutterMode": "profile" 17 | }, 18 | { 19 | "name": "watermeter (release mode)", 20 | "request": "launch", 21 | "type": "dart", 22 | "flutterMode": "release" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "mesonbuild.configureOnOpen": false, 3 | "dart.flutterSdkPaths": [ 4 | ".fvm/flutter_sdk", 5 | ], 6 | "dart.analysisExcludedFolders": [ 7 | ".flutter" 8 | ], 9 | "search.exclude": { 10 | "**/.fvm": true 11 | }, 12 | "files.watcherExclude": { 13 | "**/.fvm": true 14 | }, 15 | "files.associations": { 16 | "*.arb": "json" 17 | }, 18 | "licenser.author": "BenderBlog Rodriguez and contributors", 19 | "licenser.license": "MPLv2", 20 | "licenser.useSPDXLicenseFormat": true, 21 | } -------------------------------------------------------------------------------- /XDYou-Poster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/XDYou-Poster.jpg -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/io/github/benderblog/traintime_pda/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package io.github.benderblog.traintime_pda 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity : FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/io/github/benderblog/traintime_pda/model/ClassTableWidgetModels.kt: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | package io.github.benderblog.traintime_pda.model 6 | 7 | enum class ClassTableWidgetLoadState { 8 | LOADING, 9 | ERROR, 10 | FINISHED, 11 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/io/github/benderblog/traintime_pda/widget/classtable/ClassTableWidgetReceiver.kt: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | package io.github.benderblog.traintime_pda.widget.classtable 6 | 7 | import HomeWidgetGlanceWidgetReceiver 8 | 9 | class ClassTableWidgetReceiver : HomeWidgetGlanceWidgetReceiver() { 10 | override val glanceAppWidget = ClassTableWidget() 11 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/io/github/benderblog/traintime_pda/widget/classtable/ToggleDayAction.kt: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | package io.github.benderblog.traintime_pda.widget.classtable 6 | 7 | import HomeWidgetGlanceStateDefinition 8 | import android.content.Context 9 | import android.util.Log 10 | import androidx.core.content.edit 11 | import androidx.glance.GlanceId 12 | import androidx.glance.action.ActionParameters 13 | import androidx.glance.appwidget.action.ActionCallback 14 | import androidx.glance.appwidget.state.updateAppWidgetState 15 | import io.github.benderblog.traintime_pda.model.ClassTableWidgetKeys 16 | 17 | class ToggleDayAction : ActionCallback { 18 | 19 | override suspend fun onAction( 20 | context: Context, 21 | glanceId: GlanceId, 22 | parameters: ActionParameters 23 | ) { 24 | Log.d("[PDA ClassTableWidget][ToggleDayAction]", "ToggleDayAction triggered for $glanceId") 25 | 26 | updateAppWidgetState( 27 | context, 28 | HomeWidgetGlanceStateDefinition(), 29 | glanceId 30 | ) { prefs -> 31 | val currentIsShowToday = prefs.preferences 32 | .getBoolean(ClassTableWidgetKeys.SHOW_TODAY, true) 33 | Log.d("[PDA ClassTableWidget][ToggleDayAction]", "Current showToday value: $currentIsShowToday") 34 | 35 | val newIsShowToday = !currentIsShowToday 36 | Log.d("[PDA ClassTableWidget][ToggleDayAction]", "New showToday value: $newIsShowToday") 37 | 38 | prefs.preferences.edit { 39 | putBoolean(ClassTableWidgetKeys.SHOW_TODAY, newIsShowToday) 40 | } 41 | Log.d("[PDA ClassTableWidget][ToggleDayAction]", "Set showToday value to: $newIsShowToday") 42 | 43 | prefs 44 | } 45 | 46 | ClassTableWidget().update(context, glanceId) 47 | } 48 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/drawable-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/drawable-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/drawable-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/drawable-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/drawable-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_classtable_error.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_classtable_no_course.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_classtable_refresh.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_next_day.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_prev_day.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/values-night-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 日程小组件 4 | 加载中…… 5 | PDA 日程信息 6 | 目前没有安排 7 | 切换显示日期 8 | 假期中 9 | 第 %1$d 周 10 | 遇到错误:%1$s 11 | 未知错误 12 | 数据加载故障。%1$s 13 | 计算时间索引时出错。%1$s 14 | 无法解析学期开始日期格式 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #64B4F6 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Time Arrangement Widget 4 | Loading… 5 | PDA Arrangements 6 | No arrangement 7 | ClassTable Day Switcher 8 | On Holiday 9 | Week %1$d 10 | Error occurred: %1$s 11 | Unknown error 12 | Failed to load data. %1$s 13 | Problem on calculating index. %1$s 14 | Failed to parse the term start day 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/classtable_widget_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | xidian.edu.cn 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | // https://github.com/flutter/flutter/issues/153281#issuecomment-2292201697 9 | rootProject.buildDir = '../build' 10 | subprojects { 11 | afterEvaluate { project -> 12 | if (project.extensions.findByName("android") != null) { 13 | Integer pluginCompileSdk = project.android.compileSdk 14 | if (pluginCompileSdk != null && pluginCompileSdk < 31) { 15 | project.logger.error( 16 | "Warning: Overriding compileSdk version in Flutter plugin: " 17 | + project.name 18 | + " from " 19 | + pluginCompileSdk 20 | + " to 31 (to work around https://issuetracker.google.com/issues/199180389)." 21 | + "\nIf there is not a new version of " + project.name + ", consider filing an issue against " 22 | + project.name 23 | + " to increase their compileSdk to the latest (otherwise try updating to the latest version)." 24 | ) 25 | project.android { 26 | compileSdk 31 27 | } 28 | } 29 | } 30 | } 31 | 32 | project.buildDir = "${rootProject.buildDir}/${project.name}" 33 | project.evaluationDependsOn(":app") 34 | } 35 | tasks.register("clean", Delete) { 36 | delete rootProject.buildDir 37 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Feb 15 15:33:20 CST 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /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.10.0' apply false 22 | id "org.jetbrains.kotlin.android" version "1.9.25" apply false 23 | } 24 | 25 | include ":app" 26 | 27 | 28 | -------------------------------------------------------------------------------- /assets/Icon-App-iTunes-Background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/Icon-App-iTunes-Background.png -------------------------------------------------------------------------------- /assets/Icon-App-iTunes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/Icon-App-iTunes.png -------------------------------------------------------------------------------- /assets/README.MD: -------------------------------------------------------------------------------- 1 | 由于 XDYou 不是自由软件,必须说明本程序资产授权。 2 | 未声明均按照 MPL 授权: 3 | 4 | - art 5 | - CP1919.svg.vec:基于 CP1919.svg 制作,公有领域 6 | - pda_classtable_empty.png:LichtYy 7 | - pda_empty_cover: ZCWzy 8 | - pda_girl_default_ver1: Benderblog,PDA 娘(初始版本) 9 | - pda_girl_default: Benderblog,PDA 娘(目前版本,配合开发代号) 10 | - pda_girl_reading: Benderblog,PDA 娘在阅读 11 | - flutter_i18n:全部的翻译文件和转换脚本 12 | - random 13 | - CP1919.svg:基于 PSR B1919+21 脉冲星数据生成,公有领域 14 | - Credit-1.jpg:早期版本感谢名单,最终产物没有使用 15 | - Credit-2.jpg:早期版本感谢名单,最终产物没有使用 16 | - Ray.jpg:贡献者 Ray(Elliot Edition)自画像,最终产物没有使用。版权所有,作者保留一切权利 17 | - xdyou_girl:Ray(Elliot Edition),XDYou 娘,仅 iOS 版本使用。版权所有,作者保留一切权利 18 | - ZCWzy-MPL-License:ZCWzy 授权文书 19 | - captcha-solver-payment.tflite:stalomeow,缴费系统验证码模型,MIT 授权 20 | - captcha-solver-zfw.tflite:stalomeow,网络计费查询系统验证码模型,MIT 授权 21 | - Icon-App-iTunes-Background:lsy223622,XDYou 图标,仅 iOS 版本使用。版权所有,作者保留一切权利 22 | - Icon-App-iTunes:lsy223622,XDYou 图标,仅 iOS 版本使用。版权所有,作者保留一切权利 23 | - icon.png:Benderblog / lsy223622,Traintime PDA 图标 24 | - guide:西电信息技术中心 -------------------------------------------------------------------------------- /assets/art/CP1919.svg.vec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/CP1919.svg.vec -------------------------------------------------------------------------------- /assets/art/aboutRobots-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/aboutRobots-icon.png -------------------------------------------------------------------------------- /assets/art/pda_classtable_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/pda_classtable_empty.png -------------------------------------------------------------------------------- /assets/art/pda_empty_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/pda_empty_cover.jpg -------------------------------------------------------------------------------- /assets/art/pda_girl_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/pda_girl_default.png -------------------------------------------------------------------------------- /assets/art/pda_girl_default_ver1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/pda_girl_default_ver1.png -------------------------------------------------------------------------------- /assets/art/pda_girl_default_ver2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/pda_girl_default_ver2.png -------------------------------------------------------------------------------- /assets/art/pda_girl_reading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/pda_girl_reading.png -------------------------------------------------------------------------------- /assets/art/pda_girl_reading_ver1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/pda_girl_reading_ver1.png -------------------------------------------------------------------------------- /assets/art/pda_girl_singing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/art/pda_girl_singing.png -------------------------------------------------------------------------------- /assets/captcha-solver-payment.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/captcha-solver-payment.tflite -------------------------------------------------------------------------------- /assets/captcha-solver-zfw.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/captcha-solver-zfw.tflite -------------------------------------------------------------------------------- /assets/flutter_i18n/s2tw.py: -------------------------------------------------------------------------------- 1 | import opencc 2 | import yaml 3 | from collections import OrderedDict 4 | 5 | converter = opencc.OpenCC('s2tw.json') 6 | 7 | # 自定义 Loader,使用 OrderedDict 读取 YAML 文件 8 | class OrderedLoader(yaml.SafeLoader): 9 | pass 10 | 11 | def construct_mapping(loader, node): 12 | loader.flatten_mapping(node) 13 | return OrderedDict(loader.construct_pairs(node)) 14 | 15 | OrderedLoader.add_constructor( 16 | yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, 17 | construct_mapping 18 | ) 19 | 20 | # 读取 YAML 文件并保持顺序 21 | with open('zh_CN.yaml', 'r', encoding='utf-8') as file: 22 | yaml_content = yaml.load(file, Loader=OrderedLoader) 23 | 24 | # 遍历 YAML 内容并转换 25 | def convert_yaml(content): 26 | if isinstance(content, dict): 27 | return OrderedDict((key, convert_yaml(value)) for key, value in content.items()) 28 | elif isinstance(content, list): 29 | return [convert_yaml(item) for item in content] 30 | elif isinstance(content, str): 31 | return converter.convert(content) # 转换字符串中的汉字 32 | else: 33 | return content 34 | 35 | # 对 YAML 文件的内容进行转换 36 | converted_content = convert_yaml(yaml_content) 37 | 38 | # 自定义 Dumper,确保输出时保持顺序 39 | class OrderedDumper(yaml.SafeDumper): 40 | pass 41 | 42 | def dict_representer(dumper, data): 43 | return dumper.represent_dict(data.items()) 44 | 45 | OrderedDumper.add_representer(OrderedDict, dict_representer) 46 | 47 | # 将转换后的内容写入新的 YAML 文件,并保持顺序 48 | with open('zh_TW.yaml', 'w', encoding='utf-8') as file: 49 | file.write("# Translated using OpenCC s2twp Dictionary, script by Hancl777\n") 50 | yaml.dump(converted_content, file, Dumper=OrderedDumper, allow_unicode=True) 51 | 52 | print("YAML 文件中的中文已经转换并保持了顺序!") 53 | -------------------------------------------------------------------------------- /assets/guide/img/010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/010.png -------------------------------------------------------------------------------- /assets/guide/img/011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/011.png -------------------------------------------------------------------------------- /assets/guide/img/012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/012.png -------------------------------------------------------------------------------- /assets/guide/img/013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/013.png -------------------------------------------------------------------------------- /assets/guide/img/015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/015.png -------------------------------------------------------------------------------- /assets/guide/img/016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/016.png -------------------------------------------------------------------------------- /assets/guide/img/017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/017.png -------------------------------------------------------------------------------- /assets/guide/img/021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/021.png -------------------------------------------------------------------------------- /assets/guide/img/022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/022.png -------------------------------------------------------------------------------- /assets/guide/img/023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/023.png -------------------------------------------------------------------------------- /assets/guide/img/024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/024.png -------------------------------------------------------------------------------- /assets/guide/img/026.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/026.png -------------------------------------------------------------------------------- /assets/guide/img/028.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/028.png -------------------------------------------------------------------------------- /assets/guide/img/029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/029.png -------------------------------------------------------------------------------- /assets/guide/img/030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/030.png -------------------------------------------------------------------------------- /assets/guide/img/031.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/031.png -------------------------------------------------------------------------------- /assets/guide/img/032.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/032.png -------------------------------------------------------------------------------- /assets/guide/img/034.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/034.png -------------------------------------------------------------------------------- /assets/guide/img/035.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/035.png -------------------------------------------------------------------------------- /assets/guide/img/037.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/037.png -------------------------------------------------------------------------------- /assets/guide/img/042.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/042.png -------------------------------------------------------------------------------- /assets/guide/img/043.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/043.png -------------------------------------------------------------------------------- /assets/guide/img/044.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/044.jpeg -------------------------------------------------------------------------------- /assets/guide/img/045.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/045.png -------------------------------------------------------------------------------- /assets/guide/img/046.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/046.png -------------------------------------------------------------------------------- /assets/guide/img/047.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/047.png -------------------------------------------------------------------------------- /assets/guide/img/052.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/052.png -------------------------------------------------------------------------------- /assets/guide/img/054.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/054.png -------------------------------------------------------------------------------- /assets/guide/img/055.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/055.png -------------------------------------------------------------------------------- /assets/guide/img/056.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/056.png -------------------------------------------------------------------------------- /assets/guide/img/057.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/057.png -------------------------------------------------------------------------------- /assets/guide/img/058.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/058.png -------------------------------------------------------------------------------- /assets/guide/img/059.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/059.jpeg -------------------------------------------------------------------------------- /assets/guide/img/060.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/060.jpeg -------------------------------------------------------------------------------- /assets/guide/img/061.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/061.png -------------------------------------------------------------------------------- /assets/guide/img/062.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/062.jpeg -------------------------------------------------------------------------------- /assets/guide/img/063.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/063.jpeg -------------------------------------------------------------------------------- /assets/guide/img/064.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/064.png -------------------------------------------------------------------------------- /assets/guide/img/066.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/066.png -------------------------------------------------------------------------------- /assets/guide/img/067.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/067.png -------------------------------------------------------------------------------- /assets/guide/img/068.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/068.png -------------------------------------------------------------------------------- /assets/guide/img/070.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/070.png -------------------------------------------------------------------------------- /assets/guide/img/071.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/071.jpg -------------------------------------------------------------------------------- /assets/guide/img/072.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/072.png -------------------------------------------------------------------------------- /assets/guide/img/073.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/guide/img/073.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/icon.png -------------------------------------------------------------------------------- /assets/random/Credit-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/random/Credit-1.jpg -------------------------------------------------------------------------------- /assets/random/Credit-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/random/Credit-2.jpg -------------------------------------------------------------------------------- /assets/random/Ray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/random/Ray.jpg -------------------------------------------------------------------------------- /assets/random/ZCWzy-MPL-License.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/random/ZCWzy-MPL-License.jpg -------------------------------------------------------------------------------- /assets/random/xdyou_girl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/assets/random/xdyou_girl.png -------------------------------------------------------------------------------- /blobs/libtensorflowlite_c-linux.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/blobs/libtensorflowlite_c-linux.so -------------------------------------------------------------------------------- /blobs/libtensorflowlite_c-macos.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/blobs/libtensorflowlite_c-macos.dylib -------------------------------------------------------------------------------- /blobs/libtensorflowlite_c-win.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/blobs/libtensorflowlite_c-win.dll -------------------------------------------------------------------------------- /devtools_options.yaml: -------------------------------------------------------------------------------- 1 | description: This file stores settings for Dart & Flutter DevTools. 2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states 3 | extensions: 4 | - provider: true 5 | - shared_preferences: true -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/1.txt: -------------------------------------------------------------------------------- 1 | Webview support, which means you can access more services. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/10.txt: -------------------------------------------------------------------------------- 1 | 1. Dingxiang dorm electricity value. 2 | 2. An app info function. 3 | 3. Library borrow may seen. 4 | 4. Tomorrow class optimized. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/12.txt: -------------------------------------------------------------------------------- 1 | 1. New UI 2 | 2. Lots of improvement -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/19.txt: -------------------------------------------------------------------------------- 1 | Fix bugs, sync the codebase with iOS XDYou v1.1.0. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/2.txt: -------------------------------------------------------------------------------- 1 | Empty classroom query and bug fixes. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/203.txt: -------------------------------------------------------------------------------- 1 | 1. Detail of score. 2 | 2. Redesign of mainpage. 3 | 3. Master-detail page for pad. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/233.txt: -------------------------------------------------------------------------------- 1 | Emergency fix of 1.3.0. Check github release for more detail. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/243.txt: -------------------------------------------------------------------------------- 1 | Check github release for more detail. 2 | 3 | 1. The electricity balance is back! Thanks @Rrrilac and @hhzm. 4 | 2. I managed to get data from postgraduate system, however, it is not stable... 5 | 3. A software upgrade notice is implemented. 6 | 4. @Pairman speeded up login. 7 | 5. @Nancuncloud fixed a bug related to dialog. 8 | 9 | Also feauring a short story: 10 | 11 | Once upon a time, there's a 'Hard Lovin' Man called Ray, whose understand the power of the Railgun called 'Flight of the Rat. 12 | 13 | Once after a battle with a 'Bloodsucker, he was tired as a high school student. He discovered a Purple Rat in the Square Forest. 14 | 15 | Unknown her name, "She like a sweet potato, like my Rat gun. Just call her Sweet Purple Potato Ball, idk...", he thought. And he brought her to his home(maybe?) 16 | 17 | The rat is clever, actually she is a angle named Elliot. We don't know why her soul inside a rat. Forgive me, I am drunked. 18 | 19 | She knows he is the 'Child of the Time. They may argue, may laugh. In my opinion, she lighten Ray's seemly colorless life. 20 | 21 | Don't know how time flies, she made he faster in running, attacking. With the power of the 'Rat gun', he become the threating 'Speed King. 22 | 23 | 6. Partner classtable. Inspired by @Elliot and @Ray(Elliot Edition). -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/253.txt: -------------------------------------------------------------------------------- 1 | 1. Traditional Chinese support @BenderBlog 2 | Translation script @GodHu777777 @Hancl777 3 | 2. Speed up electricity query @stalomeow 4 | 3. Color changing @BenderBlog @LichtYy 5 | 4. Fix related to classtable @wirsbf -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/263.txt: -------------------------------------------------------------------------------- 1 | 1. Schoolnet query dialog @BenderBlog @stalomeow 2 | 2. Fix: Unable to login in some cases. 3 | 3. Fix: Lots of stuff in classtable and class change. 4 | 4. Change assets with more cute and foss stuff @BenderBlog @LichtYy @ZCWzy -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/273.txt: -------------------------------------------------------------------------------- 1 | 1. Serveral bug fixes. @BenderBlog 2 | 2. English translation. @Elliot 3 | 3. Pre-postgraduate support (testing). @BenderBlog -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/283.txt: -------------------------------------------------------------------------------- 1 | 1. Optimize the icalendar file output. @GodHu777777 2 | 2. Output time arrangement to system calendar. @BenderBlog 3 | 3. Schoolnet usage query page. @xeonds @BenderBlog 4 | 4. Schoolnet usage documents. XDUNA through @MrBrilliant2046 -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/293.txt: -------------------------------------------------------------------------------- 1 | 1. Update SDK. 2 | 2. Fix school card money fetch error. @BenderBlog 3 | 3. Change login in search score, now case insensitive. @Pairman 4 | 4. Some url in toolbox chagned. @ZYar-er 5 | 5. (Non-mobile platform) Linux AppImage support. @lhx-666-cool 6 | 6. Fix error on outputing schedule to system calendar. @BenderBlog -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/4.txt: -------------------------------------------------------------------------------- 1 | - F-Droid upload: split the abi per package. 2 | - Remove Xidian Directory, replaced with contact book. 3 | - Add a shortcut on request of somebody. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/5.txt: -------------------------------------------------------------------------------- 1 | Major change since v0.1.0. 2 | 3 | 1. FDroid onboard. 4 | 2. Remove Xidian Dir, replaced with school contact. 5 | 3. Creative and commercialization project query. 6 | 4. Lots of WebView function. 7 | 5. Empty classroom query. 8 | 6. A little tool subwindow. 9 | 10 | Details:https://superbart.xyz/p/traintime-pda-v0.2.0-release-note.html -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/6.txt: -------------------------------------------------------------------------------- 1 | 1. Sport Session fix. (Important fix) 2 | 2. Maxium 600px page width implemented elsewhere. 3 | 3. Toolbox able to scroll. 4 | 4. Classtable toprow(week choice row) fix. 5 | 6 | Sorry for your inconvenience. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/7.txt: -------------------------------------------------------------------------------- 1 | 1. Night mode fix. 2 | 2. Library fix. 3 | 3. Horizontal and pad page, as well as new homepage. 4 | 4. Electricity fix. 5 | 5. Other minor page. 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/8.txt: -------------------------------------------------------------------------------- 1 | Other fix -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/9.txt: -------------------------------------------------------------------------------- 1 | Emergency Fix 2 | 1. Occaisonally dead on score window. 3 | 2. Erase last state when login failed. 4 | 5 | 0.3.0 means a new beginning. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 | "Traintime PDA" is an open-source personal data assistant for XDU students. 2 | 3 | The XDYou app in the Apple App Store have the same codebase as this. 4 | 5 | - Both undergraduates and postgraduates are supported. 6 | - View classtable with exam arrangement and experiment arrangement, also set your idol as the background, or exchange the classtable with your sweetie. 7 | - View sport related data: sport class detail and test score. (Punch machine will be sorely missed) 8 | - Check your dorm's electricity balance and (maybe) pay your electricty fee. (Postgraduates shall enter the electricity account manually) 9 | - View your grade and easily calculate GPA and average score by choosing the subjects. (Postgraduates cannot count your GPA and average score, sry) 10 | - View the exam schedule by semester. 11 | - View the due time of the borrowed books and query the details of the books in the library. 12 | - View the bill you spent in the cafeteria. 13 | - Empty classroom check. (Not avaliable for postgraduates) 14 | - Physics experiment schedule check and output to iCalendar. 15 | - Other tools such as call for repairing, school email, etc. 16 | - XDU Planet: Look around the blogs of your schoolmates. 17 | - Physics experiment check. 18 | - Schoolnet Query. 19 | - Homepage widget. 20 | 21 | If you got some idea about it, contact me freely. 22 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/icon.png: -------------------------------------------------------------------------------- 1 | ../../../../../assets/icon.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | Open Source data assistant for XDU students. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/title.txt: -------------------------------------------------------------------------------- 1 | Traintime PDA 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/1.txt: -------------------------------------------------------------------------------- 1 | 添加 Webview 支持,由此支持更多的服务。 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/10.txt: -------------------------------------------------------------------------------- 1 | 1. 修复丁香没有电量信息的错误。 2 | 2. 添加应用内信息,会有开发者发出的学校/社团/应用信息 3 | 3. 修复图书馆借书信息可能显示失败 4 | 4. 修复明日课程可能显示有问题的问题 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/12.txt: -------------------------------------------------------------------------------- 1 | 新 UI 和其他提升 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/19.txt: -------------------------------------------------------------------------------- 1 | 修复了一些存在于 v1.1.0 的问题,与 iOS XDYou 的 v1.1.0 代码库同步。 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/2.txt: -------------------------------------------------------------------------------- 1 | 空闲教室查询,错误修复。 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/203.txt: -------------------------------------------------------------------------------- 1 | 1. 成绩详情 2 | 2. 主页重新设计 3 | 3. 平板界面优化 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/233.txt: -------------------------------------------------------------------------------- 1 | 1. 紧急修复由于数据结构变化导致的报错问题。 2 | 2. 图书馆图片加载不出来将不会报错。 3 | 4 | 1.3.0 版本变化 5 | 6 | 1. 成绩缓存功能 @Pairman 7 | 2. 部分成绩查看失败(因为上课次数不够导致取消考试资格)@BenderBlog 8 | 3. Android 小部件修复 @Xiue233 & iOS 小部件修复 @BenderBlog 9 | 4. 优化查看成绩功能 @BenderBlog 10 | 5. 大量 XDU-Planet 优化 @xeonds @NanCunChild 11 | 6. 图书馆卡片重新设计 @BrackRat 图书馆接口改进 @BenderBlog 12 | 7. 通知小部件重新设计 @xeonds 13 | 8. 新彩蛋页面 @0xcafebabe @wtflmao 14 | 9. 升级拦截器和日志记录插件和 Flutter 版本 @BenderBlog 15 | 10. 课程表顶栏重新设计 @BenderBlog -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/243.txt: -------------------------------------------------------------------------------- 1 | 1. 搭子课表 @Elliot @Ray(Elliot Edition) 2 | 2. 研究生系统适配(可能不稳定) @BenderBlog 3 | 3. 修复弹出窗口可能被报错 @Nancuncloud 4 | 4. 升级滑块通过率 @Pairman 5 | 5. 新电费欠费查询 @Rrrilac @hhzm 6 | 6. 软件更新通知 @BenderBlog -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/253.txt: -------------------------------------------------------------------------------- 1 | 1. 繁体中文翻译 @BenderBlog 2 | 包括转换脚本 @GodHu777777 @Hancl777 3 | 2. 加速电费查询 @stalomeow 4 | 3. 更改颜色 @BenderBlog @LichtYy 5 | 4. 一些涉及课表加载的小修复 @wirsbf -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/263.txt: -------------------------------------------------------------------------------- 1 | 1. 校园网查询 @BenderBlog @stalomeow 2 | 2. 修复某些状态下无法登录 3 | 3. 修复课程表和调课信息处理方面的很多错误 4 | 4. 更换插图,保证可爱以及开源 @BenderBlog @LichtYy @ZCWzy -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/273.txt: -------------------------------------------------------------------------------- 1 | 1. 若干错误修复 @BenderBlog 2 | 2. 英语翻译支持 @Elliot 3 | 3. 研究生预科生测试支持 @BenderBlog -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/283.txt: -------------------------------------------------------------------------------- 1 | 1. 优化 iCal 文件输出 @GodHu777777 2 | 2. 输出日程安排到日历 @BenderBlog 3 | 3. 校园网余量查询页面 @xeonds @BenderBlog 4 | 4. 网络服务使用说明 西电网络管理协会经由 @MrBrilliant2046 提供 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/293.txt: -------------------------------------------------------------------------------- 1 | 1. 升级 SDK 等依赖 2 | 2. 修复校园卡余额获取错误 @BenderBlog 3 | 3. 修改成绩搜索逻辑,现在大小写不敏感 @Pairman 4 | 4. 修改部分快捷方式 @ZYar-er 5 | 5. (非移动端) Linux AppImage 编译初步支持 @lhx-666-cool 6 | 6. 导出课程表到系统日历有错误 @BenderBlog -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/4.txt: -------------------------------------------------------------------------------- 1 | 1. FDroid 上架中:分离架构构建。 2 | 2. 移除西电目录,用电话本代替。 3 | 3. 应请求添加双创网页。 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/5.txt: -------------------------------------------------------------------------------- 1 | 自 v0.1.0 版本以来的主要变化。 2 | 3 | 1. FDroid 上架。 4 | 2. 移除西电目录,用电话本代替。 5 | 3. 应请求添加双创需求大厅。 6 | 4. 添加很多利用 WebView 的小功能。 7 | 5. 空闲教室功能。 8 | 6. 提取很多使用不多的功能到小工具分页。 9 | 10 | 详情可以看:https://superbart.xyz/p/traintime-pda-v0.2.0-release-note.html 11 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/6.txt: -------------------------------------------------------------------------------- 1 | 1. 体育信息网络快速修复。(十分重要) 2 | 2. 为了横屏使用,很多页面上了 600px 。 3 | 3. 小工具页面能滚动了。(更加重要) 4 | 4. 课程表选周次,用了 PageView。 5 | 6 | 如有不便,我恳请您的原谅。 7 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/7.txt: -------------------------------------------------------------------------------- 1 | 1. 夜晚模式启动. 2 | 2. 图书馆接口修复. 3 | 3. 新首页,横屏竖屏修复. 4 | 4. 电力接口修复. 5 | 5. 其他修复. 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/8.txt: -------------------------------------------------------------------------------- 1 | 一些小更新 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/changelogs/9.txt: -------------------------------------------------------------------------------- 1 | 紧急更新: 2 | 1. 成绩界面概率性卡死 3 | 2. 登录失败后自动清除 4 | 5 | 因另一个平台上架,0.3.0 版本发布。 -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/full_description.txt: -------------------------------------------------------------------------------- 1 | Traintime PDA 是为西电学生设计的开源信息查询软件。(PDA 指个人信息管理工具) 2 | 3 | 本程序和 iOS 平台的 XDYou 系出同样的代码库。 4 | 5 | 1. 支持本科生和研究生查看课表,成绩,考试信息。 6 | 2. 查看日程表:包括课程信息,考试信息。顺便把你偶像的图片设成背景。(以及导入你对象的课表,写完真虐心啊) 7 | 3. 查看体育信息:体育课程信息和体测成绩记录。(打卡机在人世间完成了一个轮回) 8 | 4. 查看宿舍电量,也许顺手交了电费。(研究生需要自行输入电费账号) 9 | 5. 查看成绩,包括可以自行选择科目计算均分。(本程序首创,研究生不可用均分计算) 10 | 6. 考试安排查询。 11 | 7. 查询空闲教室。(研究生不可用) 12 | 8. 图书馆信息查询,个人借书状况和学校书库状况。 13 | 9. 校园卡流水查询,也就是在学校食堂的流水啦。 14 | 10. 其他小功能:请假,报修之类。 15 | 11. XDU Planet:查看同学的博客。 16 | 12. 物理实验查看功能。 17 | 13. 查询校园网用量。 18 | 13. Android 和 iOS 特有的日程查看桌面小部件。 19 | 20 | 如果你对本程序啥想法,欢迎向我提出。 21 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/short_description.txt: -------------------------------------------------------------------------------- 1 | 开源的西电学生信息查询软件 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/title.txt: -------------------------------------------------------------------------------- 1 | Traintime PDA 2 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.942", 9 | "green" : "0.942", 10 | "red" : "0.942" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.066", 27 | "green" : "0.066", 28 | "red" : "0.066" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/ClasstableWidgetBundle.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | // 5 | // ClasstableWidgetBundle.swift 6 | // ClasstableWidget 7 | // 8 | // Created by BenderBlog Rodriguez on 2024/1/7. 9 | // 10 | 11 | import WidgetKit 12 | import SwiftUI 13 | 14 | @main 15 | struct ClasstableWidgetBundle: WidgetBundle { 16 | var body: some Widget { 17 | ClasstableWidget() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/ColorList.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | // 5 | // ColorList.swift 6 | // ClasstableWidgetExtension 7 | // 8 | // Created by BenderBlog Rodriguez on 2024/2/29. 9 | // 10 | 11 | import Foundation 12 | import SwiftUI 13 | 14 | extension Color { 15 | init(hexString: String) { 16 | let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) 17 | var int = UInt64() 18 | Scanner(string: hex).scanHexInt64(&int) 19 | let a, r, g, b: UInt64 20 | switch hex.count { 21 | case 3: // RGB (12-bit) 22 | (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) 23 | case 6: // RGB (24-bit) 24 | (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) 25 | case 8: // ARGB (32-bit) 26 | (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) 27 | default: 28 | (a, r, g, b) = (255, 0, 0, 0) 29 | } 30 | self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, opacity: CGFloat(a) / 255) 31 | } 32 | } 33 | 34 | // Colors 35 | var colors: [Color] = [ 36 | Color(hexString: "#EF5350"), 37 | Color(hexString: "#EC407A"), 38 | Color(hexString: "#AB47BC"), 39 | Color(hexString: "#7E57C2"), 40 | Color(hexString: "#5C6BC0"), 41 | Color(hexString: "#42A5F5"), 42 | Color(hexString: "#29B6F6"), 43 | Color(hexString: "#26C6DA"), 44 | Color(hexString: "#26A69A"), 45 | Color(hexString: "#66BB6A"), 46 | Color(hexString: "#9CCC65"), 47 | Color(hexString: "#66BB6A"), 48 | ] 49 | 50 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/ExamModule.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | // 5 | // ExamModule.swift 6 | // ClasstableWidgetExtension 7 | // 8 | // Created by BenderBlog Rodriguez on 2024/1/18. 9 | // 10 | // Refrence to /lib/model/xidian_ids/exam.dart 11 | // 12 | 13 | import Foundation 14 | 15 | struct ExamData : Codable { 16 | let subject : [Subject] 17 | let toBeArranged : [ToBeArranged] 18 | } 19 | 20 | class Subject : Codable { 21 | let subject : String 22 | let typeStr : String 23 | let startTimeStr : String 24 | let endTimeStr : String 25 | let time : String 26 | let place : String 27 | let seat : String 28 | 29 | var startTime : Date { 30 | get { 31 | let format : String = "yyyy-MM-dd HH:mm:ss" 32 | let dateFormatter = DateFormatter() 33 | dateFormatter.dateFormat = format 34 | return dateFormatter.date(from: startTimeStr) ?? Date(timeIntervalSince1970: 0) 35 | } 36 | } 37 | 38 | var endTime : Date { 39 | get { 40 | let format : String = "yyyy-MM-dd HH:mm:ss" 41 | let dateFormatter = DateFormatter() 42 | dateFormatter.dateFormat = format 43 | return dateFormatter.date(from: endTimeStr) ?? Date(timeIntervalSince1970: 0) 44 | } 45 | } 46 | 47 | var type : String { 48 | get { 49 | if (typeStr.contains("期末考试")) { return "期末考试"; } 50 | if (typeStr.contains("期中考试")) { return "期中考试"; } 51 | if (typeStr.contains("结课考试")) { return "结课考试"; } 52 | if (typeStr.contains("入学")) { return "入学考试"; } 53 | return typeStr; 54 | } 55 | } 56 | } 57 | 58 | struct ToBeArranged : Codable { 59 | let subject : String 60 | let id : String 61 | } 62 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/HexToColor.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | // 5 | // ColorHexExtension.swift 6 | // ClasstableWidgetExtension 7 | // 8 | // Created by BenderBlog Rodriguez on 2024/2/29. 9 | // 10 | 11 | import Foundation 12 | import SwiftUI 13 | 14 | func hexStringToUIColor (hex:String) -> UIColor { 15 | var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() 16 | 17 | if (cString.hasPrefix("#")) { 18 | cString.remove(at: cString.startIndex) 19 | } 20 | 21 | if ((cString.count) != 6) { 22 | return UIColor.gray 23 | } 24 | 25 | var rgbValue:UInt64 = 0 26 | Scanner(string: cString).scanHexInt64(&rgbValue) 27 | 28 | return UIColor( 29 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, 30 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, 31 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0, 32 | alpha: CGFloat(1.0) 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.widgetkit-extension 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ios/ClasstableWidget/IsTomorrowIntent.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | // 5 | // IsTomorrowIntent.swift 6 | // ClasstableWidgetExtension 7 | // 8 | // Created by BenderBlog Rodriguez on 2024/3/1. 9 | // 10 | 11 | import Foundation 12 | import AppIntents 13 | 14 | @available(iOS 17.0, macOS 13.0, tvOS 17.0, watchOS 10.0, *) 15 | struct IsTomorrowManager { 16 | static var value = false 17 | } 18 | 19 | @available(iOS 17.0, macOS 13.0, tvOS 17.0, watchOS 10.0, *) 20 | struct IsTomorrowIntent: AppIntent { 21 | 22 | static var title: LocalizedStringResource = "IsTomorrow Task" 23 | static var description: IntentDescription = IntentDescription("IsTomorrow Task") 24 | 25 | init() { } 26 | 27 | func perform() async throws -> some IntentResult { 28 | IsTomorrowManager.value = !IsTomorrowManager.value 29 | return .result() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ios/ClasstableWidgetExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.xyz.superbart.xdyou 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/PartnerShareExtension/Base.lproj/MainInterface.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 | -------------------------------------------------------------------------------- /ios/PartnerShareExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AppGroupId 6 | $(CUSTOM_GROUP_ID) 7 | NSExtension 8 | 9 | NSExtensionAttributes 10 | 11 | NSExtensionActivationRule 12 | 13 | NSExtensionActivationSupportsFileWithMaxCount 14 | 1 15 | 16 | 17 | NSExtensionMainStoryboard 18 | MainInterface 19 | NSExtensionPointIdentifier 20 | com.apple.share-services 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ios/PartnerShareExtension/PartnerShareExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.xyz.superbart.xdyou 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/PartnerShareExtension/ShareViewController.swift: -------------------------------------------------------------------------------- 1 | // If you get no such module 'receive_sharing_intent' error. 2 | // Go to Build Phases of your Runner target and 3 | // move `Embed Foundation Extension` to the top of `Thin Binary`. 4 | import receive_sharing_intent 5 | 6 | class ShareViewController: RSIShareViewController { 7 | // Use this method to return false if you don't want to redirect to host app automatically. 8 | // Default is true 9 | override func shouldAutoRedirect() -> Bool { 10 | return true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ios/PartnerShareExtension/en.lproj/MainInterface.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/PartnerShareExtension/zh-Hans.lproj/MainInterface.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/PartnerShareExtension/zh-Hant.lproj/MainInterface.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /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 | 36 | # Share Extension is name of Extension which you created which is in this case 'Share Extension' 37 | target 'PartnerShareExtension' do 38 | inherit! :search_paths 39 | end 40 | target 'RunnerTests' do 41 | inherit! :search_paths 42 | end 43 | end 44 | 45 | post_install do |installer| 46 | installer.pods_project.targets.each do |target| 47 | flutter_additional_ios_build_settings(target) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | 12 | let controller = window?.rootViewController as! FlutterViewController 13 | let api = ApiImplementation() 14 | SaveToGroupIdSwiftApiSetup.setUp(binaryMessenger: controller.binaryMessenger, api: api) 15 | 16 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "xdyou_girl.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/xdyou_girl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/LaunchBackground.imageset/xdyou_girl.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LaunchImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "LaunchImage@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "LaunchImage@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, 6 | selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. 7 | 8 | # For XDYou iOS Specific LaunchImage 9 | 10 | Not covered by MPL, all rights reserved by Ray. 11 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/xdyou_icon_handwritten_original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/ios/Runner/Assets.xcassets/LaunchImage.imageset/xdyou_icon_handwritten_original.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.xyz.superbart.xdyou 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner/en.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/en.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hans.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hans.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hant.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hant.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/model/home_arrangement.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:json_annotation/json_annotation.dart'; 6 | 7 | part 'home_arrangement.g.dart'; 8 | 9 | /// This is for the main page applet. 10 | /// [startTime] and [endTime] must be stored with the following format 11 | // 'yyyy-MM-dd HH:mm:ss' 12 | @JsonSerializable(explicitToJson: true) 13 | class HomeArrangement { 14 | static const format = 'yyyy-MM-dd HH:mm:ss'; 15 | 16 | String name; 17 | String? teacher; 18 | String? place; 19 | String? seat; 20 | 21 | @JsonKey(name: 'start_time') 22 | String startTimeStr; 23 | @JsonKey(name: 'end_time') 24 | String endTimeStr; 25 | 26 | @override 27 | int get hashCode => 28 | "$name $teacher $place $seat $startTimeStr $endTimeStr".hashCode; 29 | 30 | DateTime get startTime => DateTime.parse(startTimeStr); 31 | DateTime get endTime => DateTime.parse(endTimeStr); 32 | 33 | @override 34 | bool operator ==(Object other) => 35 | other is HomeArrangement && 36 | other.name == name && 37 | other.teacher == teacher && 38 | other.place == place && 39 | other.seat == seat && 40 | other.startTime == startTime && 41 | other.endTime == endTime; 42 | 43 | HomeArrangement({ 44 | required this.name, 45 | required this.startTimeStr, 46 | required this.endTimeStr, 47 | this.teacher, 48 | this.place, 49 | this.seat, 50 | }); 51 | 52 | factory HomeArrangement.fromJson(Map json) => 53 | _$HomeArrangementFromJson(json); 54 | 55 | Map toJson() => _$HomeArrangementToJson(this); 56 | } 57 | -------------------------------------------------------------------------------- /lib/model/home_arrangement.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'home_arrangement.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | HomeArrangement _$HomeArrangementFromJson(Map json) => 10 | HomeArrangement( 11 | name: json['name'] as String, 12 | startTimeStr: json['start_time'] as String, 13 | endTimeStr: json['end_time'] as String, 14 | teacher: json['teacher'] as String?, 15 | place: json['place'] as String?, 16 | seat: json['seat'] as String?, 17 | ); 18 | 19 | Map _$HomeArrangementToJson(HomeArrangement instance) => 20 | { 21 | 'name': instance.name, 22 | 'teacher': instance.teacher, 23 | 'place': instance.place, 24 | 'seat': instance.seat, 25 | 'start_time': instance.startTimeStr, 26 | 'end_time': instance.endTimeStr, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/model/message/message.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:json_annotation/json_annotation.dart'; 6 | 7 | part 'message.g.dart'; 8 | 9 | @JsonSerializable(explicitToJson: true) 10 | class UpdateMessage { 11 | final String code; 12 | final List update; 13 | final String ioslink; 14 | final String github; 15 | final String fdroid; 16 | 17 | UpdateMessage({ 18 | required this.code, 19 | required this.update, 20 | required this.ioslink, 21 | required this.github, 22 | required this.fdroid, 23 | }); 24 | 25 | factory UpdateMessage.fromJson(Map json) => 26 | _$UpdateMessageFromJson(json); 27 | 28 | Map toJson() => _$UpdateMessageToJson(this); 29 | } 30 | 31 | @JsonSerializable(explicitToJson: true) 32 | class NoticeMessage { 33 | final String title; 34 | final String message; 35 | final String isLink; 36 | final String type; 37 | 38 | NoticeMessage({ 39 | required this.title, 40 | required this.message, 41 | required this.isLink, 42 | required this.type, 43 | }); 44 | 45 | factory NoticeMessage.fromJson(Map json) => 46 | _$NoticeMessageFromJson(json); 47 | 48 | Map toJson() => _$NoticeMessageToJson(this); 49 | } 50 | -------------------------------------------------------------------------------- /lib/model/message/message.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'message.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | UpdateMessage _$UpdateMessageFromJson(Map json) => 10 | UpdateMessage( 11 | code: json['code'] as String, 12 | update: 13 | (json['update'] as List).map((e) => e as String).toList(), 14 | ioslink: json['ioslink'] as String, 15 | github: json['github'] as String, 16 | fdroid: json['fdroid'] as String, 17 | ); 18 | 19 | Map _$UpdateMessageToJson(UpdateMessage instance) => 20 | { 21 | 'code': instance.code, 22 | 'update': instance.update, 23 | 'ioslink': instance.ioslink, 24 | 'github': instance.github, 25 | 'fdroid': instance.fdroid, 26 | }; 27 | 28 | NoticeMessage _$NoticeMessageFromJson(Map json) => 29 | NoticeMessage( 30 | title: json['title'] as String, 31 | message: json['message'] as String, 32 | isLink: json['isLink'] as String, 33 | type: json['type'] as String, 34 | ); 35 | 36 | Map _$NoticeMessageToJson(NoticeMessage instance) => 37 | { 38 | 'title': instance.title, 39 | 'message': instance.message, 40 | 'isLink': instance.isLink, 41 | 'type': instance.type, 42 | }; 43 | -------------------------------------------------------------------------------- /lib/model/telephone.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | class TeleyInformation { 6 | TeleyInformation({ 7 | required this.title, 8 | this.northAddress, 9 | this.southAddress, 10 | this.northTeley, 11 | this.southTeley, 12 | this.isNorth = false, 13 | this.isSouth = false, 14 | }); 15 | 16 | String title; 17 | bool? isNorth; 18 | bool? isSouth; 19 | String? northAddress; 20 | String? southAddress; 21 | String? northTeley; 22 | String? southTeley; 23 | } 24 | -------------------------------------------------------------------------------- /lib/model/toolbox_addresses.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | import 'package:flutter/widgets.dart'; 5 | 6 | class WebViewAddresses { 7 | final String name; 8 | final String url; 9 | final String description; 10 | final IconData iconData; 11 | 12 | const WebViewAddresses({ 13 | required this.name, 14 | required this.url, 15 | required this.description, 16 | required this.iconData, 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /lib/model/xidian_ids/electricity.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:json_annotation/json_annotation.dart'; 6 | 7 | part 'electricity.g.dart'; 8 | 9 | @JsonSerializable() 10 | class ElectricityInfo { 11 | DateTime fetchDay; 12 | String remain; 13 | String owe; 14 | 15 | ElectricityInfo({ 16 | required this.fetchDay, 17 | required this.remain, 18 | required this.owe, 19 | }); 20 | 21 | factory ElectricityInfo.empty( 22 | DateTime time, 23 | ) => 24 | ElectricityInfo( 25 | fetchDay: time, 26 | remain: "electricity_status.pending", 27 | owe: "electricity_status.pending", 28 | ); 29 | 30 | factory ElectricityInfo.fromJson(Map json) => 31 | _$ElectricityInfoFromJson(json); 32 | 33 | Map toJson() => _$ElectricityInfoToJson(this); 34 | } 35 | -------------------------------------------------------------------------------- /lib/model/xidian_ids/electricity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'electricity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ElectricityInfo _$ElectricityInfoFromJson(Map json) => 10 | ElectricityInfo( 11 | fetchDay: DateTime.parse(json['fetchDay'] as String), 12 | remain: json['remain'] as String, 13 | owe: json['owe'] as String, 14 | ); 15 | 16 | Map _$ElectricityInfoToJson(ElectricityInfo instance) => 17 | { 18 | 'fetchDay': instance.fetchDay.toIso8601String(), 19 | 'remain': instance.remain, 20 | 'owe': instance.owe, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/model/xidian_ids/empty_classroom.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | class EmptyClassroomPlace { 6 | final String name; 7 | final String code; 8 | 9 | EmptyClassroomPlace({ 10 | required this.name, 11 | required this.code, 12 | }); 13 | } 14 | 15 | class EmptyClassroomData { 16 | final String name; 17 | final List isUsed; 18 | 19 | EmptyClassroomData({ 20 | required this.name, 21 | required this.isUsed, 22 | }) : assert(isUsed.length == 10); 23 | } 24 | -------------------------------------------------------------------------------- /lib/model/xidian_ids/exam.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'exam.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Subject _$SubjectFromJson(Map json) => Subject( 10 | subject: json['subject'] as String, 11 | typeStr: json['typeStr'] as String, 12 | time: json['time'] as String, 13 | startTimeStr: json['startTimeStr'] as String, 14 | endTimeStr: json['endTimeStr'] as String, 15 | place: json['place'] as String, 16 | seat: json['seat'] as String?, 17 | ); 18 | 19 | Map _$SubjectToJson(Subject instance) => { 20 | 'subject': instance.subject, 21 | 'typeStr': instance.typeStr, 22 | 'startTimeStr': instance.startTimeStr, 23 | 'endTimeStr': instance.endTimeStr, 24 | 'time': instance.time, 25 | 'place': instance.place, 26 | 'seat': instance.seat, 27 | }; 28 | 29 | ToBeArranged _$ToBeArrangedFromJson(Map json) => ToBeArranged( 30 | subject: json['subject'] as String, 31 | id: json['id'] as String, 32 | ); 33 | 34 | Map _$ToBeArrangedToJson(ToBeArranged instance) => 35 | { 36 | 'subject': instance.subject, 37 | 'id': instance.id, 38 | }; 39 | 40 | ExamData _$ExamDataFromJson(Map json) => ExamData( 41 | subject: (json['subject'] as List) 42 | .map((e) => Subject.fromJson(e as Map)) 43 | .toList(), 44 | toBeArranged: (json['toBeArranged'] as List) 45 | .map((e) => ToBeArranged.fromJson(e as Map)) 46 | .toList(), 47 | ); 48 | 49 | Map _$ExamDataToJson(ExamData instance) => { 50 | 'subject': instance.subject.map((e) => e.toJson()).toList(), 51 | 'toBeArranged': instance.toBeArranged.map((e) => e.toJson()).toList(), 52 | }; 53 | -------------------------------------------------------------------------------- /lib/model/xidian_ids/experiment.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:json_annotation/json_annotation.dart'; 6 | 7 | part 'experiment.g.dart'; 8 | 9 | @JsonSerializable(explicitToJson: true) 10 | class ExperimentData { 11 | final String name; 12 | final String score; 13 | final String classroom; 14 | final String date; 15 | // final String week; 16 | final String timeStr; 17 | final String teacher; 18 | final String reference; 19 | 20 | const ExperimentData({ 21 | required this.name, 22 | required this.score, 23 | required this.classroom, 24 | required this.date, 25 | //required this.week, 26 | required this.timeStr, 27 | required this.teacher, 28 | required this.reference, 29 | }); 30 | 31 | List get time { 32 | /// Return is month/day/year, hope not change... 33 | List dateNums = List.generate( 34 | date.split('/').length, 35 | (index) => int.parse(date.split('/')[index]), 36 | ); 37 | 38 | /// And the time arrangement too. 39 | if (timeStr.contains("15")) { 40 | return [ 41 | DateTime(dateNums[2], dateNums[0], dateNums[1], 15, 55, 00), 42 | DateTime(dateNums[2], dateNums[0], dateNums[1], 18, 10, 00), 43 | ]; // Afternoon 15:55~18:10 44 | } else { 45 | return [ 46 | DateTime(dateNums[2], dateNums[0], dateNums[1], 18, 30, 00), 47 | DateTime(dateNums[2], dateNums[0], dateNums[1], 20, 45, 00), 48 | ]; // Evening 18:30~20:45 49 | } 50 | } 51 | 52 | factory ExperimentData.fromJson(Map json) => 53 | _$ExperimentDataFromJson(json); 54 | 55 | Map toJson() => _$ExperimentDataToJson(this); 56 | } 57 | -------------------------------------------------------------------------------- /lib/model/xidian_ids/experiment.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'experiment.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ExperimentData _$ExperimentDataFromJson(Map json) => 10 | ExperimentData( 11 | name: json['name'] as String, 12 | score: json['score'] as String, 13 | classroom: json['classroom'] as String, 14 | date: json['date'] as String, 15 | timeStr: json['timeStr'] as String, 16 | teacher: json['teacher'] as String, 17 | reference: json['reference'] as String, 18 | ); 19 | 20 | Map _$ExperimentDataToJson(ExperimentData instance) => 21 | { 22 | 'name': instance.name, 23 | 'score': instance.score, 24 | 'classroom': instance.classroom, 25 | 'date': instance.date, 26 | 'timeStr': instance.timeStr, 27 | 'teacher': instance.teacher, 28 | 'reference': instance.reference, 29 | }; 30 | -------------------------------------------------------------------------------- /lib/model/xidian_ids/paid_record.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | class PaidRecord { 6 | String place; 7 | String date; 8 | String money; 9 | PaidRecord({ 10 | required this.place, 11 | required this.date, 12 | required this.money, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /lib/model/xidian_ids/score.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'score.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Score _$ScoreFromJson(Map json) => Score( 10 | mark: (json['mark'] as num).toInt(), 11 | name: json['name'] as String, 12 | score: (json['score'] as num?)?.toDouble(), 13 | semesterCode: json['semesterCode'] as String, 14 | credit: (json['credit'] as num).toDouble(), 15 | classStatus: json['classStatus'] as String, 16 | isPassedStr: json['isPassedStr'] as String?, 17 | scoreTypeCode: (json['scoreTypeCode'] as num).toInt(), 18 | classType: json['classType'] as String, 19 | scoreStatus: json['scoreStatus'] as String, 20 | level: json['level'] as String?, 21 | classID: json['classID'] as String?, 22 | ); 23 | 24 | Map _$ScoreToJson(Score instance) => { 25 | 'mark': instance.mark, 26 | 'name': instance.name, 27 | 'score': instance.score, 28 | 'semesterCode': instance.semesterCode, 29 | 'credit': instance.credit, 30 | 'classStatus': instance.classStatus, 31 | 'classType': instance.classType, 32 | 'scoreStatus': instance.scoreStatus, 33 | 'scoreTypeCode': instance.scoreTypeCode, 34 | 'level': instance.level, 35 | 'isPassedStr': instance.isPassedStr, 36 | 'classID': instance.classID, 37 | }; 38 | -------------------------------------------------------------------------------- /lib/model/xidian_sport/punch.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | /* 5 | import 'package:get/get.dart'; 6 | 7 | 8 | class PunchData { 9 | String machineName; 10 | String weekNum; 11 | Jiffy time; 12 | String stateStr; 13 | 14 | String get state { 15 | if (stateStr.contains("成功")) { 16 | return stateStr.length == 4 ? stateStr : "成功:${stateStr.substring(18)}"; 17 | } else if (stateStr.contains("锻炼间隔需30分钟以上")) { 18 | return stateStr.replaceAll("锻炼间隔需30分钟以上", ""); 19 | } else { 20 | return stateStr; 21 | } 22 | } 23 | 24 | PunchData( 25 | this.machineName, 26 | this.weekNum, 27 | this.time, 28 | this.stateStr, 29 | ); 30 | } 31 | 32 | class PunchDataList { 33 | RxBool isLoad = true.obs; 34 | RxString situation = "".obs; 35 | RxInt allTime = (-1).obs; 36 | RxInt validTime = (-1).obs; 37 | RxDouble score = (-1.0).obs; 38 | RxList all = [].obs; 39 | RxList valid = [].obs; 40 | 41 | void reset() { 42 | isLoad.value = true; 43 | situation = "正在获取".obs; 44 | allTime = (-1).obs; 45 | validTime = (-1).obs; 46 | score = (-1.0).obs; 47 | all.clear(); 48 | valid.clear(); 49 | } 50 | } 51 | */ 52 | -------------------------------------------------------------------------------- /lib/model/xidian_sport/score.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | class SportItems { 6 | String examName; 7 | String examunit; 8 | String actualScore; 9 | double score; 10 | String rank = "不合格"; 11 | 12 | SportItems({ 13 | required this.examName, 14 | required this.examunit, 15 | required this.actualScore, 16 | required this.score, 17 | required this.rank, 18 | }); 19 | } 20 | 21 | class SportScoreOfYear { 22 | String year; 23 | String totalScore; 24 | String rank; 25 | String gradeType; 26 | String moreinfo = ""; 27 | List details = []; 28 | 29 | SportScoreOfYear({ 30 | required this.year, 31 | required this.totalScore, 32 | required this.rank, 33 | required this.gradeType, 34 | }); 35 | } 36 | 37 | class SportScore { 38 | String? situation; 39 | String total = "0.0"; 40 | String rank = ""; 41 | String detail = ""; 42 | List list = []; 43 | } 44 | -------------------------------------------------------------------------------- /lib/page/classtable/arrangement_detail/arrangement_detail.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:watermeter/page/classtable/arrangement_detail/arrangement_list.dart'; 7 | import 'package:watermeter/page/classtable/arrangement_detail/arrangement_detail_state.dart'; 8 | 9 | /// The class info of the period. This is an entry. 10 | class ArrangementDetail extends StatelessWidget { 11 | final int currentWeek; 12 | final List information; 13 | const ArrangementDetail({ 14 | super.key, 15 | required this.currentWeek, 16 | required this.information, 17 | }); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return ArrangementDetailState( 22 | currentWeek: currentWeek, 23 | information: information, 24 | child: const ArrangementList(), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/page/classtable/arrangement_detail/arrangement_detail_state.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:watermeter/model/xidian_ids/classtable.dart'; 7 | 8 | /// This is the shared data in the [ClassDetail]. 9 | class ArrangementDetailState extends InheritedWidget { 10 | final int currentWeek; 11 | final List information; 12 | 13 | const ArrangementDetailState({ 14 | super.key, 15 | required this.currentWeek, 16 | required this.information, 17 | required super.child, 18 | }); 19 | 20 | static ArrangementDetailState? of(BuildContext context) { 21 | return context.dependOnInheritedWidgetOfExactType(); 22 | } 23 | 24 | @override 25 | bool updateShouldNotify(covariant ArrangementDetailState oldWidget) { 26 | return false; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/page/classtable/arrangement_detail/custom_list_tile.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | class CustomListTile extends StatelessWidget { 8 | final IconData icon; 9 | final String str; 10 | final MaterialColor infoColor; 11 | 12 | const CustomListTile({ 13 | super.key, 14 | required this.icon, 15 | required this.str, 16 | required this.infoColor, 17 | }); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Padding( 22 | padding: const EdgeInsets.symmetric( 23 | vertical: 4, 24 | ), 25 | child: Row( 26 | children: [ 27 | Icon( 28 | icon, 29 | color: infoColor.shade900, 30 | ), 31 | const SizedBox(width: 10), 32 | Expanded( 33 | child: Text( 34 | str, 35 | style: TextStyle( 36 | color: infoColor.shade900, 37 | fontSize: 16, 38 | ), 39 | ), 40 | ) 41 | ], 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/page/classtable/class_add/wheel_choser.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 OR MIT 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:styled_widget/styled_widget.dart'; 7 | 8 | class WheelChooseOptions { 9 | T data; 10 | String hint; 11 | 12 | WheelChooseOptions({ 13 | required this.data, 14 | required this.hint, 15 | }); 16 | } 17 | 18 | class WheelChoose extends StatelessWidget { 19 | final ValueChanged changeBookIdCallBack; 20 | final List> options; 21 | final int defaultPage; 22 | 23 | final double heightOfText = 30; 24 | final double widthOfLine = 1; 25 | 26 | const WheelChoose({ 27 | super.key, 28 | required this.changeBookIdCallBack, 29 | required this.options, 30 | this.defaultPage = 0, 31 | }); 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Stack( 36 | children: [ 37 | Container(height: heightOfText) 38 | .border( 39 | top: widthOfLine, 40 | bottom: widthOfLine, 41 | color: Theme.of(context).colorScheme.primary, 42 | ) 43 | .center(), 44 | PageView.builder( 45 | itemCount: options.length, 46 | controller: PageController( 47 | viewportFraction: 1 / 3, 48 | initialPage: defaultPage, 49 | ), 50 | scrollDirection: Axis.vertical, 51 | pageSnapping: true, 52 | physics: const AlwaysScrollableScrollPhysics(), 53 | itemBuilder: (ctx, index) { 54 | return Text(options[index].hint) 55 | .textColor(Theme.of(context).colorScheme.primary) 56 | .center(); 57 | }, 58 | onPageChanged: (int index) { 59 | changeBookIdCallBack(options[index].data); 60 | }, 61 | ), 62 | ], 63 | ).height(heightOfText * 3).alignment(Alignment.center).center(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/page/classtable/class_page/empty_classtable_page.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_i18n/flutter_i18n.dart'; 7 | import 'package:watermeter/page/public_widget/empty_list_view.dart'; 8 | import 'package:watermeter/repository/preference.dart'; 9 | 10 | class EmptyClasstablePage extends StatelessWidget { 11 | const EmptyClasstablePage({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) => EmptyListView( 15 | type: EmptyListViewType.defaultimg, 16 | text: FlutterI18n.translate(context, "classtable.empty_class_message", 17 | translationParams: { 18 | "semester_code": getString(Preference.currentSemester) 19 | }), 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /lib/page/classtable/classtable.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:watermeter/page/classtable/classtable_state.dart'; 7 | import 'package:watermeter/page/classtable/class_page/classtable_page.dart'; 8 | 9 | /// Intro of the classtable. 10 | class ClassTableWindow extends StatelessWidget { 11 | final int currentWeek; 12 | final BuildContext parentContext; 13 | final BoxConstraints constraints; 14 | const ClassTableWindow({ 15 | super.key, 16 | required this.currentWeek, 17 | required this.parentContext, 18 | required this.constraints, 19 | }); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return ClassTableState( 24 | parentContext: parentContext, 25 | constraints: constraints, 26 | controllers: ClassTableWidgetState( 27 | currentWeek: currentWeek, 28 | ), 29 | child: const ClassTablePage(), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/page/classtable/classtable_constant.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 4 | 5 | // These are some constant used in the class table. 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_i18n/flutter_i18n.dart'; 9 | 10 | /// The width of the button. 11 | const weekButtonWidth = 74.0; 12 | 13 | /// The horizontal padding of the button. 14 | const weekButtonHorizontalPadding = 2.0; 15 | 16 | /// The width ratio for the week column. 17 | const double leftRow = 26; 18 | 19 | /// The height of the top row. 20 | const topRowHeightBig = 96.0; 21 | const topRowHeightSmall = 50.0; 22 | 23 | /// Change page time in milliseconds. 24 | const changePageTime = 200; 25 | 26 | /// The height of the middle row. 27 | const midRowHeight = 54.0; 28 | 29 | String getWeekString(BuildContext context, int index) { 30 | List weekList = [ 31 | 'monday', 32 | 'tuesday', 33 | 'wednesday', 34 | 'thursday', 35 | 'friday', 36 | 'saturday', 37 | 'sunday', 38 | ]; 39 | return FlutterI18n.translate( 40 | context, 41 | "weekday.${weekList[index]}", 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /lib/page/homepage/home_card_padding.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | extension HomeCardPadding on Widget { 8 | Widget withHomeCardStyle(BuildContext context) { 9 | return Card( 10 | elevation: 0, 11 | child: DefaultTextStyle( 12 | style: TextStyle( 13 | color: Theme.of(context).brightness == Brightness.dark 14 | ? Theme.of(context).colorScheme.onSurface 15 | : Theme.of(context).colorScheme.onSurfaceVariant, 16 | ), 17 | child: this, 18 | ), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/page/homepage/main_page_card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:watermeter/page/homepage/home_card_padding.dart'; 7 | 8 | class MainPageCard extends StatelessWidget { 9 | final bool isLoad; 10 | final IconData icon; 11 | final String text; 12 | final double? progress; 13 | final Widget infoText; 14 | final Widget bottomText; 15 | final Widget? rightButton; 16 | final bool? isBold; 17 | const MainPageCard({ 18 | super.key, 19 | required this.icon, 20 | required this.text, 21 | required this.infoText, 22 | required this.bottomText, 23 | required this.isLoad, 24 | this.rightButton, 25 | this.progress, 26 | this.isBold, 27 | }); 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return ListTile( 32 | leading: Icon( 33 | icon, 34 | size: 32, 35 | color: Theme.of(context).colorScheme.primary, 36 | ), 37 | textColor: Theme.of(context).brightness == Brightness.dark 38 | ? Theme.of(context).colorScheme.onSurface 39 | : Theme.of(context).colorScheme.onSurfaceVariant, 40 | title: infoText, 41 | subtitle: Builder( 42 | builder: (context) { 43 | if (isLoad || 44 | (progress != null && progress! >= 0 && progress! <= 1)) { 45 | return ClipRRect( 46 | borderRadius: BorderRadius.circular(8), 47 | child: LinearProgressIndicator( 48 | value: isLoad ? null : progress, 49 | minHeight: 4, 50 | ), 51 | ); 52 | } else { 53 | return bottomText; 54 | } 55 | }, 56 | ), 57 | trailing: rightButton, 58 | ).withHomeCardStyle(context); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/page/homepage/small_function_card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_i18n/flutter_i18n.dart'; 7 | import 'package:styled_widget/styled_widget.dart'; 8 | import 'package:watermeter/page/homepage/home_card_padding.dart'; 9 | 10 | class SmallFunctionCard extends StatelessWidget { 11 | final IconData icon; 12 | final String nameKey; 13 | final void Function()? onTap; 14 | final void Function()? onLongPress; 15 | 16 | const SmallFunctionCard({ 17 | super.key, 18 | required this.icon, 19 | required this.nameKey, 20 | this.onTap, 21 | this.onLongPress, 22 | }); 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return [ 27 | Icon( 28 | icon, 29 | size: 32, 30 | color: Theme.of(context).colorScheme.primary, 31 | ), 32 | const SizedBox(height: 4), 33 | Text( 34 | FlutterI18n.translate(context, nameKey), 35 | style: const TextStyle(fontSize: 14), 36 | textAlign: TextAlign.center, 37 | ), 38 | ] 39 | .toColumn(mainAxisAlignment: MainAxisAlignment.center) 40 | .alignment(Alignment.center) 41 | .withHomeCardStyle(context) 42 | .gestures(onTap: onTap); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/page/homepage/toolbox/empty_classroom_card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter_i18n/flutter_i18n.dart'; 6 | import 'package:watermeter/page/public_widget/toast.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:ming_cute_icons/ming_cute_icons.dart'; 9 | import 'package:watermeter/page/public_widget/context_extension.dart'; 10 | import 'package:watermeter/repository/xidian_ids/ids_session.dart'; 11 | import 'package:watermeter/page/empty_classroom/empty_classroom_window.dart'; 12 | import 'package:watermeter/page/homepage/small_function_card.dart'; 13 | 14 | class EmptyClassroomCard extends StatelessWidget { 15 | const EmptyClassroomCard({super.key}); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return SmallFunctionCard( 20 | onTap: () async { 21 | if (offline) { 22 | showToast( 23 | context: context, 24 | msg: FlutterI18n.translate( 25 | context, 26 | "homepage.offline_mode", 27 | ), 28 | ); 29 | } else { 30 | context.pushReplacement(const EmptyClassroomWindow()); 31 | } 32 | }, 33 | icon: MingCuteIcons.mgc_building_2_line, 34 | nameKey: "homepage.toolbox.empty_classroom", 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/page/homepage/toolbox/experiment_card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:get/get.dart'; 7 | import 'package:ming_cute_icons/ming_cute_icons.dart'; 8 | import 'package:watermeter/controller/experiment_controller.dart'; 9 | import 'package:watermeter/page/public_widget/context_extension.dart'; 10 | import 'package:watermeter/page/setting/dialogs/experiment_password_dialog.dart'; 11 | import 'package:watermeter/repository/preference.dart' as preference; 12 | import 'package:watermeter/page/experiment/experiment_window.dart'; 13 | import 'package:watermeter/page/homepage/small_function_card.dart'; 14 | 15 | class ExperimentCard extends StatelessWidget { 16 | const ExperimentCard({super.key}); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return SmallFunctionCard( 21 | onTap: () async { 22 | bool isGood = true; 23 | if (preference 24 | .getString(preference.Preference.experimentPassword) 25 | .isEmpty) { 26 | isGood = await showDialog( 27 | context: context, 28 | builder: (context) => const ExperimentPasswordDialog(), 29 | ) ?? 30 | false; 31 | } 32 | if (context.mounted && isGood == true) { 33 | Get.put(ExperimentController()).get(); 34 | context.pushReplacement(const ExperimentWindow()); 35 | } 36 | }, 37 | icon: MingCuteIcons.mgc_science_line, 38 | nameKey: "homepage.toolbox.experiment", 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/page/homepage/toolbox/score_card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_i18n/flutter_i18n.dart'; 7 | import 'package:watermeter/page/public_widget/toast.dart'; 8 | import 'package:watermeter/page/public_widget/context_extension.dart'; 9 | import 'package:watermeter/page/score/score.dart'; 10 | import 'package:watermeter/repository/xidian_ids/score_session.dart'; 11 | import 'package:watermeter/repository/xidian_ids/ids_session.dart'; 12 | import 'package:watermeter/page/homepage/small_function_card.dart'; 13 | 14 | class ScoreCard extends StatelessWidget { 15 | const ScoreCard({super.key}); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return SmallFunctionCard( 20 | onTap: () { 21 | if (offline && !ScoreSession.isCacheExist) { 22 | showToast( 23 | context: context, 24 | msg: FlutterI18n.translate( 25 | context, 26 | "homepage.toolbox.score_cannot_reach", 27 | ), 28 | ); 29 | } else { 30 | context.pushReplacement(const ScoreWindow()); 31 | } 32 | }, 33 | icon: Icons.grading_rounded, 34 | nameKey: "homepage.toolbox.score", 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/page/homepage/toolbox/sport_card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | // import 'dart:math'; 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:ming_cute_icons/ming_cute_icons.dart'; 9 | // import 'package:talker_flutter/talker_flutter.dart'; 10 | import 'package:watermeter/page/public_widget/context_extension.dart'; 11 | import 'package:watermeter/page/setting/dialogs/sport_password_dialog.dart'; 12 | import 'package:watermeter/page/sport/sport_window.dart'; 13 | import 'package:watermeter/repository/preference.dart' as preference; 14 | import 'package:watermeter/page/homepage/small_function_card.dart'; 15 | 16 | class SportCard extends StatelessWidget { 17 | const SportCard({super.key}); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return SmallFunctionCard( 22 | onTap: () async { 23 | bool isGood = true; 24 | if (preference.getString(preference.Preference.sportPassword).isEmpty) { 25 | isGood = await showDialog( 26 | context: context, 27 | builder: (context) => const SportPasswordDialog(), 28 | ) ?? 29 | false; // 当返回值为 null 时,设置 isGood 为 false 30 | } 31 | if (context.mounted && isGood) { 32 | context.pushReplacement(const SportWindow()); 33 | } 34 | }, 35 | icon: MingCuteIcons.mgc_run_fill, 36 | nameKey: "homepage.toolbox.sport", 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/page/homepage/toolbox/toolbox_card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:ming_cute_icons/ming_cute_icons.dart'; 7 | import 'package:watermeter/page/homepage/small_function_card.dart'; 8 | import 'package:watermeter/page/public_widget/context_extension.dart'; 9 | import 'package:watermeter/page/toolbox/toolbox_page.dart'; 10 | 11 | class ToolboxCard extends StatelessWidget { 12 | const ToolboxCard({super.key}); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return SmallFunctionCard( 17 | onTap: () async { 18 | context.pushReplacement(const ToolBoxPage()); 19 | }, 20 | icon: MingCuteIcons.mgc_tool_line, 21 | nameKey: "homepage.toolbox.toolbox", 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/page/library/ebook_place_card.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:styled_widget/styled_widget.dart'; 7 | import 'package:watermeter/model/xidian_ids/library.dart'; 8 | 9 | class EBookPlaceCard extends StatelessWidget { 10 | final EBookItem toUse; 11 | const EBookPlaceCard({ 12 | super.key, 13 | required this.toUse, 14 | }); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return [ 19 | [ 20 | Icon( 21 | Icons.cloud, 22 | color: Colors.lightBlue.shade900, 23 | ), 24 | const SizedBox(width: 8), 25 | Text( 26 | toUse.collectionName, 27 | style: TextStyle( 28 | fontWeight: FontWeight.w400, 29 | fontSize: 16, 30 | color: Colors.lightBlue.shade900, 31 | ), 32 | ), 33 | ].toRow(), 34 | const SizedBox(height: 8), 35 | Text( 36 | "URL:${toUse.url}", 37 | style: TextStyle( 38 | fontWeight: FontWeight.w400, 39 | color: Colors.lightBlue.shade900, 40 | ), 41 | ), 42 | ] 43 | .toColumn(crossAxisAlignment: CrossAxisAlignment.start) 44 | .padding(all: 12) 45 | .backgroundColor(Colors.lightBlue.shade200) 46 | .clipRRect(all: 12) 47 | .padding(vertical: 4); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/page/library/library_window.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | // Library Window. 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_i18n/flutter_i18n.dart'; 8 | import 'package:watermeter/page/library/borrow_list_window.dart'; 9 | import 'package:watermeter/page/library/search_book_window.dart'; 10 | 11 | class LibraryWindow extends StatelessWidget { 12 | const LibraryWindow({super.key}); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return DefaultTabController( 17 | length: 2, 18 | child: Scaffold( 19 | appBar: AppBar( 20 | title: Text(FlutterI18n.translate(context, "library.title")), 21 | bottom: TabBar( 22 | tabs: [ 23 | Tab( 24 | text: FlutterI18n.translate( 25 | context, 26 | "library.borrow_state_title", 27 | ), 28 | ), 29 | Tab( 30 | text: FlutterI18n.translate( 31 | context, 32 | "library.search_book_title", 33 | ), 34 | ), 35 | ], 36 | ), 37 | ), 38 | body: const TabBarView( 39 | children: [ 40 | BorrowListWindow(), 41 | SearchBookWindow(), 42 | ], 43 | ), 44 | ), 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/page/public_widget/app_icon.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'dart:io'; 6 | import 'package:flutter/widgets.dart'; 7 | 8 | class AppIconWidget extends StatelessWidget { 9 | final double size; 10 | 11 | const AppIconWidget({super.key, this.size = 120}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return ClipRRect( 16 | borderRadius: BorderRadius.all( 17 | Radius.circular(29 * size / 120), 18 | ), 19 | child: Image.asset( 20 | (Platform.isIOS || Platform.isMacOS) 21 | ? "assets/Icon-App-iTunes.png" 22 | : "assets/icon.png", 23 | width: size, 24 | height: size, 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/page/public_widget/column_choose_dialog.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_i18n/flutter_i18n.dart'; 7 | 8 | /// ColumnChooseDialog is a dialog with a [chooseList] to select, return the index in the [chooseList]. 9 | class ColumnChooseDialog extends StatelessWidget { 10 | final List chooseList; 11 | 12 | const ColumnChooseDialog({ 13 | super.key, 14 | required this.chooseList, 15 | }); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return SimpleDialog( 20 | title: Text(FlutterI18n.translate( 21 | context, 22 | "choose_semester", 23 | )), 24 | children: List.generate( 25 | chooseList.length, 26 | (index) => SimpleDialogOption( 27 | onPressed: () => Navigator.of(context).pop(index), 28 | child: ListTile( 29 | title: Text(FlutterI18n.translate( 30 | context, 31 | chooseList[index], 32 | )), 33 | ), 34 | ), 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/page/public_widget/context_extension.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:watermeter/repository/preference.dart'; 7 | 8 | extension BuildContextExt on BuildContext { 9 | Future push(Widget page) => 10 | (splitViewKey.currentState ?? Navigator.of(this)) 11 | .push(MaterialPageRoute(builder: (_) => page)); 12 | 13 | Future pushReplacement(Widget page) { 14 | if (splitViewKey.currentState != null) { 15 | return splitViewKey.currentState!.pushAndRemoveUntil( 16 | MaterialPageRoute(builder: (_) => page), 17 | (route) => route.isFirst && route.isActive, 18 | ); 19 | } else { 20 | return Navigator.of(this).pushReplacement(MaterialPageRoute( 21 | builder: (_) => page, 22 | )); 23 | } 24 | } 25 | 26 | ///( ?? ); 27 | 28 | void pop([T? result]) => Navigator.pop(this, result); 29 | 30 | Future pushDialog( 31 | Widget dialog, { 32 | bool barrierDismissible = true, 33 | Color? barrierColor, 34 | String? barrierLabel, 35 | bool useSafeArea = true, 36 | bool useRootNavigator = true, 37 | RouteSettings? routeSettings, 38 | Offset? anchorPoint, 39 | TraversalEdgeBehavior? traversalEdgeBehavior, 40 | }) => 41 | (splitViewKey.currentState ?? Navigator.of(this)).push( 42 | DialogRoute( 43 | context: splitViewKey.currentState?.context ?? this, 44 | builder: (context) => 45 | Material(type: MaterialType.transparency, child: dialog), 46 | ), 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /lib/page/public_widget/empty_list_view.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | enum EmptyListViewType { 8 | reading, 9 | singing, 10 | defaultimg, 11 | } 12 | 13 | class EmptyListView extends StatelessWidget { 14 | final String text; 15 | final String assets; 16 | 17 | static String _getAssets(EmptyListViewType type) { 18 | switch (type) { 19 | case EmptyListViewType.reading: 20 | return "assets/art/pda_girl_reading.png"; 21 | case EmptyListViewType.singing: 22 | return "assets/art/pda_girl_singing.png"; 23 | default: 24 | return "assets/art/pda_girl_default.png"; 25 | } 26 | } 27 | 28 | EmptyListView({ 29 | super.key, 30 | required this.text, 31 | required EmptyListViewType type, 32 | }) : assets = _getAssets(type); 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Column( 37 | mainAxisAlignment: MainAxisAlignment.center, 38 | children: [ 39 | Image.asset( 40 | assets, 41 | scale: 1.5, 42 | ), 43 | const Divider(color: Colors.transparent), 44 | Text(text), 45 | ], 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/page/public_widget/split_page_placeholder.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'dart:io'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_svg/svg.dart'; 8 | import 'package:styled_widget/styled_widget.dart'; 9 | import 'package:vector_graphics/vector_graphics.dart'; 10 | 11 | class SplitPagePlaceholder extends StatelessWidget { 12 | const SplitPagePlaceholder({super.key}); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | body: Builder(builder: (context) { 18 | if (Platform.isIOS || Platform.isMacOS) { 19 | return Opacity( 20 | opacity: 0.25, 21 | child: Image.asset( 22 | "assets/Icon-App-iTunes-Background.png", 23 | ), 24 | ).constrained(maxWidth: 300); 25 | } else { 26 | return SvgPicture( 27 | const AssetBytesLoader("assets/art/CP1919.svg.vec"), 28 | colorFilter: ColorFilter.mode( 29 | Theme.of(context).colorScheme.primary, 30 | BlendMode.srcIn, 31 | ), 32 | ).constrained(maxWidth: 300, maxHeight: 500); 33 | } 34 | }).center(), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/page/public_widget/timeline_widget/flow_event_row.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:watermeter/page/public_widget/public_widget.dart'; 7 | 8 | @immutable 9 | class FlowEventRow extends StatelessWidget { 10 | const FlowEventRow({ 11 | super.key, 12 | required this.child, 13 | required this.isTitle, 14 | }); 15 | 16 | final Widget child; 17 | final bool isTitle; 18 | 19 | double get circleRadius => 6; 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return Padding( 24 | padding: const EdgeInsets.symmetric( 25 | vertical: 10, 26 | ), 27 | child: Row( 28 | children: [ 29 | Padding( 30 | padding: EdgeInsets.symmetric( 31 | horizontal: isPhone(context) ? 8 : 20 - circleRadius, 32 | ), 33 | child: Container( 34 | width: circleRadius * 2, 35 | height: circleRadius * 2, 36 | decoration: BoxDecoration( 37 | shape: BoxShape.circle, 38 | color: isTitle 39 | ? Theme.of(context).colorScheme.primary 40 | : Colors.transparent, 41 | ), 42 | ), 43 | ), 44 | Expanded( 45 | child: child, 46 | ), 47 | ], 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/page/public_widget/timeline_widget/timeline_title.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | class TimelineTitle extends StatelessWidget { 8 | final String title; 9 | 10 | const TimelineTitle({ 11 | super.key, 12 | required this.title, 13 | }); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Text( 18 | title, 19 | textScaler: const TextScaler.linear(1.1), 20 | style: TextStyle( 21 | color: Theme.of(context).colorScheme.primary, 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/page/public_widget/timeline_widget/timeline_widget.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:watermeter/page/public_widget/timeline_widget/flow_event_row.dart'; 7 | import 'package:watermeter/page/public_widget/public_widget.dart'; 8 | 9 | class TimelineWidget extends StatelessWidget { 10 | final List isTitle; 11 | final List children; 12 | const TimelineWidget({ 13 | super.key, 14 | required this.isTitle, 15 | required this.children, 16 | }) : assert(isTitle.length == children.length); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Align( 21 | alignment: Alignment.topCenter, 22 | child: ConstrainedBox( 23 | constraints: const BoxConstraints(maxWidth: sheetMaxWidth), 24 | child: Stack( 25 | alignment: AlignmentDirectional.center, 26 | fit: StackFit.loose, 27 | children: [ 28 | Positioned( 29 | left: isPhone(context) ? 14 : 20, 30 | top: 16, 31 | bottom: 16, 32 | child: const VerticalDivider( 33 | width: 1, 34 | ), 35 | ), 36 | ListView.builder( 37 | padding: EdgeInsets.zero, 38 | shrinkWrap: true, 39 | itemCount: children.length, 40 | itemBuilder: (BuildContext context, int index) { 41 | return FlowEventRow( 42 | isTitle: isTitle[index], 43 | child: Padding( 44 | padding: const EdgeInsets.symmetric( 45 | horizontal: 8, 46 | vertical: 4, 47 | ), 48 | child: children[index], 49 | ), 50 | ); 51 | }, 52 | ), 53 | ], 54 | ), 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/page/public_widget/toast.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'dart:io'; 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:fluttertoast/fluttertoast.dart'; 9 | 10 | void showToast({ 11 | required BuildContext context, 12 | required String msg, 13 | }) { 14 | if (Platform.isAndroid || Platform.isIOS) { 15 | Fluttertoast.showToast(msg: msg); 16 | } else { 17 | ScaffoldMessenger.of(context).showSnackBar(SnackBar( 18 | content: Text(msg), 19 | )); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/page/schoolnet/data_row.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | import 'package:flutter/widgets.dart'; 5 | 6 | class NetDataRow extends StatelessWidget { 7 | final String label; 8 | final String value; 9 | final Color color; 10 | const NetDataRow({ 11 | super.key, 12 | required this.label, 13 | required this.value, 14 | required this.color, 15 | }); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Padding( 20 | padding: const EdgeInsets.symmetric(vertical: 4.0), 21 | child: Row( 22 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 23 | children: [ 24 | Text( 25 | label, 26 | style: const TextStyle( 27 | fontSize: 16, 28 | ), 29 | ), 30 | Container( 31 | padding: const EdgeInsets.symmetric( 32 | horizontal: 12, 33 | vertical: 6, 34 | ), 35 | decoration: BoxDecoration( 36 | color: color.withValues(alpha: .1), 37 | borderRadius: BorderRadius.circular(20), 38 | ), 39 | child: Text( 40 | value, 41 | style: TextStyle( 42 | fontSize: 16, 43 | fontWeight: FontWeight.bold, 44 | color: color, 45 | ), 46 | ), 47 | ) 48 | ], 49 | ), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/page/schoolnet/device_list.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_i18n/flutter_i18n.dart'; 7 | import 'package:styled_widget/styled_widget.dart'; 8 | 9 | class DeviceList extends StatelessWidget { 10 | final List<(String, String, String)> devices; 11 | const DeviceList({ 12 | super.key, 13 | required this.devices, 14 | }); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return DataTable( 19 | columns: [ 20 | DataColumn( 21 | label: Text(FlutterI18n.translate( 22 | context, 23 | "school_net.device_list.ip", 24 | ))), 25 | DataColumn( 26 | label: Text(FlutterI18n.translate( 27 | context, 28 | "school_net.device_list.time", 29 | ))), 30 | DataColumn( 31 | label: Text(FlutterI18n.translate( 32 | context, 33 | "school_net.device_list.remain", 34 | ))), 35 | ], 36 | rows: devices.map((device) { 37 | return DataRow(cells: [ 38 | DataCell(Text(device.$1)), 39 | DataCell(Text(device.$3)), 40 | DataCell(Text(device.$2)), 41 | ]); 42 | }).toList(), 43 | ).scrollable( 44 | scrollDirection: Axis.horizontal, 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/page/schoolnet/help_guide.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | import 'dart:convert'; 5 | 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; 8 | import 'package:styled_widget/styled_widget.dart'; 9 | 10 | class HelpGuide extends StatelessWidget { 11 | const HelpGuide({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: const Text("Need help?"), 18 | ), 19 | body: FutureBuilder( 20 | future: DefaultAssetBundle.of(context) 21 | .load('assets/guide/README.html') 22 | .then((value) => utf8.decode(value.buffer.asUint8List( 23 | value.offsetInBytes, 24 | value.lengthInBytes, 25 | )..cast())), 26 | builder: (context, snapshot) { 27 | if (snapshot.connectionState == ConnectionState.done) { 28 | // 资源加载完成,显示图片 29 | return HtmlWidget(snapshot.data!) 30 | .constrained(maxWidth: 480) 31 | .padding(all: 12) 32 | .scrollable() 33 | .center(); 34 | } else { 35 | // 资源加载中,显示加载指示器 36 | return const CircularProgressIndicator().center(); 37 | } 38 | }, 39 | ), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/page/score/score_statics.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | enum ScoreFetchState { 6 | ok, 7 | error, 8 | fetching, 9 | } 10 | 11 | const double cardWidth = 280; 12 | 13 | enum ChoiceState { 14 | /// All stuff from the index array. 15 | all, 16 | 17 | /// None stuff from the index array. 18 | none, 19 | 20 | /// Original stuff from the index array. 21 | original, 22 | } 23 | 24 | final courseIgnore = [ 25 | '军事', 26 | '形势与政策', 27 | '创业基础', 28 | '新生', 29 | '写作与沟通', 30 | '学科导论', 31 | '心理', 32 | '物理实验', 33 | ]; 34 | 35 | final typesIgnore = [ 36 | '通识教育选修课', 37 | '集中实践环节', 38 | '拓展提高', 39 | '通识教育核心课', 40 | '专业选修课', 41 | ]; 42 | 43 | const notCoreClassType = "公共任选"; 44 | -------------------------------------------------------------------------------- /lib/page/setting/about_page/developer_widget.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:cached_network_image/cached_network_image.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:styled_widget/styled_widget.dart'; 8 | import 'package:url_launcher/url_launcher.dart'; 9 | import 'package:watermeter/page/public_widget/context_extension.dart'; 10 | 11 | class Developer { 12 | final String name; 13 | final String imageUrl; 14 | final String description; 15 | final String url; 16 | const Developer( 17 | this.name, 18 | this.imageUrl, 19 | this.description, 20 | this.url, 21 | ); 22 | } 23 | 24 | class DeveloperWidget extends StatelessWidget { 25 | final Developer developer; 26 | const DeveloperWidget({ 27 | super.key, 28 | required this.developer, 29 | }); 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return InkWell( 34 | onTap: () => context.pushDialog(AlertDialog( 35 | title: Text(developer.name), 36 | content: Text(developer.description.splitMapJoin( 37 | " / ", 38 | onMatch: (p0) => "\n", 39 | )), 40 | actions: [ 41 | TextButton( 42 | onPressed: () => launchUrl( 43 | Uri.parse(developer.url), 44 | mode: LaunchMode.externalApplication, 45 | ), 46 | child: const Text("More about this guy"), 47 | ) 48 | ], 49 | )), 50 | child: CachedNetworkImage( 51 | fit: BoxFit.fitHeight, 52 | imageUrl: developer.imageUrl, 53 | ).clipOval().constrained( 54 | width: 48, 55 | height: 48, 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/page/setting/about_page/link_widget.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:url_launcher/url_launcher.dart'; 7 | 8 | class Link { 9 | final String name; 10 | final Icon icon; 11 | final String url; 12 | 13 | const Link({ 14 | required this.name, 15 | required this.icon, 16 | required this.url, 17 | }); 18 | } 19 | 20 | class LinkWidget extends StatelessWidget { 21 | final String name; 22 | final Icon icon; 23 | final String url; 24 | const LinkWidget({ 25 | super.key, 26 | required this.name, 27 | required this.icon, 28 | required this.url, 29 | }); 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return ListTile( 34 | minLeadingWidth: 0, 35 | contentPadding: EdgeInsets.zero, 36 | leading: icon, 37 | title: Text(name), 38 | onTap: () => launchUrl( 39 | Uri.parse(url), 40 | mode: LaunchMode.externalApplication, 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/page/sport/sport_window.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | // Intro of the sport data. 6 | // TODO: Fix reloadwidget cannot get the idea... 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_i18n/flutter_i18n.dart'; 10 | import 'package:watermeter/page/sport/sport_class_window.dart'; 11 | import 'package:watermeter/page/sport/sport_score_window.dart'; 12 | 13 | class SportWindow extends StatelessWidget { 14 | const SportWindow({super.key}); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return DefaultTabController( 19 | length: 2, 20 | child: Scaffold( 21 | appBar: AppBar( 22 | title: Text(FlutterI18n.translate( 23 | context, 24 | "sport.title", 25 | )), 26 | bottom: TabBar( 27 | tabs: [ 28 | Tab( 29 | text: FlutterI18n.translate( 30 | context, 31 | "sport.test_score", 32 | ), 33 | ), 34 | Tab( 35 | text: FlutterI18n.translate( 36 | context, 37 | "sport.class_info", 38 | ), 39 | ), 40 | ], 41 | ), 42 | ), 43 | body: const TabBarView( 44 | children: [ 45 | SportScoreWindow(), 46 | SportClassWindow(), 47 | ], 48 | ), 49 | ), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/page/toolbox/webview_list_tile.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:url_launcher/url_launcher_string.dart'; 7 | import 'package:watermeter/model/toolbox_addresses.dart'; 8 | 9 | class WebViewListTile extends StatelessWidget { 10 | final WebViewAddresses data; 11 | const WebViewListTile({ 12 | super.key, 13 | required this.data, 14 | }); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return ListTile( 19 | leading: Icon(data.iconData), 20 | title: Text(data.name), 21 | subtitle: Text(data.description), 22 | onTap: () => launchUrlString( 23 | data.url, 24 | mode: LaunchMode.externalApplication, 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/repository/localization.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | enum Localization { 6 | undefined( 7 | toShow: "setting.localization_dialog.undefined", 8 | string: "", 9 | ), 10 | simplifiedChinese( 11 | toShow: "setting.localization_dialog.simplifiedChinese", 12 | string: "zh_CN", 13 | ), 14 | traditionalChinese( 15 | toShow: "setting.localization_dialog.traditionalChinese", 16 | string: "zh_TW", 17 | ), 18 | english( 19 | toShow: "setting.localization_dialog.english", 20 | string: "en_US", 21 | ); 22 | // english under construction. 23 | 24 | const Localization({ 25 | required this.toShow, 26 | this.string = "", 27 | }); 28 | 29 | final String string; 30 | final String toShow; 31 | } 32 | -------------------------------------------------------------------------------- /lib/repository/logger.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:catcher_2/catcher_2.dart'; 6 | import 'package:talker_dio_logger/talker_dio_logger.dart'; 7 | import 'package:talker_flutter/talker_flutter.dart'; 8 | 9 | final log = TalkerFlutter.init(); 10 | final logDioAdapter = TalkerDioLogger( 11 | talker: log, 12 | settings: const TalkerDioLoggerSettings( 13 | printRequestHeaders: true, 14 | printResponseHeaders: true, 15 | printResponseMessage: true, 16 | ), 17 | ); 18 | 19 | class PDACatcher2Logger extends Catcher2Logger { 20 | @override 21 | void info(String message) { 22 | log.info('Custom Catcher2 Logger | Info | $message'); 23 | } 24 | 25 | @override 26 | void fine(String message) { 27 | log.info('Custom Catcher2 Logger | Fine | $message'); 28 | } 29 | 30 | @override 31 | void warning(String message) { 32 | log.warning('Custom Catcher2 Logger | Warning | $message'); 33 | } 34 | 35 | @override 36 | void severe(String message) { 37 | log.error('Custom Catcher2 Logger | Servere | $message'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/repository/pick_file.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | // Ref. https://github.com/acterglobal/a3/pull/2183/ 6 | // Must detect permission... 7 | 8 | import 'dart:io'; 9 | import 'package:file_picker/file_picker.dart'; 10 | import 'package:device_info_plus/device_info_plus.dart'; 11 | import 'package:permission_handler/permission_handler.dart'; 12 | 13 | Future pickFile({ 14 | FileType type = FileType.any, 15 | }) async { 16 | if (Platform.isAndroid) { 17 | // On Android 8-10 we must be sure to query for the `storage` permission 18 | // before engaging an image-based file-picker 19 | // see https://github.com/miguelpruivo/flutter_file_picker/issues/1461 20 | final androidInfo = await DeviceInfoPlugin().androidInfo; 21 | if (androidInfo.version.sdkInt <= 29) { 22 | if (!(await Permission.storage.request().isGranted)) { 23 | throw MissingStoragePermissionException(); 24 | } 25 | } 26 | } 27 | // Ref. https://github.com/miguelpruivo/flutter_file_picker/issues/1584 28 | // Disable compression:P 29 | return await FilePicker.platform.pickFiles( 30 | type: type, 31 | compressionQuality: 0, 32 | allowMultiple: false, 33 | ); 34 | } 35 | 36 | class MissingStoragePermissionException implements Exception {} 37 | -------------------------------------------------------------------------------- /lib/repository/xdu_planet_session.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | // XDU Planet API. 6 | // I will put my xduplanet.php to my github, which thanks to old computers. 7 | 8 | import 'package:dio/dio.dart'; 9 | import 'package:watermeter/repository/network_session.dart'; 10 | import 'package:watermeter/model/xdu_planet/xdu_planet.dart'; 11 | 12 | class PlanetSession extends NetworkSession { 13 | static const base = "https://xdlinux.github.io/planet"; 14 | static const commentBase = "https://planet.iris.al"; 15 | 16 | Future> getComments(String id) => 17 | dio.get("$commentBase/api/v1/comment/$id").then((value) { 18 | List toReturn = []; 19 | value.data.forEach( 20 | (value) => toReturn.add(XDUPlanetComment.fromJson(value)), 21 | ); 22 | return toReturn; 23 | }); 24 | 25 | Future sendComments({ 26 | required String id, 27 | required String content, 28 | required String userId, 29 | required String? replyto, 30 | }) => 31 | dio 32 | .post("$commentBase/api/v1/comment/$id", 33 | data: { 34 | "content": content, 35 | "user_id": userId, 36 | "reply_to": replyto ?? "", 37 | }, 38 | options: Options(contentType: Headers.jsonContentType)) 39 | .then((value) => value.data.toString()); 40 | 41 | Future auditComments({required int id}) => dio 42 | .delete("$commentBase/api/v1/comment/$id") 43 | .then((value) => value.data.toString()); 44 | 45 | Future content(String dbPath) => dio 46 | .get("$base/${Uri.encodeComponent(dbPath)}") 47 | .then((value) => value.data); 48 | 49 | Future repoList() => dio 50 | .get("$base/index.json") 51 | .then((value) => XDUPlanetDatabase.fromJson(value.data)); 52 | } 53 | -------------------------------------------------------------------------------- /lib/themes/color_seed.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flex_color_scheme/flex_color_scheme.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:watermeter/themes/default.dart'; 8 | import 'package:watermeter/themes/green.dart'; 9 | import 'package:watermeter/themes/orange.dart'; 10 | import 'package:watermeter/themes/pink.dart'; 11 | 12 | /// Colors for the class information card. 13 | const colorList = [ 14 | Colors.red, 15 | Colors.pink, 16 | Colors.purple, 17 | Colors.deepPurple, 18 | Colors.indigo, 19 | Colors.blue, 20 | Colors.lightBlue, 21 | Colors.cyan, 22 | Colors.teal, 23 | Colors.green, 24 | Colors.lightGreen, 25 | Colors.lime, 26 | Colors.yellow, 27 | Colors.orange, 28 | Colors.deepOrange, 29 | Colors.brown, 30 | ]; 31 | 32 | /// Bright mode select 33 | const demoBlueModeMap = { 34 | 0: ThemeMode.system, 35 | 1: ThemeMode.light, 36 | 2: ThemeMode.dark, 37 | }; 38 | 39 | List pdaColorScheme = [ 40 | DefaultColor.light, 41 | DefaultColor.dark, 42 | FlexScheme.blue.colors(Brightness.light), 43 | FlexScheme.blue.colors(Brightness.dark), 44 | FlexScheme.deepPurple.colors(Brightness.light), 45 | FlexScheme.deepPurple.colors(Brightness.dark), 46 | GreenColor.light, 47 | GreenColor.dark, 48 | OrangeColor.light, 49 | OrangeColor.dark, 50 | PinkColor.light, 51 | PinkColor.dark, 52 | ]; 53 | 54 | enum ColorSeed { 55 | indigo('default', 0), 56 | blue('blue', 1), 57 | deepPurple('deepPurple', 2), 58 | green('green', 3), 59 | orange('orange', 4), 60 | pink('pink', 5); 61 | 62 | const ColorSeed(this.label, this.colorOffset); 63 | final String label; 64 | final int colorOffset; 65 | } 66 | 67 | /// Colors for class information card which not in this week. 68 | const uselessColor = Colors.grey; 69 | -------------------------------------------------------------------------------- /lib/themes/default.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flex_color_scheme/flex_color_scheme.dart'; 7 | import 'package:flutter/cupertino.dart'; 8 | 9 | /// Original demo_blue theme. 10 | sealed class DefaultColor { 11 | static FlexSchemeColor light = const FlexSchemeColor( 12 | primary: Color(0xff3f5f90), 13 | primaryContainer: Color(0xffd0e4ff), 14 | primaryLightRef: Color(0xff3f5f90), 15 | secondary: Color(0xff526070), 16 | secondaryContainer: Color(0xffffdbcf), 17 | secondaryLightRef: Color(0xff526070), 18 | tertiary: Color(0xff006875), 19 | tertiaryContainer: Color(0xff95f0ff), 20 | tertiaryLightRef: Color(0xff006875), 21 | appBarColor: Color(0xffffdbcf), 22 | error: Color(0xffba1a1a), 23 | errorContainer: Color(0xffffdad6), 24 | ); 25 | static FlexSchemeColor dark = const FlexSchemeColor( 26 | primary: Color(0xff9fc9ff), 27 | primaryContainer: Color(0xff00325b), 28 | primaryLightRef: Color(0xff3f5f90), 29 | secondary: Color(0xffffb59d), 30 | secondaryContainer: Color(0xff872100), 31 | secondaryLightRef: Color(0xff526070), 32 | tertiary: Color(0xff86d2e1), 33 | tertiaryContainer: Color(0xff004e59), 34 | tertiaryLightRef: Color(0xff006875), 35 | appBarColor: Color(0xffffdbcf), 36 | error: Color(0xffffb4ab), 37 | errorContainer: Color(0xff93000a), 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /lib/themes/green.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | // "Spring breeze green" by LichtYy 6 | // Flowers - Andy Warhol - 1964 7 | 8 | import 'package:flex_color_scheme/flex_color_scheme.dart'; 9 | import 'package:flutter/material.dart'; 10 | 11 | sealed class GreenColor { 12 | // The defined light theme. 13 | static FlexSchemeColor light = const FlexSchemeColor( 14 | // Custom 15 | primary: Color(0xff4ea34c), 16 | primaryContainer: Color(0xff92c692), 17 | primaryLightRef: Color(0xff4ea34c), 18 | secondary: Color(0xffa5e0bd), 19 | secondaryContainer: Color(0xff5fc889), 20 | secondaryLightRef: Color(0xffa5e0bd), 21 | tertiary: Color(0xff7cba34), 22 | tertiaryContainer: Color(0xffafd583), 23 | tertiaryLightRef: Color(0xff7cba34), 24 | appBarColor: Color(0xff5fc889), 25 | error: Color(0xffc33a26), 26 | errorContainer: Color(0xffffcdd3), 27 | ); 28 | // The defined dark theme. 29 | static FlexSchemeColor dark = const FlexSchemeColor( 30 | // Custom 31 | primary: Color(0xff4ea34c), 32 | primaryContainer: Color(0xff73fa70), 33 | primaryLightRef: Color(0xff4ea34c), 34 | secondary: Color(0xff489466), 35 | secondaryContainer: Color(0xff5fc889), 36 | secondaryLightRef: Color(0xffa5e0bd), 37 | tertiary: Color(0xff7cba34), 38 | tertiaryContainer: Color(0xffabff4a), 39 | tertiaryLightRef: Color(0xff7cba34), 40 | appBarColor: Color(0xff5fc889), 41 | error: Color(0xffc33a26), 42 | errorContainer: Color(0xff8e1003), 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /lib/themes/orange.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | // Asuka Orange 6 | 7 | import 'package:flex_color_scheme/flex_color_scheme.dart'; 8 | import 'package:flutter/material.dart'; 9 | 10 | sealed class OrangeColor { 11 | /// Light [ColorScheme] made with FlexColorScheme v8.0.1. 12 | /// Requires Flutter 3.22.0 or later. 13 | static FlexSchemeColor light = const FlexSchemeColor( 14 | // Custom 15 | primary: Color(0xffdb683f), 16 | primaryContainer: Color(0xffd0e4ff), 17 | primaryLightRef: Color(0xffdb683f), 18 | secondary: Color(0xffac3306), 19 | secondaryContainer: Color(0xffffdbcf), 20 | secondaryLightRef: Color(0xffac3306), 21 | tertiary: Color(0xff006875), 22 | tertiaryContainer: Color(0xff95f0ff), 23 | tertiaryLightRef: Color(0xff006875), 24 | appBarColor: Color(0xffffdbcf), 25 | error: Color(0xffba1a1a), 26 | errorContainer: Color(0xffffdad6), 27 | ); 28 | 29 | /// Dark [ColorScheme] made with FlexColorScheme v8.0.1. 30 | /// Requires Flutter 3.22.0 or later. 31 | static FlexSchemeColor dark = const FlexSchemeColor( 32 | // Custom 33 | primary: Color(0xff9fc9ff), 34 | primaryContainer: Color(0xff00325b), 35 | primaryLightRef: Color(0xffdb683f), 36 | secondary: Color(0xffffb59d), 37 | secondaryContainer: Color(0xff872100), 38 | secondaryLightRef: Color(0xffac3306), 39 | tertiary: Color(0xff86d2e1), 40 | tertiaryContainer: Color(0xff004e59), 41 | tertiaryLightRef: Color(0xff006875), 42 | appBarColor: Color(0xffffdbcf), 43 | error: Color(0xffffb4ab), 44 | errorContainer: Color(0xff93000a), 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /lib/themes/pink.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | // "Fox Pink" refer to fn by LichtYy 6 | // Dancers in Pink - Edgar Degas - 1876 7 | 8 | import 'package:flex_color_scheme/flex_color_scheme.dart'; 9 | import 'package:flutter/cupertino.dart'; 10 | import 'package:flutter/material.dart'; 11 | 12 | sealed class PinkColor { 13 | // The defined light theme. 14 | static FlexSchemeColor light = const FlexSchemeColor( 15 | // Custom 16 | primary: Color(0xfff47b8c), 17 | primaryContainer: Color(0xffffd9dc), 18 | primaryLightRef: Color(0xfff47b8c), 19 | secondary: Color(0xffbec9c8), 20 | secondaryContainer: Color(0xff18a78f), 21 | secondaryLightRef: Color(0xffbec9c8), 22 | tertiary: Color(0xffd8734c), 23 | tertiaryContainer: Color(0xfff5d1c4), 24 | tertiaryLightRef: Color(0xffd8734c), 25 | appBarColor: Color(0xff18a78f), 26 | error: Color(0xffe01a05), 27 | errorContainer: Color(0xffffb4a8), 28 | ); 29 | // The defined dark theme. 30 | static FlexSchemeColor dark = const FlexSchemeColor( 31 | // Custom 32 | primary: Color(0xfff47b8c), 33 | primaryContainer: Color(0xffe91e63), 34 | primaryLightRef: Color(0xfff47b8c), 35 | secondary: Color(0xff506864), 36 | secondaryContainer: Color(0xff18a78f), 37 | secondaryLightRef: Color(0xffbec9c8), 38 | tertiary: Color(0xffd8734c), 39 | tertiaryContainer: Color(0xfffa4e0c), 40 | tertiaryLightRef: Color(0xffd8734c), 41 | appBarColor: Color(0xff18a78f), 42 | error: Color(0xffe01a05), 43 | errorContainer: Color(0xff8e1003), 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /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) charset_converter_registrar = 14 | fl_plugin_registry_get_registrar_for_plugin(registry, "CharsetConverterPlugin"); 15 | charset_converter_plugin_register_with_registrar(charset_converter_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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | charset_converter 7 | url_launcher_linux 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | tflite_flutter 12 | ) 13 | 14 | set(PLUGIN_BUNDLED_LIBRARIES) 15 | 16 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 17 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux 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}/linux plugins/${ffi_plugin}) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 26 | endforeach(ffi_plugin) 27 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /linux/packaging/appimage/make_config.yaml: -------------------------------------------------------------------------------- 1 | display_name: watermeter 2 | 3 | icon: assets/icon.png 4 | 5 | keywords: 6 | - watermeter 7 | 8 | generic_name: watermeter 9 | 10 | # supported mime types that can be opened using this application 11 | # supported_mime_type: 12 | # - audio/mpeg 13 | 14 | metainfo: linux/packaging/watermeter.appdata.xml 15 | 16 | actions: [] 17 | 18 | categories: 19 | - Education 20 | 21 | startup_notify: true 22 | 23 | # You can specify the shared libraries that you want to bundle with your app 24 | # 25 | # fastforge automatically detects the shared libraries that your app 26 | # depends on, but you can also specify them manually here. 27 | # 28 | # The following example shows how to bundle the libcurl library with your app. 29 | # 30 | # include: 31 | # - libcurl.so.4 32 | include: [] 33 | 34 | -------------------------------------------------------------------------------- /linux/packaging/watermeter.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | watermeter 4 | CC0-1.0 5 | MIT 6 | watermeter 7 | watermeter 8 | 9 |

szgg

10 |
11 | watermeter.desktop 12 | https://github.com/BenderBlog/traintime_pda 13 | 14 | watermeter.desktop 15 | 16 | 17 | 18 | benderblog 19 | 20 |
21 | 22 | -------------------------------------------------------------------------------- /pigeon_bridge/copyright_header.txt: -------------------------------------------------------------------------------- 1 | Copyright 2024 BenderBlog Rodriguez and contributors. 2 | SPDX-License-Identifier: MPL-2.0 3 | 4 | -------------------------------------------------------------------------------- /pigeon_bridge/save_to_groupid.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 BenderBlog Rodriguez and contributors 2 | // Copyright 2025 Traintime PDA authors. 3 | // SPDX-License-Identifier: MPL-2.0 4 | 5 | import 'package:pigeon/pigeon.dart'; 6 | 7 | @ConfigurePigeon(PigeonOptions( 8 | dartOut: 'lib/bridge/save_to_groupid.g.dart', 9 | dartOptions: DartOptions(), 10 | swiftOut: 'ios/Runner/SaveToGroupID.g.swift', 11 | swiftOptions: SwiftOptions(), 12 | copyrightHeader: "pigeon_bridge/copyright_header.txt", 13 | )) 14 | class FileToGroupID { 15 | FileToGroupID({ 16 | required this.appid, 17 | required this.fileName, 18 | required this.data, 19 | }); 20 | String appid; 21 | String fileName; 22 | String data; 23 | } 24 | 25 | @HostApi() 26 | abstract class SaveToGroupIdSwiftApi { 27 | String getHostLanguage(); 28 | 29 | @async 30 | bool saveToGroupId(FileToGroupID data); 31 | } 32 | 33 | abstract class SaveToGroupIdFlutterApi { 34 | bool saveToGroupId(FileToGroupID data); 35 | } 36 | -------------------------------------------------------------------------------- /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 in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | /* 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:watermeter/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(const 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 | */ -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | #include 12 | #include 13 | 14 | void RegisterPlugins(flutter::PluginRegistry* registry) { 15 | CharsetConverterPluginRegisterWithRegistrar( 16 | registry->GetRegistrarForPlugin("CharsetConverterPlugin")); 17 | PermissionHandlerWindowsPluginRegisterWithRegistrar( 18 | registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); 19 | SharePlusWindowsPluginCApiRegisterWithRegistrar( 20 | registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); 21 | UrlLauncherWindowsRegisterWithRegistrar( 22 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 23 | } 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | charset_converter 7 | permission_handler_windows 8 | share_plus 9 | url_launcher_windows 10 | ) 11 | 12 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 13 | tflite_flutter 14 | ) 15 | 16 | set(PLUGIN_BUNDLED_LIBRARIES) 17 | 18 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 19 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 20 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 23 | endforeach(plugin) 24 | 25 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 26 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 27 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 28 | endforeach(ffi_plugin) 29 | -------------------------------------------------------------------------------- /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_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.Create(L"traintime_pda", 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenderBlog/traintime_pda/671f0a373175b8b56e303c4435c2a9f8396cd2cd/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length <= 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------