├── .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 |
--------------------------------------------------------------------------------