├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── -----.md │ └── bug--.md ├── PULL_REQUEST_TEMPLATE │ └── pull_request_template.md └── workflows │ ├── ci_android.yml │ ├── ci_ios.yml │ ├── ci_linux.yml │ ├── ci_windows.yml │ └── deploy_to_gh-pages.yml ├── .gitignore ├── .metadata ├── CI └── ExportOptions.plist ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── README_EN.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ ├── google-services.json │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── github │ │ │ │ └── w568w │ │ │ │ └── dan_xi │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ └── ic_launcher.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ ├── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ ├── backup_rules.xml │ │ │ └── data_extraction_rules.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── settings_aar.gradle ├── assets ├── fonts │ └── iconfont.ttf ├── graphics │ ├── Boreas618.jpg │ ├── Dest1n1.jpg │ ├── Frankstein73.jpg │ ├── HydrogenC.jpg │ ├── JingYiJun.jpg │ ├── app_icon.ico │ ├── fsy2001.jpg │ ├── hasbai.jpeg │ ├── ivanfei.jpg │ ├── kavinzhao.jpeg │ ├── koowz.jpg │ ├── kyln24.jpeg │ ├── ot_logo.png │ └── w568w.jpeg └── texts │ ├── care_words.dat │ ├── stop_words.dat │ └── tips.dat ├── build.yaml ├── build_release.dart ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── ephemeral │ │ ├── flutter_lldb_helper.py │ │ └── flutter_lldbinit ├── Gemfile ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ ├── Runner.xcscheme │ │ ├── nano (Complication).xcscheme │ │ └── nano.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── 1.2.0-1024.png │ │ │ ├── 1.2.0-20.png │ │ │ ├── 1.2.0-20@2x.png │ │ │ ├── 1.2.0-20@3x.png │ │ │ ├── 1.2.0-29.png │ │ │ ├── 1.2.0-29@2x.png │ │ │ ├── 1.2.0-29@3x.png │ │ │ ├── 1.2.0-40.png │ │ │ ├── 1.2.0-40@2x.png │ │ │ ├── 1.2.0-40@3x.png │ │ │ ├── 1.2.0-60@2x.png │ │ │ ├── 1.2.0-60@3x.png │ │ │ ├── 1.2.0-76.png │ │ │ ├── 1.2.0-76@2x.png │ │ │ ├── 1.2.0-83.5@2x.png │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ ├── Base.lproj │ │ ├── InfoPlist.strings │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── MLModels.swift │ ├── Runner-Bridging-Header.h │ ├── Runner.entitlements │ ├── TagPredictorME.mlpackage │ │ ├── Data │ │ │ └── com.apple.CoreML │ │ │ │ ├── FeatureDescriptions.json │ │ │ │ ├── Metadata.json │ │ │ │ └── TagPredictor.mlmodel │ │ └── Manifest.json │ ├── TagPredictorTL.mlmodel │ ├── TagPredictorTL.mlmodelkey │ ├── TagPredictorTL.mlpackage │ │ ├── Data │ │ │ └── com.apple.CoreML │ │ │ │ ├── FeatureDescriptions.json │ │ │ │ ├── Metadata.json │ │ │ │ └── TagPredictorTL.mlmodel │ │ └── Manifest.json │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── ja.lproj │ │ ├── InfoPlist.strings │ │ ├── LaunchScreen.strings │ │ └── Main.strings │ └── zh-Hans.lproj │ │ ├── InfoPlist.strings │ │ ├── LaunchScreen.strings │ │ └── Main.strings ├── fastlane │ ├── Appfile │ └── Fastfile ├── nano Extension │ ├── Assets.xcassets │ │ ├── Complication.complicationset │ │ │ ├── Circular.imageset │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Extra Large.imageset │ │ │ │ └── Contents.json │ │ │ ├── Graphic Bezel.imageset │ │ │ │ └── Contents.json │ │ │ ├── Graphic Circular.imageset │ │ │ │ └── Contents.json │ │ │ ├── Graphic Corner.imageset │ │ │ │ └── Contents.json │ │ │ ├── Graphic Extra Large.imageset │ │ │ │ └── Contents.json │ │ │ ├── Graphic Large Rectangular.imageset │ │ │ │ └── Contents.json │ │ │ ├── Modular.imageset │ │ │ │ └── Contents.json │ │ │ └── Utilitarian.imageset │ │ │ │ └── Contents.json │ │ └── Contents.json │ ├── ComplicationController.swift │ ├── Info.plist │ ├── Models │ │ └── TreeHoleModels.swift │ ├── Pages │ │ ├── TreeHoleDetailsPage.swift │ │ └── TreeHolePage.swift │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── TreeHoleRepository.swift │ ├── Views │ │ ├── THPostDetailView.swift │ │ └── THPostView.swift │ ├── WatchConnectivity.swift │ ├── en.lproj │ │ └── Localizable.strings │ ├── ja.lproj │ │ └── Localizable.strings │ ├── nano Extension.entitlements │ └── zh-Hans.lproj │ │ └── Localizable.strings ├── nano │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── 1.2.0-1024@1x.png │ │ │ ├── 1.2.0-108@2x.png │ │ │ ├── 1.2.0-24@2x.png │ │ │ ├── 1.2.0-24@3x.png │ │ │ ├── 1.2.0-27-5@2x.png │ │ │ ├── 1.2.0-29@2x.png │ │ │ ├── 1.2.0-40@2x.png │ │ │ ├── 1.2.0-44@2x.png │ │ │ ├── 1.2.0-50@2x.png │ │ │ ├── 1.2.0-86@2x.png │ │ │ ├── 1.2.0-98@2x.png │ │ │ └── Contents.json │ │ └── Contents.json │ └── Info.plist └── nanoDanxi WatchKit Extension │ ├── ContentView.swift │ └── RunnerApp.swift ├── lib ├── common │ ├── constant.dart │ ├── feature_registers.dart │ └── icon_fonts.dart ├── feature │ ├── aao_notice_feature.dart │ ├── base_feature.dart │ ├── bus_feature.dart │ ├── custom_shortcut.dart │ ├── dining_hall_crowdedness_feature.dart │ ├── dorm_electricity_feature.dart │ ├── ecard_balance_feature.dart │ ├── empty_classroom_feature.dart │ ├── feature_map.dart │ ├── fudan_library_crowdedness_feature.dart │ ├── lan_connection_notification.dart │ ├── next_course_feature.dart │ ├── pe_feature.dart │ ├── qr_feature.dart │ └── welcome_feature.dart ├── l10n │ ├── intl_en.arb │ ├── intl_ja.arb │ └── intl_zh_CN.arb ├── main.dart ├── model │ ├── announcement.dart │ ├── celebration.dart │ ├── danke │ │ ├── course.dart │ │ ├── course_grade.dart │ │ ├── course_group.dart │ │ ├── course_review.dart │ │ ├── review_extra.dart │ │ ├── reviewer_achievements.dart │ │ └── search_results.dart │ ├── dashboard_card.dart │ ├── extra.dart │ ├── forum │ │ ├── audit.dart │ │ ├── division.dart │ │ ├── floor.dart │ │ ├── floors.dart │ │ ├── history.dart │ │ ├── hole.dart │ │ ├── jwt.dart │ │ ├── message.dart │ │ ├── punishment.dart │ │ ├── quiz_answer.dart │ │ ├── quiz_question.dart │ │ ├── report.dart │ │ ├── tag.dart │ │ ├── user.dart │ │ ├── user_config.dart │ │ └── user_permission.dart │ ├── person.dart │ ├── remote_sticker.dart │ └── time_table.dart ├── page │ ├── danke │ │ ├── course_group_detail.dart │ │ └── course_review_editor.dart │ ├── dashboard │ │ ├── aao_notices.dart │ │ ├── announcement_notices.dart │ │ ├── bus.dart │ │ ├── card_detail.dart │ │ ├── card_traffic.dart │ │ ├── dashboard_reorder.dart │ │ ├── empty_classroom_detail.dart │ │ ├── exam_detail.dart │ │ └── gpa_table.dart │ ├── forum │ │ ├── admin_operation.dart │ │ ├── hole_detail.dart │ │ ├── hole_editor.dart │ │ ├── hole_login.dart │ │ ├── hole_messages.dart │ │ ├── hole_reports.dart │ │ ├── hole_search.dart │ │ ├── hole_tags.dart │ │ ├── image_viewer.dart │ │ ├── quiz.dart │ │ └── text_selector.dart │ ├── home_page.dart │ ├── login_page.dart │ ├── platform_subpage.dart │ ├── settings │ │ ├── diagnostic_console.dart │ │ ├── hidden_tags_preference.dart │ │ └── open_source_license.dart │ ├── subpage_danke.dart │ ├── subpage_dashboard.dart │ ├── subpage_forum.dart │ ├── subpage_settings.dart │ └── subpage_timetable.dart ├── provider │ ├── forum_provider.dart │ ├── language_manager.dart │ ├── notification_provider.dart │ ├── settings_provider.dart │ └── state_provider.dart ├── repository │ ├── app │ │ └── announcement_repository.dart │ ├── base_repository.dart │ ├── cookie │ │ ├── independent_cookie_jar.dart │ │ ├── parallel_cookie_jars.dart │ │ └── readonly_cookie_jar.dart │ ├── danke │ │ └── curriculum_board_repository.dart │ ├── fdu │ │ ├── aao_repository.dart │ │ ├── bus_repository.dart │ │ ├── data_center_repository.dart │ │ ├── dorm_repository.dart │ │ ├── ecard_repository.dart │ │ ├── edu_service_repository.dart │ │ ├── ehall_repository.dart │ │ ├── empty_classroom_repository.dart │ │ ├── library_repository.dart │ │ ├── neo_login_tool.dart │ │ ├── pe_repository.dart │ │ ├── postgraduate_timetable_repository.dart │ │ ├── qr_code_repository.dart │ │ ├── sports_reserve_repository.dart │ │ ├── time_table_repository.dart │ │ └── uis_login_tool.dart │ └── forum │ │ └── forum_repository.dart ├── test │ └── test.dart ├── util │ ├── animation.dart │ ├── browser_util.dart │ ├── condition_variable.dart │ ├── danxi_care.dart │ ├── flutter_app.dart │ ├── forum │ │ ├── clean_mode_filter.dart │ │ ├── editor_object.dart │ │ ├── fduhole_platform_bridge.dart │ │ ├── human_duration.dart │ │ └── jwt_interceptor.dart │ ├── haptic_feedback_util.dart │ ├── io │ │ ├── cache.dart │ │ ├── cache_manager_with_webvpn.dart │ │ ├── cookie_manager_fix.dart │ │ ├── dio_utils.dart │ │ ├── queued_interceptor.dart │ │ └── user_agent_interceptor.dart │ ├── js │ │ ├── js.dart │ │ └── js_web.dart │ ├── lazy_future.dart │ ├── master_detail_utils.dart │ ├── master_detail_view.dart │ ├── noticing.dart │ ├── platform_universal.dart │ ├── public_extension_methods.dart │ ├── retrier.dart │ ├── screen_proxy.dart │ ├── scroller_fix │ │ └── mirror_scroll_controller.dart │ ├── shared_preferences.dart │ ├── smart_widget.dart │ ├── sticker_download_manager.dart │ ├── stream_listener.dart │ ├── timetable_converter_impl.dart │ ├── universal_link │ │ ├── apple-app-site-association.json │ │ └── assetlinks.json │ ├── vague_time.dart │ ├── viewport_utils.dart │ ├── watermark.dart │ ├── webvpn_proxy.dart │ └── win32 │ │ ├── auto_start.dart │ │ ├── auto_start_stub.dart │ │ ├── registry.dart │ │ └── shell.dart └── widget │ ├── danke │ ├── course_list_widget.dart │ ├── course_review_widget.dart │ ├── course_search_bar.dart │ ├── course_widgets.dart │ ├── random_review_widgets.dart │ └── review_vote_widget.dart │ ├── dialogs │ ├── care_dialog.dart │ ├── login_dialog.dart │ ├── manually_add_course_dialog.dart │ ├── manually_add_course_dialog_sub.dart │ ├── new_shortcut_widget_dialog.dart │ ├── qr_code_dialog.dart │ └── swatch_picker_dialog.dart │ ├── feature_item │ ├── feature_card_item.dart │ ├── feature_list_item.dart │ └── feature_progress_indicator.dart │ ├── forum │ ├── auto_banner.dart │ ├── auto_bbs_image.dart │ ├── bbs_tags_container.dart │ ├── flutter_watermark_widget.dart │ ├── forum_widgets.dart │ ├── horizontal_selector.dart │ ├── login_widgets.dart │ ├── ottag_selector.dart │ ├── post_render.dart │ ├── render │ │ ├── base_render.dart │ │ └── render_impl.dart │ └── tag_selector │ │ ├── flutter_tagging │ │ ├── configurations.dart │ │ ├── taggable.dart │ │ └── tagging.dart │ │ ├── selector.dart │ │ └── tag.dart │ ├── libraries │ ├── chip_widgets.dart │ ├── dynamic_theme.dart │ ├── error_page_widget.dart │ ├── future_widget.dart │ ├── image_picker_proxy.dart │ ├── linkify_x.dart │ ├── material_banner.dart │ ├── material_x.dart │ ├── paged_listview.dart │ ├── platform_app_bar_ex.dart │ ├── platform_context_menu.dart │ ├── platform_nav_bar_m3.dart │ ├── scale_transform.dart │ ├── sized_by_child_builder.dart │ ├── small_tag.dart │ ├── state_key.dart │ ├── top_controller.dart │ └── with_scrollbar.dart │ └── time_table │ ├── day_events.dart │ ├── event.dart │ └── schedule_view.dart ├── linux ├── .gitignore ├── CMakeLists.txt ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── main.cc ├── my_application.cc └── my_application.h ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── 1024.png │ │ ├── 128.png │ │ ├── 16.png │ │ ├── 256 1.png │ │ ├── 256.png │ │ ├── 32 1.png │ │ ├── 32.png │ │ ├── 512 1.png │ │ ├── 512.png │ │ ├── 64.png │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ └── MainMenu.xib │ ├── Configs │ ├── AppInfo.xcconfig │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ ├── Release.entitlements │ └── zh-Hans.lproj │ └── MainMenu.strings ├── packaging ├── dan_xi.png └── io.github.danxi_dev.dan_xi.desktop ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart ├── web ├── favicon.webp ├── index.html └── manifest.json └── windows ├── .gitignore ├── CMakeLists.txt ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake └── runner ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── resources └── app_icon.ico ├── run_loop.cpp ├── run_loop.h ├── 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: ["https://afdian.net/@danxi-dev"] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-----.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 请求新功能 3 | about: 请求APP加入新的功能! 4 | title: "[Feature Request]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **你的功能需求和某个bug有关吗?** 11 | `[是/否]` 12 | 13 | **你想要什么样的功能?** 14 | 简要、清晰地描述你请求增加的功能。 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug--.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug报告 3 | about: 说明你遇到的Bug。 4 | title: "[BUG] " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **描述 Bug** 11 | 简要描述 Bug 是什么。 12 | 如果你认为标题已经说得很清楚了,可以删除这一项。 13 | 14 | **复现步骤** 15 | 复现该 Bug 的步骤: 16 | 1. 到 xx 页面 17 | 2. 点击 xxx 18 | 3. 选择 xxx 19 | 4. 出现错误 20 | 21 | **截图** 22 | 如果方便的话,你可以添加截图。 23 | 24 | **系统信息** 25 | - 设备型号: 26 | - 系统版本: 27 | - 旦挞校园助手版本(见「设置-关于本应用」): 28 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request_template.md: -------------------------------------------------------------------------------- 1 | This fixes # . 2 | 3 | Other changes in this pull request: 4 | - 5 | - 6 | - 7 | - 8 | -------------------------------------------------------------------------------- /.github/workflows/ci_linux.yml: -------------------------------------------------------------------------------- 1 | name: Automated-CI-Linux 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tag_name: 7 | description: "Tag name for release. If set to nightly, the release will be a pre-release." 8 | required: false 9 | default: nightly 10 | 11 | jobs: 12 | Automated-CI-Linux: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | - name: Install Flutter 18 | uses: subosito/flutter-action@v2 19 | with: 20 | channel: 'stable' 21 | - name: Install Flutter Linux Dependencies 22 | run: | 23 | sudo apt-get update -y 24 | sudo apt-get install -y ninja-build libgtk-3-dev libsecret-1-dev 25 | - name: Prepare Flutter Dependencies 26 | run: | 27 | flutter pub get 28 | flutter pub global activate intl_utils 29 | flutter pub global run intl_utils:generate 30 | 31 | - name: Build Executable 32 | run: | 33 | dart build_release.dart --target linux --versionCode dummy 34 | 35 | - if: github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name != 'nightly' 36 | name: Release 37 | uses: softprops/action-gh-release@v1 38 | with: 39 | files: build/app/DanXi-dummy-release.linux-x64.zip 40 | prerelease: false 41 | tag_name: ${{ github.event.inputs.tag_name }} 42 | name: Release ${{ github.ref }} 43 | generate_release_notes: true 44 | fail_on_unmatched_files: true 45 | 46 | - if: github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name == 'nightly' 47 | name: Release Nightly 48 | uses: softprops/action-gh-release@v1 49 | with: 50 | files: build/app/DanXi-dummy-release.linux-x64.zip 51 | prerelease: true 52 | tag_name: nightly 53 | name: Nightly build 54 | generate_release_notes: true 55 | fail_on_unmatched_files: true 56 | -------------------------------------------------------------------------------- /.github/workflows/ci_windows.yml: -------------------------------------------------------------------------------- 1 | name: Automated-CI-Windows 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tag_name: 7 | description: "Tag name for release. If set to nightly, the release will be a pre-release." 8 | required: false 9 | default: nightly 10 | 11 | jobs: 12 | Automated-CI-Windows: 13 | runs-on: windows-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | - name: Workaround - Export pub environment variable on Windows 18 | run: | 19 | if [ "$RUNNER_OS" == "Windows" ]; then 20 | echo "PUB_CACHE=$LOCALAPPDATA\\Pub\\Cache" >> $GITHUB_ENV 21 | fi 22 | shell: bash 23 | - name: Install Flutter 24 | uses: subosito/flutter-action@v2 25 | with: 26 | channel: 'stable' 27 | 28 | - name: Prepare Flutter Dependencies 29 | run: | 30 | flutter pub get 31 | flutter pub global activate intl_utils 32 | flutter pub global run intl_utils:generate 33 | 34 | - name: Build Executable 35 | run: | 36 | dart build_release.dart --target windows --versionCode dummy 37 | 38 | - if: github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name != 'nightly' 39 | name: Release 40 | uses: softprops/action-gh-release@v1 41 | with: 42 | files: build/app/DanXi-dummy-release.windows-x64.zip 43 | prerelease: false 44 | tag_name: ${{ github.event.inputs.tag_name }} 45 | name: Release ${{ github.ref }} 46 | generate_release_notes: true 47 | fail_on_unmatched_files: true 48 | 49 | - if: github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name == 'nightly' 50 | name: Release Nightly 51 | uses: softprops/action-gh-release@v1 52 | with: 53 | files: build/app/DanXi-dummy-release.windows-x64.zip 54 | prerelease: true 55 | tag_name: nightly 56 | name: Nightly build 57 | generate_release_notes: true 58 | fail_on_unmatched_files: true 59 | -------------------------------------------------------------------------------- /.github/workflows/deploy_to_gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | Deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - name: Install Flutter 14 | uses: subosito/flutter-action@v2 15 | with: 16 | channel: "stable" 17 | 18 | - name: Prepare Dependencies 19 | run: | 20 | flutter pub get 21 | flutter pub global activate intl_utils 22 | flutter pub global run intl_utils:generate 23 | 24 | - name: Generate Models 25 | run: dart run build_runner build --delete-conflicting-outputs 26 | 27 | - name: Build 28 | run: | 29 | flutter build web --release --optimization-level 4 30 | 31 | - name: Deploy 🚀 32 | uses: JamesIves/github-pages-deploy-action@v4.2.5 33 | with: 34 | branch: gh-pages 35 | folder: build/web 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | .gradle/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | lib/generated/ 35 | **/*.g.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | 48 | # VSCode 49 | .vscode 50 | 51 | # macOS 52 | ios/build 53 | 54 | # Private Key 55 | macos/Podfile.lock 56 | 57 | # Visual Studio 58 | windows/.vs 59 | windows/out 60 | ios/fastlane/Matchfile 61 | 62 | # FVM Version Cache 63 | .fvm/ 64 | .fvmrc 65 | 66 | # Flutter DevTools 67 | devtools_options.yaml 68 | 69 | # Android NDK build intermediate files 70 | android/app/.cxx 71 | 72 | # Claude Code 73 | /CLAUDE.md 74 | /.claude/*.local.* 75 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 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: f468f3366c26a5092eb964a230ce7892fda8f2f8 17 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 18 | - platform: linux 19 | create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 20 | base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 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 | -------------------------------------------------------------------------------- /CI/ExportOptions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | destination 6 | export 7 | method 8 | app-store 9 | signingStyle 10 | automatic 11 | stripSwiftSymbols 12 | 13 | teamID 14 | QZ9KCS2T78 15 | uploadBitcode 16 | 17 | uploadSymbols 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /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.cn/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 | constant_identifier_names: false 26 | prefer_function_declarations_over_variables: false 27 | empty_catches: false 28 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 29 | 30 | # Additional information about this file can be found at 31 | # https://dart.cn/guides/language/analysis-options 32 | 33 | analyzer: 34 | exclude: [ build/**, lib/generated/** ] 35 | language: 36 | strict-raw-types: true -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | /app/.cxx/ 10 | 11 | # Remember to never publicly share your keystore. 12 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 13 | key.properties 14 | 15 | /app/.cxx/ 16 | /build/reports/ -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "859967910399", 4 | "project_id": "danxi-e765c", 5 | "storage_bucket": "danxi-e765c.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:859967910399:android:ce65a6929f5eafbf5a37ca", 11 | "android_client_info": { 12 | "package_name": "io.github.w568w.dan_xi" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "859967910399-2bvug8if8fkdmeld2oo324hp9845ntgj.apps.googleusercontent.com", 18 | "client_type": 3 19 | } 20 | ], 21 | "api_key": [ 22 | { 23 | "current_key": "AIzaSyAqUjb40DipIBoX0atb3pIgKUimXLvU9uw" 24 | } 25 | ], 26 | "services": { 27 | "appinvite_service": { 28 | "other_platform_oauth_client": [ 29 | { 30 | "client_id": "859967910399-2bvug8if8fkdmeld2oo324hp9845ntgj.apps.googleusercontent.com", 31 | "client_type": 3 32 | } 33 | ] 34 | } 35 | } 36 | } 37 | ], 38 | "configuration_version": "1" 39 | } -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Flutter Wrapper 2 | -keep class io.flutter.plugin.** { *; } 3 | -keep class io.flutter.util.** { *; } 4 | -keep class io.flutter.view.** { *; } 5 | -keep class io.flutter.plugins.** { *; } 6 | -keep class de.prosiebensat1digital.** { *; } -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/io/github/w568w/dan_xi/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package io.github.w568w.dan_xi 19 | 20 | import io.flutter.embedding.android.FlutterActivity 21 | 22 | class MainActivity : FlutterActivity() { 23 | } 24 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 校园助手 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | import groovy.xml.XmlSlurper 2 | 3 | allprojects { 4 | repositories { 5 | google() 6 | mavenCentral() 7 | } 8 | } 9 | 10 | rootProject.buildDir = '../build' 11 | 12 | 13 | subprojects { 14 | afterEvaluate { project -> 15 | // override the android compileSdkVersion and namespace for each dependencies to compile with the latest Gradle 16 | if (project.plugins.hasPlugin("com.android.application") || 17 | project.plugins.hasPlugin("com.android.library")) { 18 | project.android.compileSdkVersion = 36 19 | 20 | // override Java version to 23 21 | project.android.compileOptions.sourceCompatibility = JavaVersion.VERSION_23 22 | project.android.compileOptions.targetCompatibility = JavaVersion.VERSION_23 23 | 24 | // override Kotlin JVM target to 23 too 25 | project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { 26 | kotlinOptions { 27 | jvmTarget = "23" 28 | } 29 | } 30 | 31 | if (project.android.namespace == null) { 32 | def manifest = new XmlSlurper().parse(file(project.android.sourceSets.main.manifest.srcFile)) 33 | def packageName = manifest.@package.text() 34 | println("Setting ${packageName} as android namespace") 35 | project.android.namespace = packageName 36 | } 37 | } 38 | } 39 | } 40 | 41 | // override the kotlin language version for each dependencies to 2.2.20 42 | configurations.all { 43 | resolutionStrategy.eachDependency { details -> 44 | if (details.requested.group == 'org.jetbrains.kotlin' && details.requested.name == 'kotlin-gradle-plugin') { 45 | details.useVersion '2.2.20' 46 | } 47 | } 48 | } 49 | 50 | subprojects { 51 | project.buildDir = "${rootProject.buildDir}/${project.name}" 52 | } 53 | subprojects { 54 | project.evaluationDependsOn(':app') 55 | } 56 | 57 | tasks.register("clean", Delete) { 58 | delete rootProject.buildDir 59 | } 60 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.useAndroidX=true 2 | android.enableJetifier=true 3 | org.gradle.jvmargs=-Xmx4096M -XX:MaxNewSize=3G 4 | org.gradle.parallel=true 5 | org.gradle.caching=true 6 | org.gradle.configureondemand=false -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https://services.gradle.org/distributions/gradle-9.1.0-bin.zip 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.13.0" apply false 22 | id "org.jetbrains.kotlin.android" version "2.2.20" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /assets/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/fonts/iconfont.ttf -------------------------------------------------------------------------------- /assets/graphics/Boreas618.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/Boreas618.jpg -------------------------------------------------------------------------------- /assets/graphics/Dest1n1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/Dest1n1.jpg -------------------------------------------------------------------------------- /assets/graphics/Frankstein73.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/Frankstein73.jpg -------------------------------------------------------------------------------- /assets/graphics/HydrogenC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/HydrogenC.jpg -------------------------------------------------------------------------------- /assets/graphics/JingYiJun.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/JingYiJun.jpg -------------------------------------------------------------------------------- /assets/graphics/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/app_icon.ico -------------------------------------------------------------------------------- /assets/graphics/fsy2001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/fsy2001.jpg -------------------------------------------------------------------------------- /assets/graphics/hasbai.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/hasbai.jpeg -------------------------------------------------------------------------------- /assets/graphics/ivanfei.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/ivanfei.jpg -------------------------------------------------------------------------------- /assets/graphics/kavinzhao.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/kavinzhao.jpeg -------------------------------------------------------------------------------- /assets/graphics/koowz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/koowz.jpg -------------------------------------------------------------------------------- /assets/graphics/kyln24.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/kyln24.jpeg -------------------------------------------------------------------------------- /assets/graphics/ot_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/ot_logo.png -------------------------------------------------------------------------------- /assets/graphics/w568w.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/assets/graphics/w568w.jpeg -------------------------------------------------------------------------------- /assets/texts/care_words.dat: -------------------------------------------------------------------------------- 1 | 想自杀 2 | 想跳楼 3 | 想割腕 4 | 会自杀 5 | 会跳楼 6 | 会割腕 7 | 要自杀 8 | 要跳楼 9 | 要割腕 10 | 打算自杀 11 | 打算跳楼 12 | 打算割腕 13 | 死法 14 | 再见世界 15 | 再见了这个世界 16 | 永别 17 | 来世再见 18 | 死亡 19 | 跳下去 20 | 不想活 21 | 抑郁 22 | 双相 23 | 绝望 24 | 结束痛苦 -------------------------------------------------------------------------------- /assets/texts/stop_words.dat: -------------------------------------------------------------------------------- 1 | 蝈蝻 2 | 郭楠 3 | 锅男 4 | 国蝻 5 | 国钕 6 | 普信男 7 | 普信女 8 | 差不多得了 9 | 傻逼 10 | 啥比 11 | 傻b 12 | 弱智 13 | 脑瘫 14 | 急了急了 15 | 有病 16 | 😅 17 | 粉蛆 18 | 小粉红 19 | 神蛆 20 | 神神 21 | 约炮 -------------------------------------------------------------------------------- /assets/texts/tips.dat: -------------------------------------------------------------------------------- 1 | 文明发言,理性讨论 2 | 请勿引战、钓鱼 3 | 政治相关讨论必须严格遵守我国法律法规和社区公约 4 | 性相关属于敏感话题,只支持学术性讨论 5 | 反馈旦挞校园助手、茶楼问题和建议请到站务分区 6 | 你有权通过电子邮件上诉管理团队的处罚决定 7 | 请在正确的分区发帖 8 | 发帖时请打好合适的 Tag 9 | 旦挞开发团队的邮箱是 dev@danta.tech 10 | 编辑器支持自动保存草稿,但退出旦挞校园助手会清空草稿 11 | 对某些帖子不感兴趣?去设置屏蔽一下吧 -------------------------------------------------------------------------------- /build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | sources: 4 | - $package$ 5 | - lib/** 6 | - pubspec.yaml 7 | builders: 8 | pubspec_generator: 9 | options: 10 | output: lib/common/pubspec.yaml.g.dart -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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/Flutter/ephemeral/flutter_lldb_helper.py: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | import lldb 6 | 7 | def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): 8 | """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" 9 | base = frame.register["x0"].GetValueAsAddress() 10 | page_len = frame.register["x1"].GetValueAsUnsigned() 11 | 12 | # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the 13 | # first page to see if handled it correctly. This makes diagnosing 14 | # misconfiguration (e.g. missing breakpoint) easier. 15 | data = bytearray(page_len) 16 | data[0:8] = b'IHELPED!' 17 | 18 | error = lldb.SBError() 19 | frame.GetThread().GetProcess().WriteMemory(base, data, error) 20 | if not error.Success(): 21 | print(f'Failed to write into {base}[+{page_len}]', error) 22 | return 23 | 24 | def __lldb_init_module(debugger: lldb.SBDebugger, _): 25 | target = debugger.GetDummyTarget() 26 | # Caveat: must use BreakpointCreateByRegEx here and not 27 | # BreakpointCreateByName. For some reasons callback function does not 28 | # get carried over from dummy target for the later. 29 | bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") 30 | bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) 31 | bp.SetAutoContinue(True) 32 | print("-- LLDB integration loaded --") 33 | -------------------------------------------------------------------------------- /ios/Flutter/ephemeral/flutter_lldbinit: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | command script import --relative-to-command-file flutter_lldb_helper.py 6 | -------------------------------------------------------------------------------- /ios/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /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/Assets.xcassets/AppIcon.appiconset/1.2.0-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-20.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-40.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-76.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by Kavin Zhao on 2021/10/15. 6 | 7 | */ 8 | 9 | CFBundleDisplayName = "DanXi"; 10 | NSLocationWhenInUseUsageDescription = "To provide location information for Safety Fudan check-in"; 11 | NSLocationAlwaysUsageDescription = "To provide location information for Safety Fudan check-in"; 12 | NSPhotoLibraryUsageDescription = "To upload images to Forum"; 13 | NSCameraUsageDescription = "To upload images to Forum"; 14 | NSCalendarsUsageDescription = "To save events to your calendar"; 15 | -------------------------------------------------------------------------------- /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 | aps-environment 6 | development 7 | com.apple.developer.associated-domains 8 | 9 | applinks:www.fduhole.com 10 | webcredentials:www.fduhole.com 11 | 12 | com.apple.security.app-sandbox 13 | 14 | com.apple.security.network.client 15 | 16 | com.apple.security.personal-information.location 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ios/Runner/TagPredictorME.mlpackage/Data/com.apple.CoreML/FeatureDescriptions.json: -------------------------------------------------------------------------------- 1 | { 2 | "Outputs" : { 3 | "label" : { 4 | "MLFeatureShortDescription" : "Text label" 5 | } 6 | }, 7 | "Inputs" : { 8 | "text" : { 9 | "MLFeatureShortDescription" : "Input text" 10 | } 11 | }, 12 | "TrainingInputs" : { 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /ios/Runner/TagPredictorME.mlpackage/Data/com.apple.CoreML/Metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "MLModelVersionStringKey" : "1.0", 3 | "MLModelDescriptionKey" : "--", 4 | "MLModelCreatorDefinedKey" : { 5 | "com.apple.createml.version" : "12.5.0", 6 | "com.apple.createml.app.tag" : "78.8", 7 | "com.apple.coreml.model.preview.type" : "textClassifier", 8 | "com.apple.createml.app.version" : "3.0" 9 | }, 10 | "MLModelAuthorKey" : "singularity-s0", 11 | "MLModelLicenseKey" : "--" 12 | } -------------------------------------------------------------------------------- /ios/Runner/TagPredictorME.mlpackage/Data/com.apple.CoreML/TagPredictor.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/TagPredictorME.mlpackage/Data/com.apple.CoreML/TagPredictor.mlmodel -------------------------------------------------------------------------------- /ios/Runner/TagPredictorME.mlpackage/Manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileFormatVersion": "1.0.0", 3 | "itemInfoEntries": { 4 | "0295E60B-8719-4E87-B0F6-2232821D0BF4": { 5 | "author": "com.apple.CoreML", 6 | "description": "External FeatureDescription Overlay", 7 | "name": "FeatureDescriptions.json", 8 | "path": "com.apple.CoreML/FeatureDescriptions.json" 9 | }, 10 | "C94E0CE1-23FC-4D51-8273-4C063F5CB80C": { 11 | "author": "com.apple.CoreML", 12 | "description": "CoreML Model Specification", 13 | "name": "TagPredictor.mlmodel", 14 | "path": "com.apple.CoreML/TagPredictor.mlmodel" 15 | }, 16 | "CC6F56C5-DB94-4B75-94B5-26912A07CE66": { 17 | "author": "com.apple.CoreML", 18 | "description": "External Metadata Overlay", 19 | "name": "Metadata.json", 20 | "path": "com.apple.CoreML/Metadata.json" 21 | } 22 | }, 23 | "rootModelIdentifier": "C94E0CE1-23FC-4D51-8273-4C063F5CB80C" 24 | } 25 | -------------------------------------------------------------------------------- /ios/Runner/TagPredictorTL.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/TagPredictorTL.mlmodel -------------------------------------------------------------------------------- /ios/Runner/TagPredictorTL.mlmodelkey: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IV 6 | 7 | jnSgqoWKsNQPlIPBbDoKqg== 8 | 9 | Key 10 | 11 | w338qWq6YEbF/DFBBPXX4Q== 12 | 13 | KeyIdentifier 14 | E3ECE827-6C1D-4A9D-AB80-399346876A92 15 | UsesCodeSigningIdentityForEncryption 16 | 17 | Version 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /ios/Runner/TagPredictorTL.mlpackage/Data/com.apple.CoreML/FeatureDescriptions.json: -------------------------------------------------------------------------------- 1 | { 2 | "Outputs" : { 3 | "label" : { 4 | "MLFeatureShortDescription" : "Text label" 5 | } 6 | }, 7 | "Inputs" : { 8 | "text" : { 9 | "MLFeatureShortDescription" : "Input text" 10 | } 11 | }, 12 | "TrainingInputs" : { 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /ios/Runner/TagPredictorTL.mlpackage/Data/com.apple.CoreML/Metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "MLModelCreatorDefinedKey" : { 3 | "com.apple.createml.version" : "12.5.0", 4 | "com.apple.createml.app.tag" : "78.8", 5 | "com.apple.createml.app.version" : "3.0", 6 | "com.apple.coreml.model.preview.type" : "textClassifier" 7 | }, 8 | "MLModelAuthorKey" : "Singularity" 9 | } -------------------------------------------------------------------------------- /ios/Runner/TagPredictorTL.mlpackage/Data/com.apple.CoreML/TagPredictorTL.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/Runner/TagPredictorTL.mlpackage/Data/com.apple.CoreML/TagPredictorTL.mlmodel -------------------------------------------------------------------------------- /ios/Runner/TagPredictorTL.mlpackage/Manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileFormatVersion": "1.0.0", 3 | "itemInfoEntries": { 4 | "1213D118-6F0C-4D70-93E7-600A41F26A04": { 5 | "author": "com.apple.CoreML", 6 | "description": "External Metadata Overlay", 7 | "name": "Metadata.json", 8 | "path": "com.apple.CoreML/Metadata.json" 9 | }, 10 | "5FE98130-57ED-445E-B78B-C6A12B8BED3D": { 11 | "author": "com.apple.CoreML", 12 | "description": "CoreML Model Specification", 13 | "name": "TagPredictorTL.mlmodel", 14 | "path": "com.apple.CoreML/TagPredictorTL.mlmodel" 15 | }, 16 | "E138152D-F9CA-4E3E-BA41-4612EDA489B9": { 17 | "author": "com.apple.CoreML", 18 | "description": "External FeatureDescription Overlay", 19 | "name": "FeatureDescriptions.json", 20 | "path": "com.apple.CoreML/FeatureDescriptions.json" 21 | } 22 | }, 23 | "rootModelIdentifier": "5FE98130-57ED-445E-B78B-C6A12B8BED3D" 24 | } 25 | -------------------------------------------------------------------------------- /ios/Runner/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by Kavin Zhao on 2021/10/15. 6 | 7 | */ 8 | 9 | CFBundleDisplayName = "DanXi"; 10 | NSLocationWhenInUseUsageDescription = "To provide location information for Safety Fudan check-in"; 11 | NSLocationAlwaysUsageDescription = "To provide location information for Safety Fudan check-in"; 12 | NSPhotoLibraryUsageDescription = "To upload images to Forum"; 13 | NSCameraUsageDescription = "To upload images to Forum"; 14 | NSCalendarsUsageDescription = "To save events to your calendar"; 15 | -------------------------------------------------------------------------------- /ios/Runner/ja.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by Kavin Zhao on 2021/10/15. 6 | 7 | */ 8 | 9 | CFBundleDisplayName = "DanXi"; 10 | NSLocationWhenInUseUsageDescription = "To provide location information for Safety Fudan check-in"; 11 | NSLocationAlwaysUsageDescription = "To provide location information for Safety Fudan check-in"; 12 | NSPhotoLibraryUsageDescription = "To upload images to Forum"; 13 | NSCameraUsageDescription = "To upload images to Forum"; 14 | NSCalendarsUsageDescription = "To save events to your calendar"; 15 | -------------------------------------------------------------------------------- /ios/Runner/ja.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/ja.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | Runner 4 | 5 | Created by Kavin Zhao on 2021/10/15. 6 | 7 | */ 8 | 9 | CFBundleDisplayName = "旦夕"; 10 | NSLocationWhenInUseUsageDescription = "为平安复旦打卡提供位置信息"; 11 | NSLocationAlwaysUsageDescription = "为平安复旦打卡提供位置信息"; 12 | NSPhotoLibraryUsageDescription = "为上传图片至Forum"; 13 | NSCameraUsageDescription = "为上传图片至Forum"; 14 | NSCalendarsUsageDescription = "为向系统日历中添加课程表和考试日程"; 15 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hans.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Runner/zh-Hans.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier("io.github.danxi-dev.dan-xi") # The bundle identifier of your app 2 | apple_id("xingjian_zhao@hotmail.com") # Your Apple email address 3 | 4 | itc_team_id("123065304") # App Store Connect Team ID 5 | team_id("QZ9KCS2T78") # Developer Portal Team ID 6 | 7 | # For more information about the Appfile, see: 8 | # https://docs.fastlane.tools/advanced/#appfile 9 | -------------------------------------------------------------------------------- /ios/fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | # This file contains the fastlane.tools configuration 2 | # You can find the documentation at https://docs.fastlane.tools 3 | # 4 | # For a list of all available actions, check out 5 | # 6 | # https://docs.fastlane.tools/actions 7 | # 8 | # For a list of all available plugins, check out 9 | # 10 | # https://docs.fastlane.tools/plugins/available-plugins 11 | # 12 | 13 | # Uncomment the line if you want fastlane to automatically update itself 14 | # update_fastlane 15 | 16 | default_platform(:ios) 17 | 18 | platform :ios do 19 | desc "Push a new beta build to TestFlight" 20 | lane :beta do 21 | setup_ci if ENV['CI'] 22 | app_store_connect_api_key() if ENV['CI'] 23 | match(type: 'appstore') 24 | build_app(workspace: "Runner.xcworkspace", scheme: "Runner") 25 | upload_to_testflight(skip_waiting_for_build_processing: true) 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">161" 12 | }, 13 | { 14 | "idiom" : "watch", 15 | "scale" : "2x", 16 | "screen-width" : ">145" 17 | }, 18 | { 19 | "idiom" : "watch", 20 | "scale" : "2x", 21 | "screen-width" : ">183" 22 | } 23 | ], 24 | "info" : { 25 | "author" : "xcode", 26 | "version" : 1 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "filename" : "Circular.imageset", 5 | "idiom" : "watch", 6 | "role" : "circular" 7 | }, 8 | { 9 | "filename" : "Extra Large.imageset", 10 | "idiom" : "watch", 11 | "role" : "extra-large" 12 | }, 13 | { 14 | "filename" : "Graphic Bezel.imageset", 15 | "idiom" : "watch", 16 | "role" : "graphic-bezel" 17 | }, 18 | { 19 | "filename" : "Graphic Circular.imageset", 20 | "idiom" : "watch", 21 | "role" : "graphic-circular" 22 | }, 23 | { 24 | "filename" : "Graphic Corner.imageset", 25 | "idiom" : "watch", 26 | "role" : "graphic-corner" 27 | }, 28 | { 29 | "filename" : "Graphic Extra Large.imageset", 30 | "idiom" : "watch", 31 | "role" : "graphic-extra-large" 32 | }, 33 | { 34 | "filename" : "Graphic Large Rectangular.imageset", 35 | "idiom" : "watch", 36 | "role" : "graphic-large-rectangular" 37 | }, 38 | { 39 | "filename" : "Modular.imageset", 40 | "idiom" : "watch", 41 | "role" : "modular" 42 | }, 43 | { 44 | "filename" : "Utilitarian.imageset", 45 | "idiom" : "watch", 46 | "role" : "utilitarian" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">161" 12 | }, 13 | { 14 | "idiom" : "watch", 15 | "scale" : "2x", 16 | "screen-width" : ">145" 17 | }, 18 | { 19 | "idiom" : "watch", 20 | "scale" : "2x", 21 | "screen-width" : ">183" 22 | } 23 | ], 24 | "info" : { 25 | "author" : "xcode", 26 | "version" : 1 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : ">161" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">183" 12 | } 13 | ], 14 | "info" : { 15 | "author" : "xcode", 16 | "version" : 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : ">161" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">183" 12 | } 13 | ], 14 | "info" : { 15 | "author" : "xcode", 16 | "version" : 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : ">161" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">183" 12 | } 13 | ], 14 | "info" : { 15 | "author" : "xcode", 16 | "version" : 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">161" 12 | }, 13 | { 14 | "idiom" : "watch", 15 | "scale" : "2x", 16 | "screen-width" : ">145" 17 | }, 18 | { 19 | "idiom" : "watch", 20 | "scale" : "2x", 21 | "screen-width" : ">183" 22 | } 23 | ], 24 | "info" : { 25 | "author" : "xcode", 26 | "version" : 1 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : ">161" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">183" 12 | } 13 | ], 14 | "info" : { 15 | "author" : "xcode", 16 | "version" : 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">161" 12 | }, 13 | { 14 | "idiom" : "watch", 15 | "scale" : "2x", 16 | "screen-width" : ">145" 17 | }, 18 | { 19 | "idiom" : "watch", 20 | "scale" : "2x", 21 | "screen-width" : ">183" 22 | } 23 | ], 24 | "info" : { 25 | "author" : "xcode", 26 | "version" : 1 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">161" 12 | }, 13 | { 14 | "idiom" : "watch", 15 | "scale" : "2x", 16 | "screen-width" : ">145" 17 | }, 18 | { 19 | "idiom" : "watch", 20 | "scale" : "2x", 21 | "screen-width" : ">183" 22 | } 23 | ], 24 | "info" : { 25 | "author" : "xcode", 26 | "version" : 1 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ios/nano Extension/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/nano Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | 旦夕 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.3.11 21 | CFBundleVersion 22 | 185 23 | CLKComplicationPrincipalClass 24 | $(PRODUCT_MODULE_NAME).ComplicationController 25 | NSExtension 26 | 27 | NSExtensionAttributes 28 | 29 | WKAppBundleIdentifier 30 | io.github.danxi-dev.dan-xi.watchapp 31 | 32 | NSExtensionPointIdentifier 33 | com.apple.watchkit 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ios/nano Extension/Models/TreeHoleModels.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Discussion.swift 3 | // DanXi-native 4 | // 5 | // Created by Kavin Zhao on 2021/6/26. 6 | // 7 | 8 | import Foundation 9 | 10 | class FduholeLoginInfo: ObservableObject { 11 | @Published var token: String = "" 12 | } 13 | 14 | struct OTHole: Hashable, Codable, Identifiable { 15 | var id: Int { 16 | get { 17 | return self.hole_id 18 | } 19 | } 20 | 21 | let hole_id, division_id: Int 22 | let view, reply: Int? 23 | let floors: _OTFloors 24 | let time_created, time_updated: String 25 | let tags: [OTTag]? 26 | } 27 | 28 | struct _OTFloors: Hashable, Codable { 29 | let last_floor: OTFloor 30 | let prefetch: [OTFloor] 31 | } 32 | 33 | struct OTFloor: Hashable, Codable, Identifiable { 34 | var id: Int { 35 | get { 36 | return self.floor_id 37 | } 38 | } 39 | 40 | let floor_id, hole_id, like: Int 41 | let content, anonyname, time_updated, time_created: String 42 | let deleted, is_me, liked: Bool? 43 | let fold: [String]? 44 | } 45 | 46 | struct OTDivision: Hashable, Codable, Identifiable { 47 | var id: Int { 48 | get { 49 | return self.division_id 50 | } 51 | } 52 | 53 | let division_id: Int 54 | let name, description: String 55 | let pinned: [OTHole]? 56 | } 57 | 58 | struct OTTag: Hashable, Codable { 59 | let name: String 60 | let tag_id, temperature: Int 61 | } 62 | -------------------------------------------------------------------------------- /ios/nano Extension/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/nano Extension/Views/THPostDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // THPostDetailView.swift 3 | // DanXi-native 4 | // 5 | // Created by Kavin Zhao on 2021/7/1. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct THPostDetailView: View { 11 | var reply: OTFloor 12 | 13 | var body: some View { 14 | VStack(alignment: .leading) { 15 | Text("\(reply.anonyname)") 16 | Text(preprocessTextForHtmlAndImage(text:reply.content)) 17 | } 18 | .padding() 19 | } 20 | } 21 | 22 | struct THPostDetailView_Previews: PreviewProvider { 23 | static var previews: some View { 24 | THPostDetailView(reply: OTFloor(floor_id: 1, hole_id: 2, like: 3, content: "he", anonyname: "MMM", time_updated: "", time_created: "", deleted: false, is_me: false, liked: false, fold: [])) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ios/nano Extension/WatchConnectivity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WatchConnectivity.swift 3 | // nano Extension 4 | // 5 | // Created by Kavin Zhao on 2021/7/3. 6 | // 7 | 8 | import Foundation 9 | import WatchConnectivity 10 | import SwiftUI 11 | 12 | let KEY_FDUHOLE_TOKEN = "fduhole_token_v2" 13 | 14 | class WatchSessionDelegate: NSObject, WCSessionDelegate, ObservableObject { 15 | let session = WCSession.default; 16 | static var shared = WatchSessionDelegate() 17 | 18 | @Published var token = "" 19 | 20 | func activate() { 21 | session.delegate = self 22 | session.activate() 23 | } 24 | 25 | func initialize() { 26 | token = getFduholeToken() 27 | } 28 | 29 | func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { 30 | } 31 | 32 | func requestToken() -> Bool { 33 | if(!session.isReachable) { 34 | return false 35 | } 36 | DispatchQueue.main.async { 37 | self.session.sendMessage(["requestToken": true], replyHandler: nil) 38 | } 39 | return true 40 | } 41 | 42 | func session(_ session: WCSession, didReceiveMessage message: [String : Any]) { 43 | DispatchQueue.main.async { 44 | self.token = message["token"] as! String 45 | } 46 | setFduholeToken(token: message["token"] as! String) 47 | } 48 | 49 | func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) { 50 | DispatchQueue.main.async { 51 | self.token = userInfo["token"] as! String 52 | } 53 | self.setFduholeToken(token: userInfo["token"] as! String) 54 | session.transferUserInfo(["token_set": true]) 55 | } 56 | 57 | let defaults = UserDefaults.standard 58 | func setFduholeToken(token: String) -> Void { 59 | defaults.set(token, forKey: KEY_FDUHOLE_TOKEN) 60 | } 61 | 62 | func getFduholeToken() -> String { 63 | return defaults.string(forKey: KEY_FDUHOLE_TOKEN) ?? "" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ios/nano Extension/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | DanXi-native 4 | 5 | Created by Kavin Zhao on 2021/6/29. 6 | 7 | */ 8 | 9 | // Content View 10 | "dashboard" = "Dashboard"; 11 | "treehole" = "Tree Hole"; 12 | 13 | // Login Page 14 | "login" = "Login"; 15 | "uisLogin" = "UIS Login"; 16 | "studentId" = "Student ID"; 17 | "pwd" = "Password"; 18 | "fduholeLogin" = "FDUHOLE Login"; 19 | "loginWithFduhole" = "Login with FDUHOLE"; 20 | "fduholeLogin_footer" = "You will be able to use only FDUHOLE features if you login with this option."; 21 | 22 | // Tree Hole 23 | "selectAPost" = "Select a post to view"; 24 | "report" = "Report"; 25 | "gettingtoken" = "Waiting for account information from iPhone..."; 26 | "image_tag" = " [Image] "; 27 | "iphoneunreachable" = "iPhone Unreachable. Tap to retry"; 28 | "manualInputToken" = "Manually import Token"; 29 | "error" = "Error"; 30 | "discussionFolded" = "Content hidden. Tap to view"; 31 | "end_reached" = "You have reached the end"; 32 | "refresh" = "Refresh"; 33 | "retry_login" = "Retry Login"; 34 | "division" = "Topic"; 35 | -------------------------------------------------------------------------------- /ios/nano Extension/ja.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | DanXi-native 4 | 5 | Created by Kavin Zhao on 2021/6/29. 6 | 7 | */ 8 | 9 | // Content View 10 | "dashboard" = "Dashboard"; 11 | "treehole" = "Tree Hole"; 12 | 13 | // Login Page 14 | "login" = "Login"; 15 | "uisLogin" = "UIS Login"; 16 | "studentId" = "Student ID"; 17 | "pwd" = "Password"; 18 | "fduholeLogin" = "FDUHOLE Login"; 19 | "loginWithFduhole" = "Login with FDUHOLE"; 20 | "fduholeLogin_footer" = "You will be able to use only FDUHOLE features if you login with this option."; 21 | 22 | // Tree Hole 23 | "selectAPost" = "Select a post to view"; 24 | "report" = "Report"; 25 | "gettingtoken" = "Waiting for account information from iPhone..."; 26 | "image_tag" = " [Image] "; 27 | "iphoneunreachable" = "iPhone Unreachable. Tap to retry"; 28 | "manualInputToken" = "Manually import Token"; 29 | "error" = "Error"; 30 | "discussionFolded" = "Content hidden. Tap to view"; 31 | "end_reached" = "You have reached the end"; 32 | "refresh" = "Refresh"; 33 | "retry_login" = "Retry Login"; 34 | "division" = "Topic"; 35 | -------------------------------------------------------------------------------- /ios/nano Extension/nano Extension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.associated-domains 6 | 7 | webcredentials:www.fduhole.com 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/nano Extension/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | DanXi-native 4 | 5 | Created by Kavin Zhao on 2021/6/29. 6 | 7 | */ 8 | 9 | // Content View 10 | "dashboard" = "Dashboard"; 11 | "treehole" = "茶楼"; 12 | 13 | // Login Page 14 | "login" = "Login"; 15 | "uisLogin" = "UIS Login"; 16 | "studentId" = "Student ID"; 17 | "pwd" = "Password"; 18 | "fduholeLogin" = "FDUHOLE Login"; 19 | "loginWithFduhole" = "Login with FDUHOLE"; 20 | "fduholeLogin_footer" = "You will be able to use only FDUHOLE features if you login with this option."; 21 | 22 | // Tree Hole 23 | "selectAPost" = "Select a post to view"; 24 | "report" = "Report"; 25 | "gettingtoken" = "正在从iPhone获取账户信息..."; 26 | "image_tag" = " [图片] "; 27 | "iphoneunreachable" = "无法连接到iPhone,点击重试"; 28 | "manualInputToken" = "手动导入Token"; 29 | "error" = "错误"; 30 | "discussionFolded" = "该内容已折叠,点击查看"; 31 | "end_reached" = "已经到底了"; 32 | "refresh" = "刷新"; 33 | "retry_login" = "重新登录"; 34 | "division" = "分区"; 35 | -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "platform" : "ios", 6 | "reference" : "systemBlueColor" 7 | }, 8 | "idiom" : "universal" 9 | } 10 | ], 11 | "info" : { 12 | "author" : "xcode", 13 | "version" : 1 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-1024@1x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-108@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-108@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-24@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-24@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-24@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-24@3x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-27-5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-27-5@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-29@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-40@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-44@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-44@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-50@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-86@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-86@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-98@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/ios/nano/Assets.xcassets/AppIcon.appiconset/1.2.0-98@2x.png -------------------------------------------------------------------------------- /ios/nano/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/nano/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | 旦夕 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.3.11 21 | CFBundleVersion 22 | 185 23 | UISupportedInterfaceOrientations 24 | 25 | UIInterfaceOrientationPortrait 26 | UIInterfaceOrientationPortraitUpsideDown 27 | 28 | WKCompanionAppBundleIdentifier 29 | io.github.danxi-dev.dan-xi 30 | WKWatchKitApp 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ios/nanoDanxi WatchKit Extension/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // nanoDanxi WatchKit Extension 4 | // 5 | // Created by Kavin Zhao on 2021/7/3. 6 | // 7 | 8 | import SwiftUI 9 | import WatchKit 10 | 11 | struct ContentView: View { 12 | @EnvironmentObject var fduholeLoginInfo: WatchSessionDelegate 13 | @State private var connectionReachable = true; 14 | 15 | 16 | var body: some View { 17 | if (fduholeLoginInfo.token == "") { 18 | VStack { 19 | if (connectionReachable) { 20 | ProgressView() 21 | Text("gettingtoken") 22 | } 23 | else { 24 | Text("iphoneunreachable") 25 | } 26 | /*TextField("test", text: $capturedText) 27 | { isEditing in 28 | 29 | } onCommit: { 30 | UserDefaults.standard.set(capturedText, forKey: "fduhole_token") 31 | fduholeLoginInfo.token = capturedText 32 | } 33 | .textContentType(.oneTimeCode)*/ 34 | } 35 | .onAppear() { 36 | WatchSessionDelegate.shared.activate() 37 | connectionReachable = WatchSessionDelegate.shared.requestToken() 38 | } 39 | .onTapGesture() { 40 | connectionReachable = WatchSessionDelegate.shared.requestToken() 41 | } 42 | } 43 | else { 44 | TreeHolePage() 45 | } 46 | } 47 | } 48 | 49 | struct ContentView_Previews: PreviewProvider { 50 | static var previews: some View { 51 | ContentView() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ios/nanoDanxi WatchKit Extension/RunnerApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RunnerApp.swift 3 | // nanoDanxi WatchKit Extension 4 | // 5 | // Created by Kavin Zhao on 2021/7/3. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct RunnerApp: App { 12 | @StateObject var fduholeLoginInfo = WatchSessionDelegate.shared 13 | 14 | init() { 15 | // Read FDUHOLE Token 16 | WatchSessionDelegate.shared.initialize() 17 | } 18 | 19 | var body: some Scene { 20 | WindowGroup { 21 | NavigationView { 22 | ContentView() 23 | } 24 | .environmentObject(fduholeLoginInfo) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/common/icon_fonts.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:flutter/widgets.dart'; 19 | 20 | /// Some icons from third-part. 21 | class IconFont { 22 | static const IconData markdown = 23 | IconData(0xe673, fontFamily: "iconfont", matchTextDirection: true); 24 | static const IconData tex = 25 | IconData(0xe6a9, fontFamily: "iconfont", matchTextDirection: true); 26 | } 27 | -------------------------------------------------------------------------------- /lib/feature/custom_shortcut.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 kavinzhao 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/feature/base_feature.dart'; 19 | import 'package:dan_xi/generated/l10n.dart'; 20 | import 'package:dan_xi/util/browser_util.dart'; 21 | import 'package:dan_xi/util/noticing.dart'; 22 | import 'package:flutter/cupertino.dart'; 23 | 24 | /// A feature providing a shortcut a custom link. 25 | class CustomShortcutFeature extends Feature { 26 | final String? title; 27 | final String? link; 28 | 29 | CustomShortcutFeature({this.title, this.link}); 30 | 31 | @override 32 | String? get mainTitle => title; 33 | 34 | @override 35 | bool get loadOnTap => false; 36 | 37 | @override 38 | String? get subTitle => link; 39 | 40 | @override 41 | Widget get icon => const Icon(CupertinoIcons.bookmark); 42 | 43 | @override 44 | void onTap() async { 45 | try { 46 | await BrowserUtil.openUrl(link!, context); 47 | } catch (_) { 48 | if (context != null && context!.mounted) { 49 | Noticing.showNotice(context!, S.of(context!).cannot_launch_url); 50 | } 51 | } 52 | } 53 | 54 | @override 55 | bool get clickable => true; 56 | } 57 | -------------------------------------------------------------------------------- /lib/feature/empty_classroom_feature.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 kavinzhao 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/feature/base_feature.dart'; 19 | import 'package:dan_xi/generated/l10n.dart'; 20 | import 'package:dan_xi/util/master_detail_view.dart'; 21 | import 'package:dan_xi/util/platform_universal.dart'; 22 | import 'package:flutter/cupertino.dart'; 23 | import 'package:flutter/material.dart'; 24 | 25 | class EmptyClassroomFeature extends Feature { 26 | @override 27 | String get mainTitle => S.of(context!).empty_classrooms; 28 | 29 | @override 30 | String get subTitle => S.of(context!).tap_to_view; 31 | 32 | @override 33 | Widget get icon => PlatformX.isMaterial(context!) 34 | ? const Icon(Icons.room) 35 | : const Icon(CupertinoIcons.building_2_fill); 36 | 37 | @override 38 | void onTap() async => smartNavigatorPush(context!, '/room/detail'); 39 | 40 | @override 41 | bool get clickable => true; 42 | 43 | @override 44 | bool get loadOnTap => false; 45 | } 46 | -------------------------------------------------------------------------------- /lib/feature/qr_feature.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 kavinzhao 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/feature/base_feature.dart'; 19 | import 'package:dan_xi/generated/l10n.dart'; 20 | import 'package:dan_xi/util/platform_universal.dart'; 21 | import 'package:dan_xi/widget/dialogs/qr_code_dialog.dart'; 22 | import 'package:flutter/cupertino.dart'; 23 | import 'package:flutter/material.dart'; 24 | 25 | class QRFeature extends Feature { 26 | @override 27 | String get mainTitle => S.of(context!).fudan_qr_code; 28 | 29 | @override 30 | String get subTitle => S.of(context!).tap_to_view; 31 | 32 | @override 33 | Widget get icon => PlatformX.isMaterial(context!) 34 | ? const Icon(Icons.qr_code) 35 | : const Icon(CupertinoIcons.qrcode); 36 | 37 | @override 38 | void onTap() { 39 | QRHelper.showQRCode(context!); 40 | } 41 | 42 | @override 43 | bool get clickable => true; 44 | 45 | @override 46 | bool get loadOnTap => false; 47 | } 48 | -------------------------------------------------------------------------------- /lib/model/announcement.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:json_annotation/json_annotation.dart'; 19 | 20 | part 'announcement.g.dart'; 21 | 22 | @JsonSerializable() 23 | class Announcement { 24 | String? createdAt; 25 | String? updatedAt; 26 | String? objectId; 27 | 28 | String? content; 29 | int? maxVersion; 30 | 31 | factory Announcement.fromJson(Map json) => 32 | _$AnnouncementFromJson(json); 33 | 34 | @override 35 | String toString() { 36 | return 'Announcement{content: $content, maxVersion: $maxVersion}'; 37 | } 38 | 39 | Map toJson() => _$AnnouncementToJson(this); 40 | 41 | Announcement(this.content); 42 | 43 | // FIXME: Use updatedAt as objectId requires updatedAt to be unique 44 | Announcement.fromToml(Map notice) { 45 | updatedAt = notice['updated_at']; 46 | content = notice['content']; 47 | maxVersion = notice['build']; 48 | createdAt = updatedAt; 49 | objectId = updatedAt; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/model/celebration.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/util/vague_time.dart'; 19 | import 'package:json_annotation/json_annotation.dart'; 20 | import 'package:lunar/calendar/Lunar.dart'; 21 | 22 | part 'celebration.g.dart'; 23 | 24 | @JsonSerializable() 25 | class Celebration { 26 | /// Type of celebration [date]. 27 | /// 28 | /// 1: Chinese lunar festival(e.g. date = 春节) 29 | /// 2: Chinese lunar date(e.g. date = 01-01) 30 | /// 3: Standard date(e.g. date = 01-01) 31 | final int type; 32 | 33 | final String date; 34 | 35 | final List celebrationWords; 36 | 37 | /// Return whether the [date] corresponds with [dateTime]. 38 | bool match(DateTime dateTime) { 39 | switch (type) { 40 | case 1: 41 | return Lunar.fromDate(dateTime).getFestivals().contains(date); 42 | case 2: 43 | var lunarDate = Lunar.fromDate(dateTime); 44 | var splitTime = date.split("-"); 45 | return lunarDate.getMonth() == int.parse(splitTime[0]) && 46 | lunarDate.getDay() == int.parse(splitTime[1]); 47 | case 3: 48 | return VagueTime.onlyMMdd(date).match(dateTime); 49 | } 50 | return false; 51 | } 52 | 53 | const Celebration(this.type, this.date, this.celebrationWords); 54 | 55 | Map toJson() => _$CelebrationToJson(this); 56 | 57 | factory Celebration.fromJson(Map json) => 58 | _$CelebrationFromJson(json); 59 | } 60 | -------------------------------------------------------------------------------- /lib/model/danke/review_extra.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import 'dart:core'; 18 | 19 | import 'package:dan_xi/model/danke/reviewer_achievements.dart'; 20 | import 'package:json_annotation/json_annotation.dart'; 21 | 22 | part 'review_extra.g.dart'; 23 | 24 | @JsonSerializable() 25 | class ReviewExtra { 26 | List? achievements; 27 | 28 | ReviewExtra(this.achievements); 29 | 30 | factory ReviewExtra.fromJson(Map json) => 31 | _$ReviewExtraFromJson(json); 32 | 33 | Map toJson() => _$ReviewExtraToJson(this); 34 | 35 | factory ReviewExtra.dummy() => ReviewExtra([ReviewerAchievement.dummy()]); 36 | } 37 | -------------------------------------------------------------------------------- /lib/model/danke/reviewer_achievements.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import 'dart:core'; 18 | 19 | import 'package:json_annotation/json_annotation.dart'; 20 | 21 | part 'reviewer_achievements.g.dart'; 22 | 23 | @JsonSerializable() 24 | class ReviewerAchievement { 25 | String? name; 26 | 27 | ReviewerAchievement(this.name); 28 | 29 | factory ReviewerAchievement.fromJson(Map json) => 30 | _$ReviewerAchievementFromJson(json); 31 | 32 | Map toJson() => _$ReviewerAchievementToJson(this); 33 | 34 | factory ReviewerAchievement.dummy() => ReviewerAchievement("狗勋章"); 35 | } 36 | -------------------------------------------------------------------------------- /lib/model/danke/search_results.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/model/danke/course_group.dart'; 19 | import 'package:json_annotation/json_annotation.dart'; 20 | 21 | part 'search_results.g.dart'; 22 | 23 | @JsonSerializable() 24 | class CourseSearchResults { 25 | int? page; 26 | @JsonKey(name: 'page_size') 27 | int? pageSize; 28 | String? extra; 29 | List? items; 30 | 31 | CourseSearchResults(this.page, this.pageSize, this.extra, this.items); 32 | 33 | factory CourseSearchResults.fromJson(Map json) => 34 | _$CourseSearchResultsFromJson(json); 35 | 36 | Map toJson() => _$CourseSearchResultsToJson(this); 37 | } 38 | -------------------------------------------------------------------------------- /lib/model/dashboard_card.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/common/constant.dart'; 19 | import 'package:json_annotation/json_annotation.dart'; 20 | 21 | part 'dashboard_card.g.dart'; 22 | 23 | @JsonSerializable() 24 | class DashboardCard { 25 | final String? internalString; 26 | final String? title; 27 | final String? link; 28 | bool? enabled; 29 | 30 | DashboardCard(this.internalString, this.title, this.link, this.enabled); 31 | 32 | factory DashboardCard.fromJson(Map json) => 33 | _$DashboardCardFromJson(json); 34 | 35 | Map toJson() => _$DashboardCardToJson(this); 36 | 37 | bool get isSpecialCard => 38 | internalString == Constant.FEATURE_NEW_CARD || 39 | internalString == Constant.FEATURE_CUSTOM_CARD || 40 | internalString == Constant.FEATURE_DIVIDER; 41 | } 42 | -------------------------------------------------------------------------------- /lib/model/forum/audit.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | // ignore_for_file: non_constant_identifier_names 18 | 19 | import 'package:json_annotation/json_annotation.dart'; 20 | 21 | part 'audit.g.dart'; 22 | 23 | @JsonSerializable() 24 | class OTAudit { 25 | final String content; 26 | final int hole_id; 27 | final int id; 28 | final bool? is_actual_sensitive; 29 | final int modified; 30 | final String? time_created; 31 | final String? time_updated; 32 | final String? sensitive_detail; 33 | 34 | OTAudit( 35 | this.content, 36 | this.hole_id, 37 | this.id, 38 | this.is_actual_sensitive, 39 | this.modified, 40 | this.time_created, 41 | this.time_updated, 42 | this.sensitive_detail); 43 | 44 | factory OTAudit.fromJson(Map json) => 45 | _$OTAuditFromJson(json); 46 | 47 | OTAudit processed() => OTAudit("已处理", hole_id, id, is_actual_sensitive, 48 | modified, time_created, time_updated, sensitive_detail); 49 | 50 | Map toJson() => _$OTAuditToJson(this); 51 | 52 | @override 53 | String toString() { 54 | return 'OTAudit{content: $content, hole_id: $hole_id, id: $id, is_actual_sensitive: $is_actual_sensitive, modified: $modified, time_created: $time_created, time_updated: $time_updated, sensitive_detail: $sensitive_detail}'; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/model/forum/division.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | // ignore_for_file: non_constant_identifier_names 19 | 20 | import 'package:dan_xi/model/forum/hole.dart'; 21 | import 'package:json_annotation/json_annotation.dart'; 22 | 23 | part 'division.g.dart'; 24 | 25 | @JsonSerializable() 26 | class OTDivision { 27 | int? division_id; 28 | String? name; 29 | String? description; 30 | List? pinned; 31 | 32 | factory OTDivision.fromJson(Map json) => 33 | _$OTDivisionFromJson(json); 34 | 35 | Map toJson() => _$OTDivisionToJson(this); 36 | 37 | @override 38 | bool operator ==(Object other) => 39 | (other is OTDivision) && division_id == other.division_id; 40 | 41 | OTDivision(this.division_id, this.name, this.description, this.pinned); 42 | 43 | @override 44 | String toString() => name ?? "null"; 45 | 46 | @override 47 | int get hashCode => division_id!; 48 | } 49 | -------------------------------------------------------------------------------- /lib/model/forum/floors.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | // ignore_for_file: non_constant_identifier_names 19 | 20 | import 'package:dan_xi/model/forum/floor.dart'; 21 | import 'package:json_annotation/json_annotation.dart'; 22 | 23 | part 'floors.g.dart'; 24 | 25 | @JsonSerializable() 26 | class OTFloors { 27 | OTFloor? first_floor; 28 | OTFloor? last_floor; 29 | 30 | factory OTFloors.fromJson(Map json) => 31 | _$OTFloorsFromJson(json); 32 | 33 | Map toJson() => _$OTFloorsToJson(this); 34 | 35 | OTFloors(this.first_floor, this.last_floor); 36 | } 37 | -------------------------------------------------------------------------------- /lib/model/forum/history.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import 'package:json_annotation/json_annotation.dart'; 18 | 19 | part 'history.g.dart'; 20 | 21 | @JsonSerializable() 22 | class OTHistory { 23 | String? content; 24 | int? user_id; 25 | String? time_updated; 26 | 27 | factory OTHistory.fromJson(Map json) => 28 | _$OTHistoryFromJson(json); 29 | 30 | Map toJson() => _$OTHistoryToJson(this); 31 | 32 | OTHistory(this.content, this.user_id, this.time_updated); 33 | } 34 | -------------------------------------------------------------------------------- /lib/model/forum/jwt.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import 'package:json_annotation/json_annotation.dart'; 18 | 19 | part 'jwt.g.dart'; 20 | 21 | @JsonSerializable() 22 | class JWToken { 23 | String? access; 24 | String? refresh; 25 | 26 | factory JWToken.fromJson(Map json) => 27 | _$JWTokenFromJson(json); 28 | 29 | bool get isValid => access != null && refresh != null; 30 | 31 | factory JWToken.fromJsonWithVerification(Map json) { 32 | JWToken token = JWToken.fromJson(json); 33 | if (!token.isValid) { 34 | throw BadTokenException(); 35 | } 36 | return token; 37 | } 38 | 39 | Map toJson() => _$JWTokenToJson(this); 40 | 41 | @override 42 | bool operator ==(Object other) => 43 | identical(this, other) || 44 | other is JWToken && 45 | runtimeType == other.runtimeType && 46 | access == other.access && 47 | refresh == other.refresh; 48 | 49 | @override 50 | int get hashCode => access.hashCode ^ refresh.hashCode; 51 | 52 | JWToken(this.access, this.refresh); 53 | } 54 | 55 | class BadTokenException implements Exception {} 56 | -------------------------------------------------------------------------------- /lib/model/forum/message.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | // ignore_for_file: non_constant_identifier_names 19 | 20 | import 'package:json_annotation/json_annotation.dart'; 21 | 22 | part 'message.g.dart'; 23 | 24 | @JsonSerializable() 25 | class OTMessage { 26 | int? message_id; 27 | String? message; 28 | String? description; 29 | String? code; 30 | String? time_created; 31 | bool? has_read; 32 | 33 | /// This can be anything, in json format 34 | Map? data; 35 | 36 | factory OTMessage.fromJson(Map json) => 37 | _$OTMessageFromJson(json); 38 | 39 | Map toJson() => _$OTMessageToJson(this); 40 | 41 | @override 42 | bool operator ==(Object other) => 43 | (other is OTMessage) && message_id == other.message_id; 44 | 45 | OTMessage(this.message_id, this.message, this.code, this.time_created, 46 | this.has_read, this.data); 47 | 48 | @override 49 | int get hashCode => message_id!; 50 | } 51 | -------------------------------------------------------------------------------- /lib/model/forum/punishment.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/model/forum/floor.dart'; 19 | import 'package:json_annotation/json_annotation.dart'; 20 | 21 | part 'punishment.g.dart'; 22 | 23 | @JsonSerializable() 24 | class OTPunishment { 25 | String? created_at; 26 | String? deleted_at; 27 | int? division_id; 28 | int? duration; 29 | String? end_time; 30 | OTFloor? floor; 31 | int? floor_id; 32 | int? id; 33 | int? made_by; 34 | String? reason; 35 | String? start_time; 36 | int? user_id; 37 | 38 | factory OTPunishment.fromJson(Map json) => 39 | _$OTPunishmentFromJson(json); 40 | 41 | Map toJson() => _$OTPunishmentToJson(this); 42 | 43 | OTPunishment( 44 | this.created_at, 45 | this.deleted_at, 46 | this.division_id, 47 | this.duration, 48 | this.end_time, 49 | this.floor, 50 | this.floor_id, 51 | this.id, 52 | this.made_by, 53 | this.reason, 54 | this.start_time, 55 | this.user_id); 56 | } 57 | -------------------------------------------------------------------------------- /lib/model/forum/quiz_answer.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'quiz_answer.g.dart'; 4 | 5 | // Represents a question in the quiz popped out after register 6 | @JsonSerializable() 7 | class QuizAnswer { 8 | List? answer; 9 | int? id; 10 | 11 | factory QuizAnswer.fromJson(Map json) => 12 | _$QuizAnswerFromJson(json); 13 | 14 | Map toJson() => _$QuizAnswerToJson(this); 15 | 16 | QuizAnswer(this.answer, this.id); 17 | } 18 | -------------------------------------------------------------------------------- /lib/model/forum/quiz_question.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'quiz_question.g.dart'; 4 | 5 | // Represents a question in the quiz popped out after register 6 | @JsonSerializable() 7 | class QuizQuestion { 8 | String? analysis; 9 | List? answer; 10 | String? group; 11 | int? id; 12 | List? options; 13 | String? question; 14 | String? type; 15 | 16 | // Client-side info, disable serialization 17 | @JsonKey(includeFromJson: false, includeToJson: false) 18 | bool correct = false; 19 | 20 | factory QuizQuestion.fromJson(Map json) => 21 | _$QuizQuestionFromJson(json); 22 | 23 | Map toJson() => _$QuizQuestionToJson(this); 24 | 25 | QuizQuestion(this.analysis, this.answer, this.group, this.id, this.options, 26 | this.question, this.type); 27 | } 28 | -------------------------------------------------------------------------------- /lib/model/forum/tag.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | // ignore_for_file: non_constant_identifier_names 19 | 20 | import 'package:dan_xi/util/public_extension_methods.dart'; 21 | import 'package:dan_xi/widget/forum/tag_selector/flutter_tagging/taggable.dart'; 22 | import 'package:flutter/material.dart'; 23 | import 'package:json_annotation/json_annotation.dart'; 24 | 25 | part 'tag.g.dart'; 26 | 27 | @JsonSerializable() 28 | class OTTag extends Taggable { 29 | final int? tag_id; 30 | final int? temperature; 31 | final String? name; 32 | 33 | factory OTTag.fromJson(Map json) => _$OTTagFromJson(json); 34 | 35 | Map toJson() => _$OTTagToJson(this); 36 | 37 | @override 38 | bool operator ==(Object other) => (other is OTTag) && tag_id == other.tag_id; 39 | 40 | const OTTag(this.tag_id, this.temperature, this.name); 41 | 42 | @override 43 | int get hashCode => tag_id!; 44 | 45 | Color get color => (name?.hashColor() ?? Colors.red); 46 | 47 | @override 48 | List get props { 49 | if (name == null) return []; 50 | return [name!]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/model/forum/user.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | // ignore_for_file: non_constant_identifier_names 19 | 20 | import 'package:dan_xi/model/forum/user_config.dart'; 21 | import 'package:dan_xi/model/forum/user_permission.dart'; 22 | import 'package:json_annotation/json_annotation.dart'; 23 | 24 | part 'user.g.dart'; 25 | 26 | @JsonSerializable() 27 | class OTUser { 28 | int? user_id; 29 | String? nickname; 30 | List? favorites; 31 | List? subscriptions; 32 | OTUserPermission? permission; 33 | OTUserConfig? config; 34 | String? joined_time; 35 | bool? is_admin; 36 | bool? has_answered_questions; 37 | 38 | factory OTUser.fromJson(Map json) => _$OTUserFromJson(json); 39 | 40 | Map toJson() => _$OTUserToJson(this); 41 | 42 | @override 43 | bool operator ==(Object other) => 44 | (other is OTUser) && user_id == other.user_id; 45 | 46 | OTUser( 47 | this.user_id, 48 | this.nickname, 49 | this.favorites, 50 | this.subscriptions, 51 | this.joined_time, 52 | this.config, 53 | this.permission, 54 | this.is_admin, 55 | this.has_answered_questions); 56 | 57 | @override 58 | int get hashCode => user_id!; 59 | } 60 | -------------------------------------------------------------------------------- /lib/model/forum/user_config.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | // ignore_for_file: non_constant_identifier_names 19 | 20 | import 'package:json_annotation/json_annotation.dart'; 21 | 22 | part 'user_config.g.dart'; 23 | 24 | @JsonSerializable() 25 | class OTUserConfig { 26 | List? notify; 27 | String? show_folded; 28 | 29 | factory OTUserConfig.fromJson(Map json) => 30 | _$OTUserConfigFromJson(json); 31 | 32 | Map toJson() => _$OTUserConfigToJson(this); 33 | 34 | OTUserConfig(this.notify, this.show_folded); 35 | } 36 | -------------------------------------------------------------------------------- /lib/model/forum/user_permission.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | // ignore_for_file: non_constant_identifier_names 19 | 20 | import 'package:json_annotation/json_annotation.dart'; 21 | 22 | part 'user_permission.g.dart'; 23 | 24 | @JsonSerializable() 25 | class OTUserPermission { 26 | Map? silent; 27 | String? admin; 28 | 29 | factory OTUserPermission.fromJson(Map json) => 30 | _$OTUserPermissionFromJson(json); 31 | 32 | Map toJson() => _$OTUserPermissionToJson(this); 33 | 34 | OTUserPermission(this.silent, this.admin); 35 | } 36 | -------------------------------------------------------------------------------- /lib/model/remote_sticker.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:json_annotation/json_annotation.dart'; 19 | 20 | part 'remote_sticker.g.dart'; 21 | 22 | @JsonSerializable() 23 | class RemoteSticker { 24 | final String id; 25 | final String url; 26 | final String sha256; 27 | 28 | RemoteSticker({ 29 | required this.id, 30 | required this.url, 31 | required this.sha256, 32 | }); 33 | 34 | factory RemoteSticker.fromJson(Map json) => 35 | _$RemoteStickerFromJson(json); 36 | 37 | Map toJson() => _$RemoteStickerToJson(this); 38 | 39 | factory RemoteSticker.fromToml(Map tomlData) { 40 | return RemoteSticker( 41 | id: tomlData['id'] as String, 42 | url: tomlData['url'] as String, 43 | sha256: tomlData['sha256'] as String, 44 | ); 45 | } 46 | } -------------------------------------------------------------------------------- /lib/provider/language_manager.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:dan_xi/common/constant.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class LanguageManager { 7 | /// Convert the [Language] to language code for [Locale]. 8 | static Locale toLocale(Language language) { 9 | if (language == Language.SIMPLE_CHINESE) return const Locale("zh", "CN"); 10 | if (language == Language.ENGLISH) return const Locale("en"); 11 | if (language == Language.JAPANESE) return const Locale("ja"); 12 | return const Locale("en"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/provider/notification_provider.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/feature/base_feature.dart'; 19 | import 'package:dan_xi/page/subpage_dashboard.dart'; 20 | import 'package:dan_xi/provider/settings_provider.dart'; 21 | import 'package:flutter/cupertino.dart'; 22 | 23 | /// Hold a list of notification shown in [HomeSubpage]. 24 | class NotificationProvider with ChangeNotifier { 25 | final List _notifications = []; 26 | 27 | List get notifications => _notifications; 28 | 29 | void addNotification(Feature feature) { 30 | if (_notifications.any((element) => 31 | element.runtimeType.toString() == feature.runtimeType.toString())) { 32 | return; 33 | } 34 | if (SettingsProvider.getInstance() 35 | .hiddenNotifications 36 | .contains(feature.runtimeType.toString())) { 37 | return; 38 | } 39 | 40 | _notifications.add(feature); 41 | notifyListeners(); 42 | } 43 | 44 | void removeNotification(Feature feature) { 45 | bool removed = false; 46 | _notifications.removeWhere((element) { 47 | final equality = 48 | feature.runtimeType.toString() == element.runtimeType.toString(); 49 | if (equality) removed = true; 50 | return equality; 51 | }); 52 | if (removed) notifyListeners(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/provider/state_provider.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/model/person.dart'; 19 | import 'package:dan_xi/provider/forum_provider.dart'; 20 | import 'package:flutter/cupertino.dart'; 21 | import 'package:provider/provider.dart'; 22 | 23 | /// Manage global states of the app. 24 | /// 25 | /// Code Structural Warning: 26 | /// You should ONLY directly refer to this class in the codes of 27 | /// Application layer, rather than in any classes of Util, Model or Repository. 28 | /// Do NOT break the decoupling of the project! 29 | class StateProvider { 30 | /// The user's basic information. 31 | static final ValueNotifier isLoggedIn = ValueNotifier(false); 32 | static final ValueNotifier personInfo = ValueNotifier(null); 33 | static bool needScreenshotWarning = false; 34 | static bool isForeground = true; 35 | static bool showingScreenshotWarning = false; 36 | 37 | static String? onlineUserAgent; 38 | 39 | static void initialize(BuildContext context) { 40 | ForumProvider provider = context.read(); 41 | provider.currentDivisionId = null; 42 | isLoggedIn.value = false; 43 | personInfo.value = null; 44 | isForeground = true; 45 | needScreenshotWarning = showingScreenshotWarning = false; 46 | provider.editorCache.clear(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/repository/fdu/library_repository.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'dart:convert'; 19 | 20 | import 'package:dan_xi/repository/base_repository.dart'; 21 | import 'package:dio/dio.dart'; 22 | 23 | class FudanLibraryRepository extends BaseRepositoryWithDio { 24 | static const String _INFO_URL = 25 | "https://mlibrary.fudan.edu.cn/api/common/h5/getspaceseat"; 26 | 27 | FudanLibraryRepository._(); 28 | 29 | static final _instance = FudanLibraryRepository._(); 30 | 31 | factory FudanLibraryRepository.getInstance() => _instance; 32 | 33 | Future> getLibraryRawData() async { 34 | Response r = await dio.post(_INFO_URL); 35 | final jsonData = json.decode(r.data!); 36 | final campusToInNum = {}; 37 | for (final item in jsonData['data']) { 38 | final campusName = item['campusName']; 39 | final inNum = item['inNum']; 40 | campusToInNum[campusName] = inNum; 41 | } 42 | return campusToInNum; 43 | } 44 | 45 | @override 46 | String get linkHost => "fudan.edu.cn"; 47 | } 48 | -------------------------------------------------------------------------------- /lib/repository/fdu/qr_code_repository.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:beautiful_soup_dart/beautiful_soup.dart'; 19 | import 'package:dan_xi/repository/base_repository.dart'; 20 | import 'package:dan_xi/repository/fdu/neo_login_tool.dart'; 21 | import 'package:dio/dio.dart'; 22 | 23 | class TermsNotAgreed implements Exception {} 24 | 25 | class QRCodeRepository extends BaseRepositoryWithDio { 26 | static const String QR_URL = 27 | "https://ecard.fudan.edu.cn/epay/wxpage/fudan/zfm/qrcode"; 28 | 29 | QRCodeRepository._(); 30 | 31 | static final _instance = QRCodeRepository._(); 32 | 33 | factory QRCodeRepository.getInstance() => _instance; 34 | 35 | Future getQRCode() { 36 | final options = RequestOptions( 37 | method: "GET", 38 | path: QR_URL, 39 | responseType: ResponseType.plain, 40 | ); 41 | return FudanSession.request(options, (rep) { 42 | final soup = BeautifulSoup(rep.data.toString()); 43 | try { 44 | return soup.find("#myText")!.attributes['value']!; 45 | } catch (_) { 46 | if (soup.find("#btn-agree-ok") != null) { 47 | throw TermsNotAgreed(); 48 | } else { 49 | rethrow; 50 | } 51 | } 52 | }, isFatalError: (e) => e is TermsNotAgreed); 53 | } 54 | 55 | @override 56 | String get linkHost => "fudan.edu.cn"; 57 | } 58 | -------------------------------------------------------------------------------- /lib/util/animation.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Odyso Project 3 | */ 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | class MySlideTransition extends AnimatedWidget { 8 | const MySlideTransition({ 9 | super.key, 10 | required Animation position, 11 | this.transformHitTests = true, 12 | required this.child, 13 | }) : super(listenable: position); 14 | 15 | Animation get position => listenable as Animation; 16 | final bool transformHitTests; 17 | final Widget child; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | Offset offset = position.value; 22 | //当即将执行退场动画时 23 | if (position.status == AnimationStatus.reverse) { 24 | offset = Offset(-offset.dx, offset.dy); 25 | } 26 | return FractionalTranslation( 27 | translation: offset, 28 | transformHitTests: transformHitTests, 29 | child: child, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/util/condition_variable.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:collection'; 3 | 4 | import 'package:mutex/mutex.dart'; 5 | 6 | /// Copied from https://github.com/adrianjagielak/semaphore_plus/blob/master/lib/src/condition_variable/condition_variable.dart. 7 | 8 | class ConditionVariable { 9 | final Queue> _readyQueue = Queue>(); 10 | 11 | final Mutex _lock; 12 | 13 | ConditionVariable(this._lock); 14 | 15 | Future signal() async { 16 | if (_readyQueue.isNotEmpty) { 17 | final completer = _readyQueue.removeFirst(); 18 | completer.complete(); 19 | } 20 | } 21 | 22 | Future wait() async { 23 | final completer = Completer(); 24 | _readyQueue.add(completer); 25 | _lock.release(); 26 | 27 | await completer.future; 28 | await _lock.acquire(); 29 | } 30 | 31 | Future broadcast() async { 32 | final completers = _readyQueue.toList(); 33 | _readyQueue.clear(); 34 | for (final completer in completers) { 35 | completer.complete(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /lib/util/danxi_care.dart: -------------------------------------------------------------------------------- 1 | import 'package:dan_xi/common/constant.dart'; 2 | 3 | Future detectCareWords(String? target) async { 4 | if (target == null) { 5 | return false; 6 | } 7 | 8 | List careWords = await Constant.careWords; 9 | 10 | for (var word in careWords) { 11 | if (target.contains(word)) { 12 | return true; 13 | } 14 | } 15 | 16 | return false; 17 | } 18 | -------------------------------------------------------------------------------- /lib/util/forum/clean_mode_filter.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | class CleanModeFilter { 19 | static const List DELETE_EMOJI = [ 20 | '😅', 21 | '😄', 22 | '😋', 23 | '🥰', 24 | '🤭', 25 | '😊', 26 | '😍', 27 | '😇', 28 | '🤗', 29 | '😁', 30 | '🤤', 31 | '😡', 32 | '🥵', 33 | '🤭', 34 | '🤓' 35 | ]; 36 | static const List CN_FILTER_TEXT = [ 37 | '差不多得了', 38 | '傻逼', 39 | '伞兵', 40 | 'nmsl', 41 | 'sb', 42 | '4000+', 43 | '你妈死了', 44 | '批' 45 | ]; 46 | 47 | static String? cleanText(String? content) { 48 | String? newContent = content; 49 | for (var element in DELETE_EMOJI) { 50 | newContent = newContent!.replaceAll(element, ' '); 51 | } 52 | 53 | /* CN_FILTER_TEXT.forEach((element) { 54 | final filterRegex = RegExp( 55 | r'[\u4E00-\u9FFF\b]' + RegExp.escape(element) + r'[\u4E00-\u9FFF\b]', 56 | caseSensitive: false, 57 | unicode: false); 58 | newContent = newContent.replaceAll(filterRegex, r' !@#$% '); 59 | });*/ 60 | return newContent; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/util/forum/editor_object.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import 'package:dan_xi/page/forum/hole_editor.dart'; 18 | 19 | /// [EditorObject] represents an object the [BBSEditorWidget] replies or posts to. 20 | /// 21 | /// See also: 22 | /// 23 | /// * [FDUHoleProvider], where [EditorObject]s are usually stored. 24 | class EditorObject { 25 | /// The post id or discussion id. 26 | /// 27 | /// Set to 0 if creating a new post. 28 | final int? id; 29 | final EditorObjectType type; 30 | 31 | @override 32 | bool operator ==(Object other) => 33 | identical(this, other) || 34 | other is EditorObject && 35 | runtimeType == other.runtimeType && 36 | id == other.id && 37 | type == other.type; 38 | 39 | @override 40 | int get hashCode => id.hashCode ^ type.hashCode; 41 | 42 | EditorObject(this.id, this.type); 43 | } 44 | 45 | enum EditorObjectType { 46 | NONE, 47 | REPLY_TO_FLOOR, 48 | REPLY_TO_HOLE, 49 | MODIFY_FLOOR, 50 | NEW_POST 51 | } 52 | -------------------------------------------------------------------------------- /lib/util/forum/fduhole_platform_bridge.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/util/platform_universal.dart'; 19 | import 'package:flutter/services.dart'; 20 | 21 | class FDUHolePlatformBridge { 22 | static const FORUM_CHANNEL = MethodChannel('fduhole'); 23 | 24 | static void registerRemoteNotification() { 25 | if (PlatformX.isIOS) { 26 | FORUM_CHANNEL.invokeMethod("request_notification_permission"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/util/forum/human_duration.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import 'package:dan_xi/generated/l10n.dart'; 18 | import 'package:flutter/cupertino.dart'; 19 | import 'package:intl/intl.dart'; 20 | 21 | /// Create human-readable duration, e.g.: 1 hour ago, 2 days ago 22 | class HumanDuration { 23 | static String tryFormat(BuildContext context, DateTime? dateTime) { 24 | try { 25 | final Duration duration = DateTime.now().difference(dateTime!); 26 | if (duration.inSeconds < 1) { 27 | return S.of(context).moment_ago; 28 | } else if (duration.inMinutes < 1) { 29 | return S.of(context).second_ago(duration.inSeconds); 30 | } else if (duration.inHours < 1) { 31 | return S.of(context).minute_ago(duration.inMinutes); 32 | } else if (duration.inDays < 1) { 33 | return S.of(context).hour_ago(duration.inHours); 34 | } else if (duration.inDays <= 30) { 35 | return S.of(context).day_ago(duration.inDays); 36 | } else { 37 | return DateFormat("yyyy/MM/dd").format(dateTime.toLocal()); 38 | } 39 | } catch (e) { 40 | return ""; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/util/js/js.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:flutter_js/flutter_js.dart'; 19 | 20 | var flutterJs = getJavascriptRuntime(); 21 | 22 | String evaluate(String jsCode) { 23 | return flutterJs.evaluate(jsCode).stringResult; 24 | } 25 | -------------------------------------------------------------------------------- /lib/util/js/js_web.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | // ignore: deprecated_member_use 19 | import 'package:js/js.dart'; 20 | 21 | @JS('window.eval') 22 | external dynamic eval(dynamic arg); 23 | 24 | String evaluate(String jsCode) { 25 | return eval(jsCode).toString(); 26 | } 27 | -------------------------------------------------------------------------------- /lib/util/master_detail_utils.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:flutter/widgets.dart'; 19 | 20 | const kTabletMasterContainerWidth = 370.0; 21 | 22 | bool isTablet(BuildContext context) { 23 | // A tablet view (i.e. dual-pane layout) is defined as a device with a screen width of 840dp or greater. 24 | // Reference: 25 | // 1. https://developer.android.com/develop/ui/compose/layouts/adaptive/use-window-size-classes 26 | // 2. https://m2.material.io/design/layout/responsive-layout-grid.html#breakpoints 27 | // 3. https://m3.material.io/foundations/layout/applying-layout/window-size-classes 28 | return MediaQuery.widthOf(context) >= 840.0; 29 | } 30 | -------------------------------------------------------------------------------- /lib/util/screen_proxy.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/util/platform_universal.dart'; 19 | import 'package:screen_brightness/screen_brightness.dart'; 20 | 21 | /// A proxy class for [ScreenBrightness] to make it work on all platforms. 22 | class ScreenProxy { 23 | static Future init() async { 24 | if (PlatformX.isMobile) await ScreenBrightness().setAutoReset(false); 25 | } 26 | 27 | static Future get brightness async { 28 | if (PlatformX.isMobile) { 29 | return await ScreenBrightness().application; 30 | } else { 31 | return 0; 32 | } 33 | } 34 | 35 | static Future setBrightness(double brightness) async { 36 | if (PlatformX.isMobile) { 37 | await ScreenBrightness().setApplicationScreenBrightness(brightness); 38 | } 39 | } 40 | 41 | static Future resetBrightness() async { 42 | if (PlatformX.isMobile) { 43 | await ScreenBrightness().resetApplicationScreenBrightness(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/util/universal_link/apple-app-site-association.json: -------------------------------------------------------------------------------- 1 | { 2 | "applinks": { 3 | "apps": [], 4 | "details": [ 5 | { 6 | "appID": "QZ9KCS2T78.io.github.danxi-dev.dan-xi", 7 | "paths": ["*"] 8 | } 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /lib/util/universal_link/assetlinks.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "relation": ["delegate_permission/common.handle_all_urls"], 3 | "target" : { "namespace": "android_app", "package_name": "io.github.danxi_dev.dan_xi", 4 | "sha256_cert_fingerprints": ["8D:3A:9A:8E:C8:37:34:39:3C:78:88:0A:62:F8:56:BC:9F:E1:A3:8D:8E:80:E0:BC:15:15:D8:CB:F1:8D:C1:8A"] } 5 | }] -------------------------------------------------------------------------------- /lib/util/viewport_utils.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import 'package:dan_xi/util/master_detail_utils.dart'; 18 | import 'package:flutter/cupertino.dart'; 19 | 20 | /// Some useful methods to help get an accurate size whether in mobile or tablet mode. 21 | class ViewportUtils { 22 | static double getViewportWidth(BuildContext context) => 23 | MediaQuery.of(context).size.width; 24 | 25 | static double getViewportHeight(BuildContext context) => 26 | MediaQuery.of(context).size.height; 27 | 28 | static Size getMainNavigatorSize(BuildContext context) => 29 | Size(getMainNavigatorWidth(context), getMainNavigatorHeight(context)); 30 | 31 | static double getMainNavigatorWidth(BuildContext context) => isTablet(context) 32 | ? kTabletMasterContainerWidth 33 | : getViewportWidth(context); 34 | 35 | static double getMainNavigatorHeight(BuildContext context) => 36 | getViewportHeight(context); 37 | } 38 | -------------------------------------------------------------------------------- /lib/util/win32/auto_start.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/util/platform_universal.dart'; 19 | import 'package:dan_xi/util/win32/registry.dart'; 20 | import 'package:win32/win32.dart'; 21 | 22 | class WindowsAutoStart { 23 | static const KEY_PATH = r'Software\Microsoft\Windows\CurrentVersion\Run'; 24 | static const KEY_NAME = "Danxi"; 25 | static const KEY_FULL_PATH = 26 | r"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run"; 27 | 28 | static bool get autoStart { 29 | int hKey = Registry.getRegistryKeyHandle(HKEY_CURRENT_USER, KEY_PATH); 30 | String? path; 31 | try { 32 | path = Registry.getStringKey(hKey, KEY_NAME); 33 | } catch (_) { 34 | } finally { 35 | RegCloseKey(hKey); 36 | } 37 | return PlatformX.executablePath == path; 38 | } 39 | 40 | static set autoStart(bool value) { 41 | if (value) { 42 | Registry.setStringValueA( 43 | KEY_FULL_PATH, KEY_NAME, PlatformX.executablePath); 44 | } else { 45 | Registry.deleteStringKeyA(KEY_FULL_PATH, KEY_NAME); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/util/win32/auto_start_stub.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | class WindowsAutoStart { 19 | static bool get autoStart => false; 20 | 21 | static set autoStart(bool value) {} 22 | } 23 | -------------------------------------------------------------------------------- /lib/util/win32/shell.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'dart:ffi'; 19 | 20 | import 'package:ffi/ffi.dart'; 21 | import 'package:win32/win32.dart'; 22 | 23 | class Win32Shell { 24 | /// Execute shell, return the status code. 25 | /// 26 | /// Notes: It WON'T wait the process to finish. 27 | static int executeShell(String filePath, 28 | {int showCmd = SW_HIDE, 29 | String? dir, 30 | String param = '', 31 | bool runAsAdmin = false}) { 32 | return ShellExecute( 33 | 0, 34 | runAsAdmin ? "runas".toNativeUtf16() : nullptr, 35 | filePath.toNativeUtf16(), 36 | param.toNativeUtf16(), 37 | dir?.toNativeUtf16() ?? nullptr, 38 | showCmd); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/widget/dialogs/care_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:dan_xi/util/browser_util.dart'; 2 | import 'package:dan_xi/widget/forum/post_render.dart'; 3 | import 'package:dan_xi/widget/forum/render/render_impl.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; 7 | 8 | import '../../generated/l10n.dart'; 9 | 10 | class CareDialog extends StatefulWidget { 11 | const CareDialog({super.key}); 12 | 13 | @override 14 | State createState() => _CareDialogState(); 15 | } 16 | 17 | class _CareDialogState extends State { 18 | @override 19 | Widget build(BuildContext context) { 20 | return PlatformAlertDialog( 21 | title: Text(S.of(context).danxi_care), 22 | content: SingleChildScrollView( 23 | child: PostRenderWidget( 24 | content: S.of(context).danxi_care_message, 25 | render: kMarkdownRender, 26 | onTapLink: (url) => BrowserUtil.openUrl(url!, null), 27 | hasBackgroundImage: false, 28 | )), 29 | actions: [ 30 | PlatformDialogAction( 31 | child: Text(S.of(context).i_see), 32 | onPressed: () => Navigator.of(context).pop(), 33 | ) 34 | ], 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/widget/feature_item/feature_progress_indicator.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/feature/base_feature.dart'; 19 | import 'package:dan_xi/util/platform_universal.dart'; 20 | import 'package:dan_xi/widget/libraries/scale_transform.dart'; 21 | import 'package:flutter/widgets.dart'; 22 | import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; 23 | 24 | /// A slightly smaller version of [CircularProgressIndicator]. 25 | /// 26 | /// It is commonly used in [Feature] to indicate that the feature is loading. 27 | class FeatureProgressIndicator extends StatelessWidget { 28 | const FeatureProgressIndicator({super.key}); 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return ScaleTransform( 33 | scale: PlatformX.isMaterial(context) ? 0.5 : 1.0, 34 | child: PlatformCircularProgressIndicator(), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/widget/forum/post_render.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/widget/forum/render/base_render.dart'; 19 | import 'package:flutter/widgets.dart'; 20 | 21 | class PostRenderWidget extends StatelessWidget { 22 | final String? content; 23 | final BaseRender render; 24 | final ImageTapCallback? onTapImage; 25 | final LinkTapCallback? onTapLink; 26 | final bool hasBackgroundImage; 27 | final bool isPreviewWidget; 28 | final ImageLongPressCallback? onLongPressImage; 29 | 30 | const PostRenderWidget( 31 | {super.key, 32 | required this.content, 33 | required this.render, 34 | this.onTapImage, 35 | this.onTapLink, 36 | required this.hasBackgroundImage, 37 | this.isPreviewWidget = false, 38 | this.onLongPressImage}); 39 | 40 | @override 41 | Widget build(BuildContext context) => render.call(context, content, 42 | hasBackgroundImage, isPreviewWidget, 43 | onTapImage: onTapImage, 44 | onTapLink: onTapLink, 45 | onLongPressImage: onLongPressImage); 46 | } 47 | -------------------------------------------------------------------------------- /lib/widget/forum/render/base_render.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:flutter/cupertino.dart'; 19 | 20 | typedef LinkTapCallback = void Function(String? url); 21 | typedef ImageTapCallback = void Function(String? url, Object heroTag); 22 | typedef ImageLongPressCallback = void Function(String? url); 23 | 24 | /// BaseRender is the base type of a render which renders the post raw [content] into a [Widget]. 25 | /// 26 | /// [kHtmlRender] is one of its implementations. 27 | typedef BaseRender = Widget Function( 28 | BuildContext context, 29 | String? content, 30 | bool translucentCard, 31 | bool isPreviewWidget, 32 | {ImageTapCallback? onTapImage, 33 | LinkTapCallback? onTapLink, 34 | ImageLongPressCallback? onLongPressImage}); 35 | -------------------------------------------------------------------------------- /lib/widget/libraries/image_picker_proxy.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/util/platform_universal.dart'; 19 | import 'package:file_picker/file_picker.dart'; 20 | import 'package:image_picker/image_picker.dart'; 21 | 22 | abstract class ImagePickerProxy { 23 | Future pickImage(); 24 | 25 | factory ImagePickerProxy.createPicker() { 26 | if (PlatformX.isMobile) { 27 | return _ImagePickerMobile(); 28 | } else { 29 | return _ImagePickerUniversal(); 30 | } 31 | } 32 | 33 | ImagePickerProxy(); 34 | } 35 | 36 | class _ImagePickerMobile extends ImagePickerProxy { 37 | final ImagePicker _picker = ImagePicker(); 38 | 39 | @override 40 | Future pickImage() async { 41 | XFile? image = await _picker.pickImage(source: ImageSource.gallery); 42 | return image?.path; 43 | } 44 | } 45 | 46 | class _ImagePickerUniversal extends ImagePickerProxy { 47 | @override 48 | Future pickImage() async { 49 | FilePickerResult? result = 50 | await FilePicker.platform.pickFiles(type: FileType.image); 51 | return result?.files.single.path; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/widget/libraries/linkify_x.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/common/constant.dart'; 19 | import 'package:flutter/material.dart'; 20 | import 'package:flutter_linkify/flutter_linkify.dart'; 21 | 22 | /// [Linkify] with a default link theme. 23 | /// 24 | /// It is sad that [Linkify] hardcoded the link style in its source code, so we 25 | /// have to create a new class to override it. 26 | class LinkifyX extends Linkify { 27 | const LinkifyX({ 28 | super.key, 29 | required super.text, 30 | super.onOpen, 31 | super.textAlign, 32 | super.textScaleFactor, 33 | super.maxLines, 34 | TextOverflow super.overflow, 35 | super.style, 36 | }) : super( 37 | linkStyle: Constant.LINKIFY_THEME, 38 | ); 39 | } 40 | 41 | class SelectableLinkifyX extends SelectableLinkify { 42 | const SelectableLinkifyX({ 43 | super.key, 44 | required super.text, 45 | super.onOpen, 46 | TextAlign super.textAlign = TextAlign.start, 47 | super.textScaleFactor, 48 | super.maxLines, 49 | super.style, 50 | }) : super( 51 | linkStyle: Constant.LINKIFY_THEME, 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /lib/widget/libraries/scale_transform.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:flutter/widgets.dart'; 19 | 20 | /// A widget that will scale its child at specific scale. 21 | class ScaleTransform extends StatelessWidget { 22 | final Widget? child; 23 | final double? scale; 24 | 25 | const ScaleTransform({super.key, this.scale, this.child}); 26 | 27 | @override 28 | Widget build(BuildContext context) => Transform( 29 | alignment: Alignment.center, 30 | transform: Matrix4.identity()..scale(scale, scale, 1.0), 31 | child: child); 32 | } 33 | -------------------------------------------------------------------------------- /lib/widget/libraries/sized_by_child_builder.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:flutter/widgets.dart'; 19 | 20 | /// This widget is used to build a widget with sizes determined by its [child], 21 | /// after that, the sizes will be remembered and used for the next build, 22 | /// which calls [builder] with the remembered sizes. 23 | class SizedByChildBuilder extends StatefulWidget { 24 | final Widget Function(BuildContext, Key) child; 25 | final Widget Function(BuildContext, Size) builder; 26 | 27 | const SizedByChildBuilder( 28 | {super.key, required this.child, required this.builder}); 29 | 30 | @override 31 | State createState() => _SizedByChildBuilderState(); 32 | } 33 | 34 | class _SizedByChildBuilderState extends State { 35 | Size? _size; 36 | final GlobalKey _key = GlobalKey(); 37 | 38 | @override 39 | void initState() { 40 | super.initState(); 41 | WidgetsBinding.instance.endOfFrame.then( 42 | (_) { 43 | if (mounted && _size == null) { 44 | setState(() { 45 | _size = _key.currentContext!.size; 46 | }); 47 | } 48 | }, 49 | ); 50 | } 51 | 52 | @override 53 | Widget build(BuildContext context) { 54 | if (_size == null) { 55 | return widget.child(context, _key); 56 | } else { 57 | return widget.builder(context, _size!); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/widget/libraries/small_tag.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import 'package:flutter/material.dart'; 18 | 19 | /// SmallTag is a small tag, usually showing on the home page to visualize different data items. 20 | /// Such as "Next course", "Last transaction", etc. 21 | /// 22 | /// It uses [Theme.of(context).hintColor] as its background color, and 23 | /// self-adaptive text color by default. 24 | class SmallTag extends StatelessWidget { 25 | final String? label; 26 | 27 | const SmallTag({super.key, this.label}); 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Container( 32 | padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), 33 | decoration: BoxDecoration( 34 | color: Theme.of(context).hintColor.withValues(alpha: 0.25), 35 | borderRadius: const BorderRadius.all(Radius.circular(4.0))), 36 | child: Text( 37 | label!, 38 | style: TextStyle( 39 | color: Theme.of(context).hintColor.computeLuminance() >= 0.5 40 | ? Colors.black 41 | : Colors.white, 42 | fontSize: 12), 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/widget/libraries/state_key.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:flutter/cupertino.dart'; 19 | 20 | /// StateKey is a ValueKey with current context of the child widget. 21 | /// With the help of [WithStateKey], we can easily obtain a widget instance just with the key. 22 | /// 23 | /// However, the key may not be used as a "true" key to pass to a widget's initializer, 24 | /// since it is not immutable and not reliable. 25 | class StateKey extends ValueKey { 26 | late BuildContext currentContext; 27 | 28 | StateKey(super.value); 29 | } 30 | 31 | class WithStateKey extends StatefulWidget { 32 | final StateKey? childKey; 33 | final Widget? child; 34 | 35 | const WithStateKey({super.key, this.childKey, this.child}); 36 | 37 | @override 38 | WithStateKeyState createState() => WithStateKeyState(); 39 | } 40 | 41 | class WithStateKeyState extends State> 42 | with AutomaticKeepAliveClientMixin { 43 | @override 44 | Widget build(BuildContext context) { 45 | super.build(context); 46 | widget.childKey!.currentContext = context; 47 | return widget.child!; 48 | } 49 | 50 | @override 51 | void initState() { 52 | super.initState(); 53 | widget.childKey!.currentContext = context; 54 | } 55 | 56 | @override 57 | bool get wantKeepAlive => true; 58 | } 59 | -------------------------------------------------------------------------------- /lib/widget/libraries/top_controller.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/widget/libraries/platform_app_bar_ex.dart'; 19 | import 'package:flutter/widgets.dart'; 20 | 21 | /// A widget that listens to the double tap on its child, 22 | /// controlling a [ScrollController] or calling [onDoubleTap] method to scroll to the top. 23 | /// 24 | /// Usually wrap a [Text] widget in [PlatformAppBarX]. 25 | class TopController extends StatelessWidget { 26 | final Widget? child; 27 | final ScrollController? controller; 28 | final Function? onDoubleTap; 29 | 30 | const TopController( 31 | {super.key, this.controller, this.onDoubleTap, this.child}); 32 | 33 | static Future? scrollToTop(ScrollController? controller) => 34 | controller?.animateTo(-controller.initialScrollOffset, 35 | duration: const Duration(milliseconds: 300), curve: Curves.easeInOut); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return GestureDetector( 40 | onDoubleTap: () { 41 | final currentController = 42 | controller ?? PrimaryScrollController.of(context); 43 | TopController.scrollToTop(currentController); 44 | if (onDoubleTap != null) { 45 | onDoubleTap!.call(); 46 | } 47 | }, 48 | child: child, 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/widget/libraries/with_scrollbar.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/util/platform_universal.dart'; 19 | import 'package:flutter/cupertino.dart'; 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; 22 | 23 | /// A widget that will add a scroll bar for its child. 24 | class WithScrollbar extends StatelessWidget { 25 | final ScrollController? controller; 26 | final Widget? child; 27 | 28 | const WithScrollbar({super.key, this.controller, this.child}); 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return PlatformWidget( 33 | // Add a scrollbar on desktop platform 34 | material: (_, __) => Scrollbar( 35 | controller: controller, 36 | interactive: PlatformX.isDesktop, 37 | child: child!, 38 | ), 39 | cupertino: (_, __) => CupertinoScrollbar( 40 | controller: controller, 41 | child: child!, 42 | )); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/widget/time_table/day_events.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/model/time_table.dart'; 19 | 20 | /// [DayEvents] is a list of [Event]s on a specific day. 21 | class DayEvents { 22 | /// A localized string representing the day of week. 23 | final String day; 24 | 25 | final int weekday; 26 | final List events; 27 | 28 | DayEvents({ 29 | required this.weekday, 30 | required this.day, 31 | required this.events, 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /lib/widget/time_table/event.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/model/time_table.dart'; 19 | 20 | /// [Event] represents a specific course at a specific time. 21 | /// 22 | /// Usually you can ignore [course.times], and treat the [course] as a single event. 23 | class Event { 24 | final Course course; 25 | 26 | final CourseTime slot; 27 | 28 | Event({ 29 | required this.course, 30 | required this.slot, 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /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 | desktop_window 7 | dynamic_color 8 | file_selector_linux 9 | flutter_js 10 | flutter_secure_storage_linux 11 | gtk 12 | open_file_linux 13 | platform_device_id_linux 14 | url_launcher_linux 15 | ) 16 | 17 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 18 | ) 19 | 20 | set(PLUGIN_BUNDLED_LIBRARIES) 21 | 22 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 24 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 27 | endforeach(plugin) 28 | 29 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 30 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 31 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 32 | endforeach(ffi_plugin) 33 | -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char **argv) { 4 | g_autoptr(MyApplication) 5 | app = my_application_new(); 6 | return g_application_run(G_APPLICATION(app), argc, argv); 7 | } 8 | -------------------------------------------------------------------------------- /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 | /** 11 | * my_application_new: 12 | * 13 | * Creates a new Flutter-based application. 14 | * 15 | * Returns: a new #MyApplication. 16 | */ 17 | MyApplication *my_application_new(); 18 | 19 | #endif // FLUTTER_MY_APPLICATION_H_ 20 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/256 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/256 1.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/32 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/32 1.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/512 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/512 1.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/macos/Runner/Assets.xcassets/AppIcon.appiconset/64.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "32.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "32 1.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "64.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "256.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "256 1.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "512.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "512 1.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "1024.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = dan_xi 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = io.github.w568w.danXi 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2021 io.github.w568w. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | com.apple.security.network.client 12 | 13 | keychain-access-groups 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSApplicationCategoryType 24 | public.app-category.utilities 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | 32 | NSHumanReadableCopyright 33 | $(PRODUCT_COPYRIGHT) 34 | NSMainNibFile 35 | MainMenu 36 | NSPrincipalClass 37 | NSApplication 38 | 39 | 40 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | 10 | // Set Window Initial Size 11 | self.setFrame(windowFrame, display: true) 12 | 13 | RegisterGeneratedPlugins(registry: flutterViewController) 14 | 15 | super.awakeFromNib() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | com.apple.security.network.server 10 | 11 | keychain-access-groups 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packaging/dan_xi.png: -------------------------------------------------------------------------------- 1 | ../ios/Runner/Assets.xcassets/AppIcon.appiconset/1.2.0-1024.png -------------------------------------------------------------------------------- /packaging/io.github.danxi_dev.dan_xi.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=DanXi 4 | Name[zh_CN]=旦挞 5 | Comment=Maybe the best all-rounded service app for Fudan University students 6 | Comment[zh_CN]=可能是复旦学生最好的第三方校园服务 APP 7 | Exec=dan_xi 8 | Icon=dan_xi 9 | Terminal=false 10 | Categories=Education 11 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 DanXi-Dev 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import 'package:dan_xi/main.dart'; 19 | 20 | // This is a basic Flutter widget test. 21 | // 22 | // To perform an interaction with a widget in your test, use the WidgetTester 23 | // utility that Flutter provides. For example, you can send tap and scroll 24 | // gestures. You can also use WidgetTester to find child widgets in the widget 25 | // tree, read text, and verify that the values of widget properties are correct. 26 | 27 | import 'package:flutter_test/flutter_test.dart'; 28 | 29 | void main() { 30 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 31 | // Build our app and trigger a frame. 32 | await tester.pumpWidget(const DanxiApp()); 33 | 34 | // Verify that our counter starts at 0. 35 | // expect(find.text('0'), findsOneWidget); 36 | // expect(find.text('1'), findsNothing); 37 | // 38 | // // Tap the '+' icon and trigger a frame. 39 | // await tester.tap(find.byIcon(Icons.add)); 40 | // await tester.pump(); 41 | // 42 | // // Verify that our counter has incremented. 43 | // expect(find.text('0'), findsNothing); 44 | // expect(find.text('1'), findsOneWidget); 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /web/favicon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/web/favicon.webp -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 旦挞 Web 32 | 33 | 34 | 36 | 37 | 38 | 39 | 42 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dan_xi", 3 | "short_name": "dan_xi", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter application.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /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.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 | app_links 7 | desktop_window 8 | dynamic_color 9 | file_selector_windows 10 | flutter_inappwebview_windows 11 | flutter_js 12 | flutter_secure_storage_windows 13 | gal 14 | permission_handler_windows 15 | platform_device_id_windows 16 | screen_brightness_windows 17 | share_plus 18 | url_launcher_windows 19 | ) 20 | 21 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 22 | ) 23 | 24 | set(PLUGIN_BUNDLED_LIBRARIES) 25 | 26 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 27 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 28 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 29 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 30 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 31 | endforeach(plugin) 32 | 33 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 34 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 35 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 36 | endforeach(ffi_plugin) 37 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(runner LANGUAGES CXX) 3 | 4 | add_executable(${BINARY_NAME} WIN32 5 | "flutter_window.cpp" 6 | "main.cpp" 7 | "run_loop.cpp" 8 | "utils.cpp" 9 | "win32_window.cpp" 10 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 11 | "Runner.rc" 12 | "runner.exe.manifest" 13 | ) 14 | apply_standard_settings(${BINARY_NAME}) 15 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 16 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 17 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 18 | add_dependencies(${BINARY_NAME} flutter_assemble) 19 | -------------------------------------------------------------------------------- /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 "run_loop.h" 10 | #include "win32_window.h" 11 | 12 | // A window that does nothing but host a Flutter view. 13 | class FlutterWindow : public Win32Window { 14 | public: 15 | // Creates a new FlutterWindow driven by the |run_loop|, hosting a 16 | // Flutter view running |project|. 17 | explicit FlutterWindow(RunLoop* run_loop, 18 | const flutter::DartProject& project); 19 | virtual ~FlutterWindow(); 20 | 21 | protected: 22 | // Win32Window: 23 | bool OnCreate() override; 24 | void OnDestroy() override; 25 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 26 | LPARAM const lparam) noexcept override; 27 | 28 | private: 29 | // The run loop driving events for this window. 30 | RunLoop* run_loop_; 31 | 32 | // The project to run. 33 | flutter::DartProject project_; 34 | 35 | // The Flutter instance hosted by this window. 36 | std::unique_ptr flutter_controller_; 37 | }; 38 | 39 | #endif // RUNNER_FLUTTER_WINDOW_H_ 40 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "run_loop.h" 7 | #include "utils.h" 8 | 9 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 10 | _In_ wchar_t *command_line, _In_ int show_command) { 11 | // Attach to console when present (e.g., 'flutter run') or create a 12 | // new console when running with a debugger. 13 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 14 | CreateAndAttachConsole(); 15 | } 16 | 17 | // Initialize COM, so that it is available for use in the library and/or 18 | // plugins. 19 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 20 | 21 | RunLoop run_loop; 22 | 23 | flutter::DartProject project(L"data"); 24 | 25 | std::vector command_line_arguments = 26 | GetCommandLineArguments(); 27 | 28 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 29 | 30 | FlutterWindow window(&run_loop, project); 31 | Win32Window::Point origin(10, 10); 32 | Win32Window::Size size(1280, 720); 33 | if (!window.CreateAndShow(L"dan_xi", origin, size)) { 34 | return EXIT_FAILURE; 35 | } 36 | window.SetQuitOnClose(true); 37 | 38 | run_loop.Run(); 39 | 40 | ::CoUninitialize(); 41 | return EXIT_SUCCESS; 42 | } 43 | -------------------------------------------------------------------------------- /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/DanXi-Dev/DanXi/ed8c4c88fe061401b9ee83652b49077373261d28/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /windows/runner/run_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_RUN_LOOP_H_ 2 | #define RUNNER_RUN_LOOP_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | // A runloop that will service events for Flutter instances as well 10 | // as native messages. 11 | class RunLoop { 12 | public: 13 | RunLoop(); 14 | ~RunLoop(); 15 | 16 | // Prevent copying 17 | RunLoop(RunLoop const&) = delete; 18 | RunLoop& operator=(RunLoop const&) = delete; 19 | 20 | // Runs the run loop until the application quits. 21 | void Run(); 22 | 23 | // Registers the given Flutter instance for event servicing. 24 | void RegisterFlutterInstance( 25 | flutter::FlutterEngine* flutter_instance); 26 | 27 | // Unregisters the given Flutter instance from event servicing. 28 | void UnregisterFlutterInstance( 29 | flutter::FlutterEngine* flutter_instance); 30 | 31 | private: 32 | using TimePoint = std::chrono::steady_clock::time_point; 33 | 34 | // Processes all currently pending messages for registered Flutter instances. 35 | TimePoint ProcessFlutterMessages(); 36 | 37 | std::set flutter_instances_; 38 | }; 39 | 40 | #endif // RUNNER_RUN_LOOP_H_ 41 | -------------------------------------------------------------------------------- /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 | if (target_length == 0) { 52 | return std::string(); 53 | } 54 | std::string utf8_string; 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------