├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yaml
│ └── feature_request.yaml
└── workflows
│ └── main.yml
├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── lucinhu
│ │ │ │ └── bili_you
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-hdpi-v26
│ │ │ └── ic_launcher_monochrome.png
│ │ │ ├── drawable-hdpi
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-mdpi-v26
│ │ │ └── ic_launcher_monochrome.png
│ │ │ ├── drawable-mdpi
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-xhdpi-v26
│ │ │ └── ic_launcher_monochrome.png
│ │ │ ├── drawable-xhdpi
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-xxhdpi-v26
│ │ │ └── ic_launcher_monochrome.png
│ │ │ ├── drawable-xxhdpi
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-xxxhdpi-v26
│ │ │ └── ic_launcher_monochrome.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── icon
│ └── bili.png
└── screenshot
│ ├── v1.0.1
│ ├── main_page.png
│ ├── reply.png
│ ├── reply_reply.png
│ ├── search_page.png
│ ├── sms_login.png
│ ├── user_info.png
│ ├── video_fullscreen.png
│ ├── video_part.png
│ ├── video_play.png
│ └── video_search.png
│ └── v1.0.3
│ ├── about_page.png
│ ├── bangumi_play.png
│ ├── bangumi_search.png
│ ├── main_page.png
│ ├── reply.png
│ ├── reply_reply.png
│ ├── search_page.png
│ ├── user_info.png
│ ├── video_play.png
│ └── video_search.png
├── fastlane
└── metadata
│ └── android
│ ├── en-US
│ ├── full_description.txt
│ ├── images
│ │ └── phoneScreenshots
│ │ │ ├── about_page.png
│ │ │ ├── bangumi_play.png
│ │ │ ├── bangumi_search.png
│ │ │ ├── main_page.png
│ │ │ ├── reply.png
│ │ │ ├── reply_reply.png
│ │ │ ├── search_page.png
│ │ │ ├── user_info.png
│ │ │ ├── video_play.png
│ │ │ └── video_search.png
│ └── short_description.txt
│ └── zh-CN
│ ├── full_description.txt
│ └── short_description.txt
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
├── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-50x50@1x.png
│ │ │ ├── Icon-App-50x50@2x.png
│ │ │ ├── Icon-App-57x57@1x.png
│ │ │ ├── Icon-App-57x57@2x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-72x72@1x.png
│ │ │ ├── Icon-App-72x72@2x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
└── RunnerTests
│ └── RunnerTests.swift
├── lib
├── common
│ ├── api
│ │ ├── api_constants.dart
│ │ ├── bangumi_api.dart
│ │ ├── danmaku_api.dart
│ │ ├── dynamic_api.dart
│ │ ├── github_api.dart
│ │ ├── history_api.dart
│ │ ├── home_api.dart
│ │ ├── index.dart
│ │ ├── live_api.dart
│ │ ├── login_api.dart
│ │ ├── realtions_api.dart
│ │ ├── related_video_api.dart
│ │ ├── reply_api.dart
│ │ ├── reply_operation_api.dart
│ │ ├── search_api.dart
│ │ ├── user_space_api.dart
│ │ ├── video_info_api.dart
│ │ ├── video_operation_api.dart
│ │ ├── video_play_api.dart
│ │ └── wbi.dart
│ ├── index.dart
│ ├── models
│ │ ├── index.dart
│ │ ├── local
│ │ │ ├── bangumi
│ │ │ │ ├── bangumi_info.dart
│ │ │ │ └── episode_info.dart
│ │ │ ├── dynamic
│ │ │ │ ├── dynamic_author.dart
│ │ │ │ ├── dynamic_content.dart
│ │ │ │ ├── dynamic_item.dart
│ │ │ │ └── dynamic_stat.dart
│ │ │ ├── history
│ │ │ │ └── video_view_history_item.dart
│ │ │ ├── home
│ │ │ │ └── recommend_item_info.dart
│ │ │ ├── live
│ │ │ │ └── live_room_card_info.dart
│ │ │ ├── login
│ │ │ │ ├── level_info.dart
│ │ │ │ ├── login_qrcode_info.dart
│ │ │ │ ├── login_qrcode_stat.dart
│ │ │ │ ├── login_user_info.dart
│ │ │ │ └── login_user_stat.dart
│ │ │ ├── reply
│ │ │ │ ├── add_reply_result.dart
│ │ │ │ ├── official_verify.dart
│ │ │ │ ├── reply_add_like_result.dart
│ │ │ │ ├── reply_content.dart
│ │ │ │ ├── reply_info.dart
│ │ │ │ ├── reply_item.dart
│ │ │ │ ├── reply_member.dart
│ │ │ │ ├── reply_reply_info.dart
│ │ │ │ └── vip.dart
│ │ │ ├── search
│ │ │ │ ├── default_search_word.dart
│ │ │ │ ├── hot_word_item.dart
│ │ │ │ ├── search_bangumi_item.dart
│ │ │ │ ├── search_suggest_item.dart
│ │ │ │ ├── search_user_item.dart
│ │ │ │ └── search_video_item.dart
│ │ │ ├── user_space
│ │ │ │ └── user_video_search.dart
│ │ │ ├── video
│ │ │ │ ├── audio_play_item.dart
│ │ │ │ ├── click_add_coin_result.dart
│ │ │ │ ├── click_add_share_result.dart
│ │ │ │ ├── click_like_result.dart
│ │ │ │ ├── part_info.dart
│ │ │ │ ├── video_info.dart
│ │ │ │ ├── video_play_info.dart
│ │ │ │ └── video_play_item.dart
│ │ │ └── video_tile
│ │ │ │ └── video_tile_info.dart
│ │ └── network
│ │ │ ├── bangumi
│ │ │ └── bangumi_info.dart
│ │ │ ├── dynamic
│ │ │ └── dynamic.dart
│ │ │ ├── github
│ │ │ └── github_releases_item.dart
│ │ │ ├── history
│ │ │ └── report_history.dart
│ │ │ ├── home
│ │ │ └── recommend_video.dart
│ │ │ ├── login
│ │ │ ├── captcha_data.dart
│ │ │ ├── captcha_result.dart
│ │ │ ├── password_login_key_hash.dart
│ │ │ ├── password_login_result.dart
│ │ │ ├── post_sms_login.dart
│ │ │ └── post_sms_require.dart
│ │ │ ├── proto
│ │ │ └── danmaku
│ │ │ │ ├── danmaku.pb.dart
│ │ │ │ ├── danmaku.pbenum.dart
│ │ │ │ ├── danmaku.pbjson.dart
│ │ │ │ ├── danmaku.pbserver.dart
│ │ │ │ └── danmaku.proto
│ │ │ ├── related_video
│ │ │ └── related_video.dart
│ │ │ ├── reply
│ │ │ ├── reply.dart
│ │ │ └── reply_reply.dart
│ │ │ ├── search
│ │ │ ├── default_search_word.dart
│ │ │ ├── hot_words.dart
│ │ │ ├── search_bangumi.dart
│ │ │ ├── search_suggest.dart
│ │ │ └── search_video.dart
│ │ │ ├── user
│ │ │ ├── user_info.dart
│ │ │ └── user_stat.dart
│ │ │ ├── user_relations
│ │ │ ├── user_realtion.dart
│ │ │ └── user_relation_types.dart
│ │ │ ├── user_space
│ │ │ └── user_video_search.dart
│ │ │ ├── video_info
│ │ │ ├── video_info.dart
│ │ │ └── video_parts.dart
│ │ │ └── video_play
│ │ │ └── video_play.dart
│ ├── utils
│ │ ├── bili_you_storage.dart
│ │ ├── bvid_avid_util.dart
│ │ ├── cache_util.dart
│ │ ├── cookie_util.dart
│ │ ├── fullscreen.dart
│ │ ├── http_utils.dart
│ │ ├── index.dart
│ │ ├── settings.dart
│ │ ├── show_dialog.dart
│ │ └── string_format_utils.dart
│ ├── values
│ │ ├── coutry_id.dart
│ │ ├── hero_tag_id.dart
│ │ └── index.dart
│ └── widget
│ │ ├── avatar.dart
│ │ ├── bangumi_tile_item.dart
│ │ ├── bili_url_scheme.dart
│ │ ├── cached_network_image.dart
│ │ ├── foldable_text.dart
│ │ ├── icon_text_button.dart
│ │ ├── index.dart
│ │ ├── live_room_card.dart
│ │ ├── radio_list_dialog.dart
│ │ ├── settings_label.dart
│ │ ├── settings_radios_tile.dart
│ │ ├── settings_slider_tile.dart
│ │ ├── settings_switch_tile.dart
│ │ ├── simple_easy_refresher.dart
│ │ ├── slider_dialog.dart
│ │ ├── tag.dart
│ │ ├── user_tile_item.dart
│ │ ├── video_audio_player.dart
│ │ ├── video_tile_item.dart
│ │ └── video_view_history_tile.dart
├── index.dart
├── main.dart
└── pages
│ ├── about
│ ├── about_page.dart
│ └── index.dart
│ ├── bili_live
│ ├── controller.dart
│ └── view.dart
│ ├── bili_video
│ ├── controller.dart
│ ├── index.dart
│ ├── view.dart
│ └── widgets
│ │ ├── bili_video_player
│ │ ├── bili_danmaku.dart
│ │ ├── bili_video_player.dart
│ │ └── bili_video_player_panel.dart
│ │ ├── introduction
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ └── view.dart
│ │ └── reply
│ │ ├── add_reply_util.dart
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ ├── view.dart
│ │ └── widgets
│ │ ├── reply_item.dart
│ │ └── reply_reply_page.dart
│ ├── bili_video1
│ ├── bili_media_content.dart
│ ├── bili_media_content_cubit.dart
│ ├── bili_media_cubit.dart
│ ├── bili_video_page.dart
│ └── bili_video_player.dart
│ ├── dynamic
│ ├── controller.dart
│ ├── index.dart
│ ├── view.dart
│ └── widget
│ │ ├── dynamic_article.dart
│ │ ├── dynamic_author_filter.dart
│ │ ├── dynamic_draw.dart
│ │ ├── dynamic_item_card.dart
│ │ └── dynamic_video_card.dart
│ ├── history
│ ├── history_controller.dart
│ └── history_page.dart
│ ├── home
│ ├── controller.dart
│ ├── index.dart
│ ├── view.dart
│ └── widgets
│ │ └── user_menu
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ └── view.dart
│ ├── live_tab_page
│ ├── controller.dart
│ └── view.dart
│ ├── login
│ ├── controller.dart
│ ├── password_login
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ └── view.dart
│ ├── qrcode_login
│ │ ├── controller.dart
│ │ └── view.dart
│ ├── sms_login
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ ├── view.dart
│ │ └── widgets
│ │ │ └── error
│ │ │ ├── controller.dart
│ │ │ ├── index.dart
│ │ │ └── view.dart
│ └── web_login
│ │ └── view.dart
│ ├── main
│ ├── controller.dart
│ ├── index.dart
│ └── view.dart
│ ├── popular_video
│ ├── controller.dart
│ └── view.dart
│ ├── recommend
│ ├── controller.dart
│ ├── index.dart
│ ├── view.dart
│ └── widgets
│ │ └── recommend_card.dart
│ ├── relation
│ ├── controller.dart
│ ├── index.dart
│ └── view.dart
│ ├── search_input
│ ├── controller.dart
│ ├── index.dart
│ └── view.dart
│ ├── search_result
│ ├── controller.dart
│ ├── index.dart
│ └── view.dart
│ ├── search_tab_view
│ ├── controller.dart
│ └── view.dart
│ ├── settings_page
│ ├── appearance_settings_page.dart
│ ├── cache_management_page.dart
│ ├── common_settings_page.dart
│ ├── others_settings_page.dart
│ └── settings_page.dart
│ ├── splash
│ ├── controller.dart
│ ├── index.dart
│ └── view.dart
│ ├── ui_test
│ ├── controller.dart
│ ├── index.dart
│ ├── test_widget
│ │ └── media_kit_test_page.dart
│ └── view.dart
│ ├── user_space
│ ├── controller.dart
│ └── view.dart
│ └── webview
│ └── browser.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
├── -configuration
├── .gitignore
├── .xcodeproj
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── app_icon_1024.png
│ │ │ ├── app_icon_128.png
│ │ │ ├── app_icon_16.png
│ │ │ ├── app_icon_256.png
│ │ │ ├── app_icon_32.png
│ │ │ ├── app_icon_512.png
│ │ │ └── app_icon_64.png
│ ├── Base.lproj
│ │ └── MainMenu.xib
│ ├── Configs
│ │ ├── AppInfo.xcconfig
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── Warnings.xcconfig
│ ├── DebugProfile.entitlements
│ ├── Info.plist
│ ├── MainFlutterWindow.swift
│ └── Release.entitlements
└── RunnerTests
│ └── RunnerTests.swift
├── pubspec.lock
├── pubspec.yaml
├── scripts
├── bili_you.AppDir
│ ├── AppRun
│ └── bili_you.desktop
├── build.sh
├── build_linux_appimage.sh
└── run_flutter_laucher_icons.sh
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── index.html
└── manifest.json
└── windows
├── .gitignore
├── CMakeLists.txt
├── flutter
├── CMakeLists.txt
├── generated_plugin_registrant.cc
├── generated_plugin_registrant.h
└── generated_plugins.cmake
└── runner
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── resources
└── app_icon.ico
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
/.github/ISSUE_TEMPLATE/bug_report.yaml:
--------------------------------------------------------------------------------
1 | name: "Bug report"
2 | description: 创建问题报告以帮助 bili_you 更好
3 | labels:
4 | - bug
5 | assignees: lucinhu
6 | body:
7 | - type: textarea
8 | attributes:
9 | label: Bug 描述
10 | description: 简洁而有力的描述 Bug
11 | validations:
12 | required: true
13 | - type: textarea
14 | attributes:
15 | label: 复现步骤
16 | description: 如何复现你描述的 Bug ?
17 | validations:
18 | required: true
19 | - type: textarea
20 | attributes:
21 | label: 预期行为
22 | description: 若无 Bug 你认为 bili_you 改如何工作
23 | - type: textarea
24 | attributes:
25 | label: 屏幕捕获
26 | description: 如果可用,添加一些截图帮助排查问题
27 | - type: textarea
28 | attributes:
29 | label: 版本信息
30 | description: 填写一些版本信息
31 | value: |
32 | 1. Android 版本:
33 | 2. Webview 版本:
34 | 3. 设备型号:
35 | 4. bili_you 版本号:
36 | validations:
37 | required: true
38 | - type: textarea
39 | attributes:
40 | label: 补充说明
41 | description: 如果有任何补充,填写此字段
42 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yaml:
--------------------------------------------------------------------------------
1 | name: "Feature request"
2 | description: 关于新功能的建议
3 | labels:
4 | - enhancement
5 | assignees: lucinhu
6 | body:
7 | - type: textarea
8 | attributes:
9 | label: 预期行为
10 | description: 你提出的功能会解决预期中的什么问题
11 | validations:
12 | required: true
13 | - type: textarea
14 | attributes:
15 | label: 功能描述
16 | description: 简洁而有力的描述你想象中的新功能
17 | validations:
18 | required: true
19 | - type: textarea
20 | attributes:
21 | label: 补充说明
22 | description: 如果有任何补充,填写此字段
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | .vscode/
23 | .json/
24 |
25 | # Flutter/Dart/Pub related
26 | **/doc/api/
27 | **/ios/Flutter/.last_build_id
28 | .dart_tool/
29 | .flutter-plugins
30 | .flutter-plugins-dependencies
31 | .packages
32 | .pub-cache/
33 | .pub/
34 | /build/
35 |
36 | # Symbolication related
37 | app.*.symbols
38 |
39 | # Obfuscation related
40 | app.*.map.json
41 |
42 | # Android Studio will place build artifacts here
43 | /android/app/debug
44 | /android/app/profile
45 | /android/app/release
46 |
--------------------------------------------------------------------------------
/.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: 835b892d7fbe808be92d5eeee7b31c7bb7a3b1eb
8 | channel: master
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 835b892d7fbe808be92d5eeee7b31c7bb7a3b1eb
17 | base_revision: 835b892d7fbe808be92d5eeee7b31c7bb7a3b1eb
18 | - platform: macos
19 | create_revision: 835b892d7fbe808be92d5eeee7b31c7bb7a3b1eb
20 | base_revision: 835b892d7fbe808be92d5eeee7b31c7bb7a3b1eb
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bili You
2 |
3 |
4 |

5 |
6 | 
7 | [](https://github.com/lucinhu/bili_you/releases)
8 | [](https://github.com/lucinhu/bili_you/releases)
9 | 
10 |
11 |
12 |
13 | 一个用flutter制作的第三方B站客户端.
14 |
15 | ## 功能实现
16 |
17 | - [x] 主页视频推荐
18 | - [x] 视频搜索
19 | - [x] 评论区
20 | - [x] 评论区楼中楼
21 | - [x] 评论图片及笔记
22 | - [x] 相关视频
23 | - [x] 热搜
24 | - [x] 视频播放
25 | - [x] 弹幕
26 | - [ ] 直播
27 | - [x] 动态(未完善)
28 | - [x] 用户投稿
29 | - [x] 番剧搜索
30 | - [x] 番剧播放
31 |
32 | ## 截图
33 |
34 |
35 |

36 |

37 |

38 |

39 |

40 |

41 |

42 |

43 |

44 |

45 |
46 |
47 | ## 交流
48 |
49 | Discord:[https://discord.gg/tsFh7Hdb4s](https://discord.gg/tsFh7Hdb4s)
50 |
51 | ## 声明
52 |
53 | - 此项目是个人为了兴趣而开发, 仅供学习交流使用, 无任何商业用途.
54 | - 资源版权仍归原网站或其作者所有.
55 | - 所用API皆从官方网站收集, 不含任何非法及破解内容.
56 |
57 | ## 感谢
58 |
59 | - [bilibili-API-collect](https://github.com/SocialSisterYi/bilibili-API-collect): 哔哩哔哩API收集,感谢@SocialSisterYi及各位贡献者的维护!
60 | - [flutter_ns_danmaku](https://github.com/xiaoyaocz/flutter_ns_danmaku): @xiaoyaocz大佬制作的flutter弹幕插件,非常感谢!
61 | - [media_kit](https://github.com/alexmercerind/media_kit): 感谢@alexmercerind大佬制作的media_kit播放器!
62 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 | **/keystore.properties
15 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/lucinhu/bili_you/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.lucinhu.bili_you
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi-v26/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-hdpi-v26/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi-v26/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-mdpi-v26/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi-v26/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-xhdpi-v26/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi-v26/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-xxhdpi-v26/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi-v26/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-xxxhdpi-v26/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffffff
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.7.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.2.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | tasks.register("clean", Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/assets/icon/bili.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/icon/bili.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/main_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/main_page.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/reply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/reply.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/reply_reply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/reply_reply.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/search_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/search_page.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/sms_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/sms_login.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/user_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/user_info.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/video_fullscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/video_fullscreen.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/video_part.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/video_part.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/video_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/video_play.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.1/video_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.1/video_search.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/about_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/about_page.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/bangumi_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/bangumi_play.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/bangumi_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/bangumi_search.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/main_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/main_page.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/reply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/reply.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/reply_reply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/reply_reply.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/search_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/search_page.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/user_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/user_info.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/video_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/video_play.png
--------------------------------------------------------------------------------
/assets/screenshot/v1.0.3/video_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/assets/screenshot/v1.0.3/video_search.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | Features
2 |
3 |
4 | - View recommanded videos
5 | - Search videos
6 | - View comments
7 | - View nested comments
8 | - View pictures and notes in comments
9 | - View related videos
10 | - View top topics
11 | - Play videos
12 | - Display danmaku
13 | - View user artworks
14 | - Search bangumi
15 | - Play bangumi
16 |
17 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/about_page.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/about_page.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/bangumi_play.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/bangumi_play.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/bangumi_search.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/bangumi_search.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/main_page.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/main_page.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/reply.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/reply.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/reply_reply.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/reply_reply.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/search_page.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/search_page.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/user_info.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/user_info.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/video_play.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/video_play.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/video_search.png:
--------------------------------------------------------------------------------
1 | ../../../../../../assets/screenshot/v1.0.3/video_search.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | A third-party Bilibili client
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/full_description.txt:
--------------------------------------------------------------------------------
1 | 功能
2 |
3 |
4 | - 主页视频推荐
5 | - 视频搜索
6 | - 评论区
7 | - 评论区楼中楼
8 | - 评论图片及笔记
9 | - 相关视频
10 | - 热搜
11 | - 视频播放
12 | - 弹幕
13 | - 用户投稿
14 | - 番剧搜索
15 | - 番剧播放
16 |
17 |
18 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/short_description.txt:
--------------------------------------------------------------------------------
1 | 第三方 Bilibili 客户端
2 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.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/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | platform :ios, '13.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | target 'RunnerTests' do
36 | inherit! :search_paths
37 | end
38 | end
39 |
40 | post_install do |installer|
41 | installer.pods_project.targets.each do |target|
42 | flutter_additional_ios_build_settings(target)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/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/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/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/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 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/ios/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/lib/common/api/bangumi_api.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/api_constants.dart';
2 | import 'package:bili_you/common/models/local/bangumi/bangumi_info.dart';
3 | import 'package:bili_you/common/models/local/bangumi/episode_info.dart';
4 | import 'package:bili_you/common/models/network/bangumi/bangumi_info.dart';
5 | import 'package:bili_you/common/utils/http_utils.dart';
6 |
7 | class BangumiApi {
8 | //ssid(seaseon_id)或者epid都可以
9 | static Future _requestBangumiInfo(
10 | {int? ssid, int? epid}) async {
11 | var response = await HttpUtils().get(
12 | ApiConstants.bangumiInfo,
13 | queryParameters: {"season_id": ssid, "ep_id": epid},
14 | );
15 | return BangumiInfoResponse.fromJson(response.data);
16 | }
17 |
18 | //获取番剧信息
19 | static Future getBangumiInfo({int? ssid, int? epid}) async {
20 | if (ssid == null && epid == null) {
21 | throw "getBangumiInfo: ssid和epid不能同时为空";
22 | }
23 | var response = await _requestBangumiInfo(ssid: ssid, epid: epid);
24 | if (response.code != 0) {
25 | throw "getBangumiInfo: code:${response.code}, message:${response.message}";
26 | }
27 | List episodes = [];
28 | for (var i in response.result?.episodes ?? []) {
29 | episodes.add(EpisodeInfo(
30 | title: i.longTitle ?? "", bvid: i.bvid ?? "", cid: i.cid ?? 0));
31 | }
32 | return BangumiInfo(
33 | title: response.result?.title ?? "",
34 | ssid: response.result?.seasonId ?? 0,
35 | episodes: episodes);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/common/api/danmaku_api.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/api_constants.dart';
2 | import 'package:bili_you/common/models/network/proto/danmaku/danmaku.pb.dart';
3 | import 'package:bili_you/common/utils/http_utils.dart';
4 | import 'package:dio/dio.dart';
5 | import 'package:flutter/foundation.dart';
6 |
7 | class DanmakuApi {
8 | static Future requestDanmaku(
9 | {int type = 1, required int cid, required int segmentIndex}) async {
10 | var ret = await compute((Map params) async {
11 | var response = await HttpUtils().get(ApiConstants.danmaku,
12 | queryParameters: params,
13 | options: Options(responseType: ResponseType.bytes));
14 | return DmSegMobileReply.fromBuffer(response.data);
15 | }, {'type': type, 'oid': cid, 'segment_index': segmentIndex});
16 | return ret;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/common/api/github_api.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:bili_you/common/utils/http_utils.dart';
4 | import 'package:dio/dio.dart';
5 |
6 | import '../models/network/github/github_releases_item.dart';
7 | import 'api_constants.dart';
8 |
9 | class GithubApi {
10 | static Future requestLatestRelease() async {
11 | var response = await HttpUtils().get(ApiConstants.githubLatestRelease,
12 | options: Options(headers: {
13 | "Authorization": base64
14 | .decode(
15 | "dG9rZW4gZ2hwX05ia0huNm9aRlRJN0ZyTzFPb1R4MkF3U21oTFN0OTBhN1lQVQ==")
16 | .toString()
17 | }));
18 | return GithubReleasesItemModel.fromJson(response.data);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/common/api/history_api.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/index.dart';
2 | import 'package:bili_you/common/models/local/history/video_view_history_item.dart';
3 | import 'package:bili_you/common/models/network/history/report_history.dart';
4 | import 'package:bili_you/common/utils/http_utils.dart';
5 |
6 | import '../utils/cookie_util.dart';
7 |
8 | class HistoryApi {
9 | ///max是上一个历史记录的id,或者是oid
10 | ///viewAt是上一条记录的最后观看时间
11 | ///可以两者都设,也可任意设置一个
12 | static Future> getVideoViewHistory(
13 | {int? max, int? viewAt}) async {
14 | var response =
15 | await HttpUtils().get(ApiConstants.viewHistory, queryParameters: {
16 | 'type': 'archive',
17 | 'business': 'archive',
18 | 'ps': 20,
19 | if (max != null) 'max': max,
20 | if (viewAt != null) 'view_at': viewAt
21 | });
22 | if (response.data['code'] != 0) {
23 | throw 'getVideoViewHistory:code:${response.data['code']},message:${response.data['message']}';
24 | }
25 | List list = [];
26 | for (Map i in response.data['data']['list']) {
27 | list.add(VideoViewHistoryItem(
28 | oid: i['history']['oid'],
29 | title: i['title'],
30 | cover: i['cover'],
31 | bvid: i['history']['bvid'],
32 | cid: i['history']['cid'],
33 | epid: i['history']['epid'],
34 | page: i['history']['page'],
35 | authorName: i['author_name'],
36 | viewAt: i['view_at'],
37 | progress: i['progress'],
38 | duration: i['duration'],
39 | isFinished: i['is_finish'] != 0 || i['progress'] < 0));
40 | }
41 | return list;
42 | }
43 |
44 | /// 汇报历史记录
45 | static Future reportVideoViewHistory(
46 | {required int aid, required int cid, int? progress}) async {
47 | var response =
48 | await HttpUtils().post(ApiConstants.reportHistory, queryParameters: {
49 | "aid": aid,
50 | "cid": cid,
51 | "progress": progress ?? 0,
52 | "platform": "android",
53 | "csrf": await CookieUtils.getCsrf()
54 | });
55 | var json = ReportHistory.fromJson(response.data);
56 | if (json.code != 0) {
57 | throw 'report_history:code:${json.code},raw:"${response.data}"';
58 | }
59 | return true;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/common/api/index.dart:
--------------------------------------------------------------------------------
1 | export 'api_constants.dart';
2 | export 'bangumi_api.dart';
3 | export 'danmaku_api.dart';
4 | export 'github_api.dart';
5 | export 'home_api.dart';
6 | export 'login_api.dart';
7 | export 'related_video_api.dart';
8 | export 'search_api.dart';
9 | export 'user_space_api.dart';
10 | export 'video_info_api.dart';
11 | export 'video_play_api.dart';
12 | export 'reply_api.dart';
13 |
--------------------------------------------------------------------------------
/lib/common/api/live_api.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/index.dart';
2 | import 'package:bili_you/common/models/local/live/live_room_card_info.dart';
3 | import 'package:bili_you/common/utils/http_utils.dart';
4 |
5 | class LiveApi {
6 | static Future> getUserRecommendLive(
7 | {required int pageNum, required int pageSize}) async {
8 | var response = await HttpUtils().get(ApiConstants.userRecommendLive,
9 | queryParameters: {
10 | 'page': pageNum,
11 | 'page_size': pageSize,
12 | 'platform': 'web'
13 | });
14 | if (response.data['code'] != 0) {
15 | throw "getUserRecommendLive: code:${response.data['code']}, message:${response.data['message']}";
16 | }
17 |
18 | return [
19 | for (Map i in response.data['data']['list'])
20 | LiveRoomCardInfo(
21 | roomId: i['roomid'] ?? 0,
22 | uid: i['uid'] ?? 0,
23 | title: i['title'] ?? '',
24 | uname: i['uname'] ?? '',
25 | cover: i['cover'] ?? '',
26 | userFace: i['face'] ?? '',
27 | parentId: i['parent_id'] ?? 0,
28 | parentName: i['parent_name'] ?? '',
29 | areaId: i['area_id'] ?? 0,
30 | areaName: i['area_name'] ?? '',
31 | watchNum: i['watched_show']?['num'] ?? 0)
32 | ];
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/common/api/realtions_api.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/api_constants.dart';
2 | import 'package:bili_you/common/models/network/user_relations/user_realtion.dart';
3 | import 'package:bili_you/common/utils/http_utils.dart';
4 |
5 | class RelationApi {
6 | static Future> getFollowingList(
7 | {required int? vmid,
8 | String? orderType,
9 | required int pn,
10 | required int ps}) async {
11 | return await _request(
12 | apiurl: ApiConstants.followings, vmid: vmid, pn: pn, ps: ps);
13 | }
14 |
15 | static Future> getFollowersList(
16 | {required int? vmid,
17 | String? orderType,
18 | required int pn,
19 | required int ps}) async {
20 | return await _request(
21 | apiurl: ApiConstants.followers,
22 | orderType: orderType,
23 | vmid: vmid,
24 | pn: pn,
25 | ps: ps);
26 | }
27 |
28 | static Future> _request(
29 | {required String apiurl,
30 | required int? vmid,
31 | String? orderType,
32 | required int pn,
33 | required int ps}) async {
34 | var response0 = await HttpUtils().get(
35 | apiurl,
36 | queryParameters: {
37 | "vmid": vmid,
38 | "order_type": orderType,
39 | "pn": pn,
40 | "ps": ps
41 | },
42 | );
43 | var response = response0.data;
44 |
45 | if (response["code"] != 0) {
46 | throw "getRelationList: code:${response["code"]}, message:${response["message"]}";
47 | }
48 |
49 | List relations = [];
50 | for (var rel in response["data"]["list"]) {
51 | relations.add(UserRelation.fromJson(rel));
52 | }
53 | return relations;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/common/api/related_video_api.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/api_constants.dart';
2 | import 'package:bili_you/common/models/local/video_tile/video_tile_info.dart';
3 | import 'package:bili_you/common/models/network/related_video/related_video.dart';
4 | import 'package:bili_you/common/utils/http_utils.dart';
5 |
6 | class RelatedVideoApi {
7 | static Future _requestRelatedVideo(
8 | {required String bvid}) async {
9 | var response = await HttpUtils().get(
10 | ApiConstants.relatedVideo,
11 | queryParameters: {'bvid': bvid},
12 | );
13 | return RelatedVideoResponse.fromJson(response.data);
14 | }
15 |
16 | ///获取相关视频
17 | static Future> getRelatedVideo(
18 | {required String bvid}) async {
19 | List list = [];
20 | var response = await _requestRelatedVideo(bvid: bvid);
21 | if (response.code != 0) {
22 | throw "getRelatedVideo: code:${response.code}, message:${response.message}";
23 | }
24 | if (response.data == null) {
25 | return list;
26 | }
27 | for (var i in response.data!) {
28 | list.add(VideoTileInfo(
29 | coverUrl: i.pic ?? "",
30 | bvid: i.bvid ?? "",
31 | cid: i.cid ?? 0,
32 | title: i.title ?? "",
33 | upName: i.owner?.name ?? "",
34 | timeLength: i.duration ?? 0,
35 | playNum: i.stat?.view ?? 0,
36 | pubDate: i.pubdate ?? 0));
37 | }
38 | return list;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/common/api/user_space_api.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/api_constants.dart';
2 | import 'package:bili_you/common/api/wbi.dart';
3 | import 'package:bili_you/common/models/local/user_space/user_video_search.dart';
4 | import 'package:bili_you/common/models/network/user_space/user_video_search.dart';
5 | import 'package:bili_you/common/utils/http_utils.dart';
6 |
7 | class UserSpaceApi {
8 | static Future _requestUserVideoSearch({
9 | required int mid,
10 | required int pageNum,
11 | String? keyword,
12 | }) async {
13 | //TODO order排序方式,tid分区筛选,keyword关键词筛选,ps每页项数,
14 | var response = await HttpUtils().get(ApiConstants.userVideoSearch,
15 | queryParameters: await WbiSign.encodeParams({
16 | "mid": mid,
17 | "pn": pageNum,
18 | "ps": 30,
19 | "keyword": keyword ?? "",
20 | "order": "pubdate",
21 | "tid": 0,
22 | "platform": "web",
23 | }));
24 | return UserVideoSearchResponse.fromJson(response.data);
25 | }
26 |
27 | static Future getUserVideoSearch({
28 | required int mid,
29 | required int pageNum,
30 | String? keyword,
31 | }) async {
32 | var response = await _requestUserVideoSearch(
33 | mid: mid, pageNum: pageNum, keyword: keyword);
34 | if (response.code != 0) {
35 | throw "getUserVideoSearch: code:${response.code}, message:${response.message}";
36 | }
37 |
38 | if (response.data == null ||
39 | response.data?.list == null ||
40 | response.data?.list?.vlist == null) {
41 | return UserVideoSearch.zero;
42 | }
43 | List videos = [];
44 | for (var i in response.data!.list!.vlist!) {
45 | videos.add(UserVideoItem(
46 | author: i.author ?? "",
47 | title: i.title ?? "",
48 | mid: i.mid ?? 0,
49 | bvid: i.bvid ?? "",
50 | coverUrl: i.pic ?? "",
51 | danmakuCount: i.videoReview ?? 0,
52 | description: i.description ?? "",
53 | isUnionVideo: i.isUnionVideo == 1,
54 | playCount: i.play ?? 0,
55 | duration: i.length ?? "--:--",
56 | pubDate: i.created ?? 0,
57 | replyCount: i.comment ?? 0));
58 | }
59 | return UserVideoSearch(videos: videos);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/common/index.dart:
--------------------------------------------------------------------------------
1 | export 'api/index.dart';
2 | export 'models/index.dart';
3 | export 'utils/index.dart';
4 | export 'values/index.dart';
5 | export 'widget/index.dart';
6 |
7 |
--------------------------------------------------------------------------------
/lib/common/models/index.dart:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/common/models/local/bangumi/bangumi_info.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/bangumi/episode_info.dart';
2 |
3 | class BangumiInfo {
4 | BangumiInfo(
5 | {required this.title, required this.ssid, required this.episodes});
6 | static BangumiInfo get zero => BangumiInfo(title: "", ssid: 0, episodes: []);
7 | String title;
8 | int ssid;
9 | List episodes;
10 | }
11 |
--------------------------------------------------------------------------------
/lib/common/models/local/bangumi/episode_info.dart:
--------------------------------------------------------------------------------
1 | class EpisodeInfo {
2 | EpisodeInfo({required this.title, required this.bvid, required this.cid});
3 | static EpisodeInfo get zero => EpisodeInfo(title: "", bvid: "", cid: 0);
4 | String title;
5 | String bvid;
6 | int cid;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/common/models/local/dynamic/dynamic_author.dart:
--------------------------------------------------------------------------------
1 | import '../reply/official_verify.dart';
2 | import '../reply/vip.dart';
3 |
4 | class DynamicAuthor {
5 | DynamicAuthor(
6 | {required this.mid,
7 | required this.name,
8 | required this.avatarUrl,
9 | required this.officialVerify,
10 | required this.vip,
11 | required this.pubTime,
12 | required this.pubAction,
13 | this.hasUpdate = false});
14 | static DynamicAuthor get zero => DynamicAuthor(
15 | mid: 0,
16 | name: "",
17 | avatarUrl: "",
18 | officialVerify: OfficialVerify.zero,
19 | vip: Vip.zero,
20 | pubTime: "",
21 | pubAction: "");
22 | int mid;
23 | String name;
24 | String avatarUrl;
25 | OfficialVerify officialVerify;
26 | Vip vip;
27 | String pubTime;
28 | String pubAction;
29 | bool hasUpdate;
30 | }
31 |
--------------------------------------------------------------------------------
/lib/common/models/local/dynamic/dynamic_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/reply/reply_item.dart';
2 |
3 | import 'dynamic_author.dart';
4 | import 'dynamic_content.dart';
5 | import 'dynamic_stat.dart';
6 |
7 | class DynamicItem {
8 | DynamicItem(
9 | {required this.replyId,
10 | required this.replyType,
11 | required this.author,
12 | required this.type,
13 | required this.content,
14 | required this.stat});
15 | static DynamicItem get zero => DynamicItem(
16 | replyId: '',
17 | replyType: ReplyType.unkown,
18 | author: DynamicAuthor.zero,
19 | type: DynamicItemType.unkown,
20 | content: WordDynamicContent.zero,
21 | stat: DynamicStat.zero);
22 |
23 | ///评论区id
24 | String replyId;
25 | ReplyType replyType;
26 | DynamicAuthor author;
27 | DynamicItemType type;
28 | DynamicContent content;
29 | DynamicStat stat;
30 | }
31 |
32 | enum DynamicItemType {
33 | //未知
34 | unkown,
35 |
36 | ///消息
37 | //DYNAMIC_TYPE_WORD
38 | word,
39 |
40 | ///文章
41 | //DYNAMIC_TYPE_ARTICLE
42 | article,
43 |
44 | ///视频投稿
45 | //DYNAMIC_TYPE_AV
46 | av,
47 |
48 | ///抽签or互动?
49 | //DYNAMIC_TYPE_DRAW
50 | draw,
51 |
52 | ///直播推荐
53 | //DYNAMIC_TYPE_LIVE_RCMD
54 | liveRecommend,
55 |
56 | ///转发动态
57 | //DYNAMIC_TYPE_FORWARD
58 | forward,
59 | }
60 |
61 | extension DynamicItemTypeCode on DynamicItemType {
62 | static const List _codeList = [
63 | "UNKOWN",
64 | "DYNAMIC_TYPE_WORD",
65 | "DYNAMIC_TYPE_ARTICLE",
66 | "DYNAMIC_TYPE_AV",
67 | "DYNAMIC_TYPE_DRAW",
68 | "DYNAMIC_TYPE_LIVE_RCMD",
69 | "DYNAMIC_TYPE_FORWARD",
70 | ];
71 | static DynamicItemType fromCode(String code) {
72 | int index = _codeList.indexOf(code);
73 | if (index == -1) {
74 | return DynamicItemType.unkown;
75 | }
76 | return DynamicItemType.values[index];
77 | }
78 |
79 | String get code => _codeList[index];
80 | }
81 |
--------------------------------------------------------------------------------
/lib/common/models/local/dynamic/dynamic_stat.dart:
--------------------------------------------------------------------------------
1 | class DynamicStat {
2 | DynamicStat(
3 | {required this.shareCount,
4 | required this.replyCount,
5 | required this.likeCount});
6 | static DynamicStat get zero =>
7 | DynamicStat(shareCount: 0, replyCount: 0, likeCount: 0);
8 | int shareCount;
9 | int replyCount;
10 | int likeCount;
11 | }
12 |
--------------------------------------------------------------------------------
/lib/common/models/local/history/video_view_history_item.dart:
--------------------------------------------------------------------------------
1 | class VideoViewHistoryItem {
2 | VideoViewHistoryItem(
3 | {required this.oid,
4 | required this.title,
5 | required this.cover,
6 | required this.bvid,
7 | required this.cid,
8 | required this.epid,
9 | required this.page,
10 | required this.authorName,
11 | required this.viewAt,
12 | required this.progress,
13 | required this.duration,
14 | required this.isFinished});
15 | static VideoViewHistoryItem get zero => VideoViewHistoryItem(
16 | oid: 0,
17 | title: '',
18 | cover: '',
19 | bvid: '',
20 | cid: 0,
21 | epid: 0,
22 | page: 1,
23 | authorName: '',
24 | viewAt: 0,
25 | progress: 0,
26 | duration: 0,
27 | isFinished: false);
28 | int oid;
29 | String title;
30 | String cover;
31 | String bvid;
32 | int cid;
33 | int epid;
34 | int page;
35 | String authorName;
36 | int viewAt;
37 | int progress;
38 | int duration;
39 | bool isFinished;
40 | }
41 |
--------------------------------------------------------------------------------
/lib/common/models/local/home/recommend_item_info.dart:
--------------------------------------------------------------------------------
1 | class RecommendVideoItemInfo {
2 | RecommendVideoItemInfo(
3 | {required this.coverUrl,
4 | required this.danmakuNum,
5 | required this.playNum,
6 | required this.timeLength,
7 | required this.title,
8 | required this.upName,
9 | required this.bvid,
10 | required this.cid});
11 | static RecommendVideoItemInfo get zero => RecommendVideoItemInfo(
12 | coverUrl: "",
13 | danmakuNum: 0,
14 | playNum: 0,
15 | timeLength: 0,
16 | title: "",
17 | upName: "",
18 | bvid: "",
19 | cid: 0);
20 | String coverUrl;
21 | int danmakuNum;
22 | int playNum;
23 | int timeLength;
24 | String title;
25 | String upName;
26 | String bvid;
27 | int cid;
28 | }
29 |
--------------------------------------------------------------------------------
/lib/common/models/local/live/live_room_card_info.dart:
--------------------------------------------------------------------------------
1 | class LiveRoomCardInfo {
2 | LiveRoomCardInfo(
3 | {required this.roomId,
4 | required this.uid,
5 | required this.title,
6 | required this.uname,
7 | required this.cover,
8 | required this.userFace,
9 | required this.parentId,
10 | required this.parentName,
11 | required this.areaId,
12 | required this.areaName,
13 | required this.watchNum});
14 | int roomId;
15 | int uid;
16 | String title;
17 | String uname;
18 | String cover;
19 | String userFace;
20 | int parentId;
21 | String parentName;
22 | int areaId;
23 | String areaName;
24 | int watchNum;
25 | }
26 |
--------------------------------------------------------------------------------
/lib/common/models/local/login/level_info.dart:
--------------------------------------------------------------------------------
1 | class LevelInfo {
2 | LevelInfo(
3 | {required this.currentLevel,
4 | required this.currentExp,
5 | required this.currentMin,
6 | required this.nextExp});
7 | static LevelInfo get zero =>
8 | LevelInfo(currentLevel: 0, currentExp: 0, currentMin: 0, nextExp: 0);
9 |
10 | ///当前等级
11 | int currentLevel;
12 |
13 | ///升到当前等级所需要的全部经验值
14 | int currentMin;
15 |
16 | ///当前经验值
17 | int currentExp;
18 |
19 | ///升到下一级所需要的全部经验值
20 | int nextExp;
21 | }
22 |
--------------------------------------------------------------------------------
/lib/common/models/local/login/login_qrcode_info.dart:
--------------------------------------------------------------------------------
1 | class LoginQRcodeInfo {
2 | ///以该url作为内容生成二维码
3 | String url = '';
4 |
5 | ///用来作为检查扫码登陆状态的函数参数
6 | String qrcodeKey = '';
7 | }
8 |
--------------------------------------------------------------------------------
/lib/common/models/local/login/login_qrcode_stat.dart:
--------------------------------------------------------------------------------
1 | enum LoginQrcodeStat {
2 | ///登录成功
3 | loginSuccess,
4 |
5 | ///未扫码
6 | hasNotScan,
7 |
8 | ///扫码了但没确认
9 | hasNotAccept,
10 |
11 | ///二维码失效
12 | qrcodeInvalid,
13 |
14 | ///其他状态
15 | other,
16 | }
17 |
18 | extension LoginQrcodeStatExtension on LoginQrcodeStat {
19 | static const map = {
20 | 0: '登录成功',
21 | 86101: '未扫码',
22 | 86090: '已扫码但未确认',
23 | 86038: "二维码已失效",
24 | -1: "登录失败"
25 | };
26 | int get code => map.keys.toList()[index];
27 | String get message => map.values.toList()[index];
28 | static LoginQrcodeStat fromCode(int code) {
29 | var index = map.keys.toList().indexOf(code);
30 | if (index == -1) {
31 | //找不到对应的就返回 其他状态
32 | return LoginQrcodeStat.other;
33 | } else {
34 | return LoginQrcodeStat.values[index];
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/common/models/local/login/login_user_info.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/reply/official_verify.dart';
2 | import 'package:bili_you/common/models/local/reply/vip.dart';
3 |
4 | import 'level_info.dart';
5 |
6 | ///TODO 修改支持Hive
7 | class LoginUserInfo {
8 | LoginUserInfo(
9 | {required this.mid,
10 | required this.name,
11 | required this.avatarUrl,
12 | required this.levelInfo,
13 | required this.officialVerify,
14 | required this.vip,
15 | required this.isLogin});
16 | static LoginUserInfo get zero => LoginUserInfo(
17 | mid: 0,
18 | name: "",
19 | avatarUrl: "",
20 | levelInfo: LevelInfo.zero,
21 | officialVerify: OfficialVerify.zero,
22 | vip: Vip.zero,
23 | isLogin: false);
24 | int mid;
25 | String name;
26 | String avatarUrl;
27 | LevelInfo levelInfo;
28 | OfficialVerify officialVerify;
29 | Vip vip;
30 | bool isLogin;
31 | }
32 |
--------------------------------------------------------------------------------
/lib/common/models/local/login/login_user_stat.dart:
--------------------------------------------------------------------------------
1 | class LoginUserStat {
2 | LoginUserStat(
3 | {required this.followerCount,
4 | required this.followingCount,
5 | required this.dynamicCount});
6 | static LoginUserStat get zero =>
7 | LoginUserStat(followerCount: 0, followingCount: 0, dynamicCount: 0);
8 | int followerCount;
9 | int followingCount;
10 | int dynamicCount;
11 | }
12 |
--------------------------------------------------------------------------------
/lib/common/models/local/reply/add_reply_result.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/reply/reply_item.dart';
2 |
3 | class AddReplyResult {
4 | AddReplyResult(
5 | {required this.isSuccess, required this.error, required this.replyItem});
6 | bool isSuccess;
7 | String error;
8 | ReplyItem replyItem;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/common/models/local/reply/official_verify.dart:
--------------------------------------------------------------------------------
1 | ///官方认证信息
2 | class OfficialVerify {
3 | OfficialVerify({required this.type, required this.description});
4 | static OfficialVerify get zero =>
5 | OfficialVerify(type: OfficialVerifyType.none, description: "");
6 | OfficialVerifyType type;
7 | String description;
8 | }
9 |
10 | ///官方认证类型
11 | enum OfficialVerifyType {
12 | none,
13 |
14 | person,
15 |
16 | organization
17 | }
18 |
19 | extension OfficialVerifyTypeCode on OfficialVerifyType {
20 | static OfficialVerifyType fromCode(int code) {
21 | switch (code) {
22 | case -1:
23 | return OfficialVerifyType.none;
24 | case 0:
25 | return OfficialVerifyType.person;
26 | case 1:
27 | return OfficialVerifyType.organization;
28 | default:
29 | return OfficialVerifyType.none;
30 | }
31 | }
32 |
33 | get code => [-1, 0, 1][index];
34 | }
35 |
--------------------------------------------------------------------------------
/lib/common/models/local/reply/reply_add_like_result.dart:
--------------------------------------------------------------------------------
1 | class ReplyAddLikeResult {
2 | ReplyAddLikeResult({required this.isSuccess, required this.error});
3 | static ReplyAddLikeResult get zero =>
4 | ReplyAddLikeResult(isSuccess: false, error: '');
5 | bool isSuccess;
6 | String error;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/common/models/local/reply/reply_content.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/reply/reply_member.dart';
2 |
3 | class ReplyContent {
4 | ReplyContent(
5 | {required this.message,
6 | required this.atMembers,
7 | required this.emotes,
8 | required this.jumpUrls,
9 | required this.pictures});
10 | static get zero {
11 | return ReplyContent(
12 | message: "", atMembers: [], emotes: [], jumpUrls: [], pictures: []);
13 | }
14 |
15 | ///评论
16 | String message;
17 |
18 | ///@到的用户
19 | List atMembers;
20 |
21 | ///需要渲染的表情转义和所表示的表情信息
22 | List emotes;
23 |
24 | ///跳转链接
25 | List jumpUrls;
26 |
27 | ///图片
28 | List pictures;
29 | }
30 |
31 | class ReplyJumpUrl {
32 | ReplyJumpUrl({required this.url, required this.title});
33 | static ReplyJumpUrl get zero => ReplyJumpUrl(url: '', title: '');
34 | String url;
35 | String title;
36 | }
37 |
38 | class ReplyPicture {
39 | ReplyPicture(
40 | {required this.url,
41 | required this.width,
42 | required this.height,
43 | required this.size});
44 | static ReplyPicture get zero =>
45 | ReplyPicture(url: '', width: 0, height: 0, size: 1);
46 | String url;
47 | int width;
48 | int height;
49 | double size;
50 | }
51 |
52 | class Emote {
53 | Emote({required this.text, required this.url, required this.size});
54 | static Emote get zero => Emote(text: "", url: "", size: EmoteSize.small);
55 |
56 | ///表情转义符
57 | String text;
58 |
59 | ///表情图片url
60 | String url;
61 |
62 | ///表情大小
63 | EmoteSize size;
64 | }
65 |
66 | enum EmoteSize {
67 | ///1
68 | small,
69 |
70 | ///2
71 | big,
72 | }
73 |
74 | extension EmoteSizeCode on EmoteSize {
75 | int get code => [1, 2][index];
76 | }
77 |
--------------------------------------------------------------------------------
/lib/common/models/local/reply/reply_info.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/reply/reply_item.dart';
2 |
3 | class ReplyInfo {
4 | ReplyInfo(
5 | {required this.replies,
6 | required this.topReplies,
7 | required this.upperMid,
8 | required this.replyCount});
9 | static ReplyInfo get zero =>
10 | ReplyInfo(replies: [], topReplies: [], upperMid: 0, replyCount: 0);
11 |
12 | ///评论
13 | List replies;
14 |
15 | ///置顶评论
16 | List topReplies;
17 |
18 | ///up主的mid
19 | int upperMid;
20 |
21 | ///评论总数
22 | int replyCount;
23 | }
24 |
--------------------------------------------------------------------------------
/lib/common/models/local/reply/reply_member.dart:
--------------------------------------------------------------------------------
1 | import 'official_verify.dart';
2 | import 'vip.dart';
3 |
4 | class ReplyMember {
5 | ReplyMember(
6 | {required this.mid,
7 | required this.name,
8 | required this.gender,
9 | required this.avatarUrl,
10 | required this.level,
11 | required this.officialVerify,
12 | required this.vip});
13 | static ReplyMember get zero => ReplyMember(
14 | mid: 0,
15 | name: "",
16 | gender: Gender.secret,
17 | avatarUrl: "",
18 | level: 0,
19 | officialVerify: OfficialVerify.zero,
20 | vip: Vip.zero);
21 | int mid;
22 | String name;
23 | String avatarUrl;
24 | int level;
25 | OfficialVerify officialVerify;
26 | Vip vip;
27 |
28 | ///性别
29 | Gender gender;
30 | }
31 |
32 | enum Gender { man, woman, secret }
33 |
34 | extension GenderText on Gender {
35 | static Gender fromText(String text) {
36 | switch (text) {
37 | case '男':
38 | return Gender.man;
39 | case '女':
40 | return Gender.woman;
41 | case '保密':
42 | return Gender.secret;
43 | default:
44 | return Gender.secret;
45 | }
46 | }
47 |
48 | get text => ['男', '女', '保密'][index];
49 | }
50 |
--------------------------------------------------------------------------------
/lib/common/models/local/reply/reply_reply_info.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/reply/reply_item.dart';
2 |
3 | class ReplyReplyInfo {
4 | ReplyReplyInfo(
5 | {required this.replies,
6 | required this.rootReply,
7 | required this.upperMid,
8 | required this.replyCount});
9 | static ReplyReplyInfo get zero => ReplyReplyInfo(
10 | replies: [], rootReply: ReplyItem.zero, upperMid: 0, replyCount: 0);
11 | List replies;
12 | ReplyItem rootReply;
13 | int upperMid;
14 |
15 | ///评论总数
16 | int replyCount;
17 | }
18 |
--------------------------------------------------------------------------------
/lib/common/models/local/reply/vip.dart:
--------------------------------------------------------------------------------
1 | ///Vip信息
2 | class Vip {
3 | Vip({required this.isVip, required this.type});
4 | static Vip get zero => Vip(isVip: false, type: VipType.none);
5 | bool isVip;
6 | VipType type;
7 | }
8 |
9 | ///Vip类型
10 | enum VipType { none, month, year }
11 |
12 | extension VipTypeCode on VipType {
13 | static VipType fromCode(int code) {
14 | return VipType.values[code];
15 | }
16 |
17 | int get code => [0, 1, 2][index];
18 | }
19 |
--------------------------------------------------------------------------------
/lib/common/models/local/search/default_search_word.dart:
--------------------------------------------------------------------------------
1 | class DefaultSearchWord {
2 | DefaultSearchWord({required this.showName, required this.name});
3 | static DefaultSearchWord get zero =>
4 | DefaultSearchWord(showName: "", name: "");
5 | String showName;
6 | String name;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/common/models/local/search/hot_word_item.dart:
--------------------------------------------------------------------------------
1 | class HotWordItem {
2 | HotWordItem({required this.keyWord, required this.showWord});
3 | static HotWordItem get zero => HotWordItem(keyWord: "", showWord: "");
4 | String keyWord;
5 | String showWord;
6 | }
7 |
--------------------------------------------------------------------------------
/lib/common/models/local/search/search_bangumi_item.dart:
--------------------------------------------------------------------------------
1 | class SearchBangumiItem {
2 | SearchBangumiItem(
3 | {required this.coverUrl,
4 | required this.title,
5 | required this.describe,
6 | required this.score,
7 | required this.ssid});
8 | static SearchBangumiItem get zero => SearchBangumiItem(
9 | coverUrl: "", title: "", describe: "", score: 0, ssid: 0);
10 | String coverUrl;
11 | String title;
12 | String describe;
13 | double score;
14 | int ssid;
15 | }
16 |
--------------------------------------------------------------------------------
/lib/common/models/local/search/search_suggest_item.dart:
--------------------------------------------------------------------------------
1 | class SearchSuggestItem {
2 | SearchSuggestItem({required this.showWord, required this.realWord});
3 | static SearchSuggestItem get zero =>
4 | SearchSuggestItem(showWord: "", realWord: "");
5 | String showWord;
6 | String realWord;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/common/models/local/search/search_user_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/reply/official_verify.dart';
2 | import 'package:bili_you/common/models/local/reply/reply_member.dart';
3 |
4 | class SearchUserItem {
5 | SearchUserItem(
6 | {required this.mid,
7 | required this.name,
8 | required this.face,
9 | required this.sign,
10 | required this.fansCount,
11 | required this.videoCount,
12 | required this.level,
13 | required this.gender,
14 | required this.isUpper,
15 | required this.isLive,
16 | required this.roomId,
17 | required this.officialVerify});
18 | static SearchUserItem get zero => SearchUserItem(
19 | mid: 0,
20 | name: '',
21 | face: '',
22 | sign: '',
23 | fansCount: 0,
24 | videoCount: 0,
25 | level: 0,
26 | gender: Gender.secret,
27 | isUpper: false,
28 | isLive: false,
29 | roomId: 0,
30 | officialVerify: OfficialVerify.zero);
31 | int mid;
32 | String name;
33 | String face;
34 | String sign;
35 | int fansCount;
36 | int videoCount;
37 | int level;
38 | Gender gender;
39 | bool isUpper;
40 | bool isLive;
41 | int roomId;
42 | OfficialVerify officialVerify;
43 | }
44 |
--------------------------------------------------------------------------------
/lib/common/models/local/search/search_video_item.dart:
--------------------------------------------------------------------------------
1 | class SearchVideoItem {
2 | SearchVideoItem(
3 | {required this.coverUrl,
4 | required this.bvid,
5 | required this.title,
6 | required this.upName,
7 | required this.timeLength,
8 | required this.playNum,
9 | required this.pubDate});
10 | static SearchVideoItem get zero => SearchVideoItem(
11 | coverUrl: "",
12 | bvid: "",
13 | title: "",
14 | upName: "",
15 | timeLength: 0,
16 | playNum: 0,
17 | pubDate: 0);
18 | String coverUrl;
19 | String bvid;
20 | String title;
21 | String upName;
22 | int timeLength;
23 | int playNum;
24 | int pubDate;
25 | }
26 |
--------------------------------------------------------------------------------
/lib/common/models/local/user_space/user_video_search.dart:
--------------------------------------------------------------------------------
1 | class UserVideoSearch {
2 | UserVideoSearch({required this.videos});
3 | static UserVideoSearch get zero => UserVideoSearch(videos: []);
4 | List videos;
5 |
6 | ///TODO 该用户所有投稿视频分区列表
7 | }
8 |
9 | class UserVideoItem {
10 | UserVideoItem({
11 | required this.author,
12 | required this.title,
13 | required this.mid,
14 | required this.bvid,
15 | required this.coverUrl,
16 | required this.danmakuCount,
17 | required this.description,
18 | required this.isUnionVideo,
19 | required this.playCount,
20 | required this.duration,
21 | required this.pubDate,
22 | required this.replyCount,
23 | // required this.typeid
24 | });
25 | static UserVideoItem get zero => UserVideoItem(
26 | author: "",
27 | title: "",
28 | mid: 0,
29 | bvid: "",
30 | coverUrl: "",
31 | danmakuCount: 0,
32 | description: "",
33 | isUnionVideo: false,
34 | playCount: 0,
35 | duration: "--:--",
36 | pubDate: 0,
37 | replyCount: 0,
38 | // typeid: 0
39 | );
40 |
41 | ///评论数
42 | int replyCount;
43 |
44 | // ///分区id
45 | // int typeid;
46 |
47 | ///播放量
48 | int playCount;
49 |
50 | ///封面
51 | String coverUrl;
52 |
53 | ///简介
54 | String description;
55 |
56 | ///标题
57 | String title;
58 |
59 | ///up主名字,如果是合作视频的话是第一个人的名字
60 | String author;
61 |
62 | ///up主mid
63 | int mid;
64 |
65 | ///投稿时间戳
66 | int pubDate;
67 |
68 | ///弹幕量
69 | int danmakuCount;
70 |
71 | ///视频时长,分:秒的形式
72 | String duration;
73 |
74 | ///bvid
75 | String bvid;
76 |
77 | ///是否是合作视频
78 | bool isUnionVideo;
79 | }
80 |
--------------------------------------------------------------------------------
/lib/common/models/local/video/audio_play_item.dart:
--------------------------------------------------------------------------------
1 | class AudioPlayItem {
2 | AudioPlayItem({
3 | required this.urls,
4 | required this.quality,
5 | required this.bandWidth,
6 | required this.codecs,
7 | // required this.mimeType,
8 | // required this.segmentBase,
9 | // required this.timeLength
10 | });
11 | static AudioPlayItem get zero => AudioPlayItem(
12 | urls: [], quality: AudioQuality.unknown, bandWidth: 0, codecs: ""
13 | // ,
14 | // mimeType: '',
15 | // segmentBase: SegmentBase(initialization: '', indexRange: ''),
16 | // timeLength: 0
17 | );
18 | List urls;
19 | AudioQuality quality;
20 | int bandWidth;
21 | String codecs;
22 | // String mimeType;
23 | // SegmentBase segmentBase;
24 | // //时长,秒为单位
25 | // int timeLength;
26 | }
27 |
28 | enum AudioQuality {
29 | unknown,
30 | audio64k,
31 | audio132k,
32 | audio192k,
33 | dolby,
34 | hiRes,
35 | }
36 |
37 | extension AudioQualityCode on AudioQuality {
38 | static final List _codeList = [
39 | -1,
40 | 30216,
41 | 30232,
42 | 30280,
43 | 30250,
44 | 30251,
45 | ];
46 |
47 | static AudioQuality fromCode(int code) {
48 | var index = _codeList.indexOf(code);
49 | if (index == -1) {
50 | return AudioQuality.unknown;
51 | }
52 | return AudioQuality.values[index];
53 | }
54 |
55 | get code => _codeList[index];
56 | }
57 |
58 | extension AudioQualityDescription on AudioQuality {
59 | get description => ['未知', '64K', '132K', '192K', '杜比全景声', 'Hi-Res无损'][index];
60 | }
61 |
--------------------------------------------------------------------------------
/lib/common/models/local/video/click_add_coin_result.dart:
--------------------------------------------------------------------------------
1 | class ClickAddCoinResult {
2 | ClickAddCoinResult({required this.isSuccess, required this.error});
3 | static ClickAddCoinResult get zero =>
4 | ClickAddCoinResult(isSuccess: false, error: '');
5 | bool isSuccess;
6 | String error;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/common/models/local/video/click_add_share_result.dart:
--------------------------------------------------------------------------------
1 | class ClickAddShareResult {
2 | ClickAddShareResult(
3 | {required this.isSuccess,
4 | required this.error,
5 | required this.currentShareNum});
6 | static ClickAddShareResult get zero =>
7 | ClickAddShareResult(isSuccess: false, error: '', currentShareNum: 0);
8 | bool isSuccess;
9 | String error;
10 | int currentShareNum;
11 | }
12 |
--------------------------------------------------------------------------------
/lib/common/models/local/video/click_like_result.dart:
--------------------------------------------------------------------------------
1 | ///点赞后的结果
2 | class ClickLikeResult {
3 | ClickLikeResult(
4 | {required this.isSuccess, required this.error, required this.haslike});
5 |
6 | ///操作是否成功
7 | bool isSuccess;
8 |
9 | ///错误信息
10 | String error;
11 |
12 | ///成功后的状态
13 | ///true为已点赞
14 | ///false则是未点赞
15 | bool haslike;
16 | }
17 |
--------------------------------------------------------------------------------
/lib/common/models/local/video/part_info.dart:
--------------------------------------------------------------------------------
1 | class PartInfo {
2 | PartInfo({required this.title, required this.cid});
3 | static PartInfo get zero => PartInfo(title: "", cid: 0);
4 | String title;
5 | int cid;
6 | }
7 |
--------------------------------------------------------------------------------
/lib/common/models/local/video/video_info.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/video/part_info.dart';
2 |
3 | class VideoInfo {
4 | VideoInfo(
5 | {required this.title,
6 | required this.describe,
7 | required this.bvid,
8 | required this.cid,
9 | required this.copyRight,
10 | required this.pubDate,
11 | required this.playNum,
12 | required this.danmaukuNum,
13 | required this.coinNum,
14 | required this.favariteNum,
15 | required this.likeNum,
16 | required this.shareNum,
17 | required this.ownerFace,
18 | required this.ownerMid,
19 | required this.ownerName,
20 | required this.parts,
21 | required this.hasLike,
22 | required this.hasAddCoin,
23 | required this.hasFavourite});
24 | static VideoInfo get zero => VideoInfo(
25 | title: "",
26 | describe: "",
27 | bvid: "",
28 | cid: 0,
29 | copyRight: "",
30 | pubDate: 0,
31 | playNum: 0,
32 | danmaukuNum: 0,
33 | coinNum: 0,
34 | favariteNum: 0,
35 | likeNum: 0,
36 | shareNum: 0,
37 | ownerFace: "",
38 | ownerMid: 0,
39 | ownerName: "",
40 | parts: [],
41 | hasLike: false,
42 | hasAddCoin: false,
43 | hasFavourite: false);
44 | String title;
45 | String describe;
46 | String bvid;
47 | int cid;
48 | String copyRight;
49 | int playNum;
50 | int danmaukuNum;
51 | int pubDate;
52 | int likeNum;
53 | int coinNum;
54 | int favariteNum;
55 | int shareNum;
56 | String ownerFace;
57 | String ownerName;
58 | int ownerMid;
59 | List parts;
60 | bool hasLike;
61 | bool hasAddCoin;
62 | bool hasFavourite;
63 | }
64 |
--------------------------------------------------------------------------------
/lib/common/models/local/video/video_play_info.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/video/audio_play_item.dart';
2 | import 'package:bili_you/common/models/local/video/video_play_item.dart';
3 |
4 | class VideoPlayInfo {
5 | VideoPlayInfo(
6 | {
7 | // required this.defualtVideoQuality,
8 | required this.supportVideoQualities,
9 | required this.supportAudioQualities,
10 | required this.timeLength,
11 | required this.videos,
12 | required this.audios,
13 | required this.lastPlayCid,
14 | required this.lastPlayTime});
15 | static VideoPlayInfo get zero => VideoPlayInfo(
16 | supportVideoQualities: [],
17 | supportAudioQualities: [],
18 | timeLength: 0,
19 | videos: [],
20 | audios: [],
21 | lastPlayCid: 0,
22 | lastPlayTime: Duration.zero);
23 | // VideoQuality defualtVideoQuality ;
24 | ///支持的视频质量
25 | ///
26 | ///不是所有的质量都能播放,因为有一些是需要Vip的,不支持的质量在videos列表中会找不到
27 | List supportVideoQualities;
28 | // AudioQuality defualtAudioQuality ;
29 | ///支持的音频质量
30 | List supportAudioQualities;
31 | int timeLength;
32 | List videos;
33 | List audios;
34 | Duration lastPlayTime;
35 | int lastPlayCid;
36 | }
37 |
38 | extension VideoPlayInfoMethods on VideoPlayInfo {
39 | ///通过画质查找视频
40 | List findVideoByVideoQuality(VideoQuality videoQuality) {
41 | List list = [];
42 | for (var i in videos) {
43 | if (i.quality == videoQuality) {
44 | list.add(i);
45 | }
46 | }
47 | return list;
48 | }
49 |
50 | ///通过音质查找视频
51 | List findAudioByAudioQuality(AudioQuality audioQuality) {
52 | List list = [];
53 | for (var i in audios) {
54 | if (i.quality == audioQuality) {
55 | list.add(i);
56 | }
57 | }
58 | return list;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/common/models/local/video_tile/video_tile_info.dart:
--------------------------------------------------------------------------------
1 | class VideoTileInfo {
2 | VideoTileInfo(
3 | {required this.coverUrl,
4 | required this.bvid,
5 | required this.cid,
6 | required this.title,
7 | required this.upName,
8 | required this.timeLength,
9 | required this.playNum,
10 | required this.pubDate});
11 | static VideoTileInfo get zero => VideoTileInfo(
12 | coverUrl: "",
13 | bvid: "",
14 | cid: 0,
15 | title: "",
16 | upName: "",
17 | timeLength: 0,
18 | playNum: 0,
19 | pubDate: 0);
20 | String coverUrl;
21 | String bvid;
22 | int cid;
23 | String title;
24 | String upName;
25 | int timeLength;
26 | int playNum;
27 | int pubDate;
28 | }
29 |
--------------------------------------------------------------------------------
/lib/common/models/network/history/report_history.dart:
--------------------------------------------------------------------------------
1 | class ReportHistory {
2 | ReportHistory({
3 | this.code,
4 | this.message,
5 | this.ttl,
6 | });
7 |
8 | ReportHistory.fromJson(dynamic json) {
9 | code = json['code'];
10 | message = json['message'];
11 | ttl = json['ttl'];
12 | }
13 | int? code;
14 | String? message;
15 | int? ttl;
16 |
17 | Map toJson() {
18 | final map = {};
19 | map['code'] = code;
20 | map['message'] = message;
21 | map['ttl'] = ttl;
22 | return map;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/common/models/network/login/captcha_result.dart:
--------------------------------------------------------------------------------
1 | import 'captcha_data.dart';
2 |
3 | class CaptchaResultModel {
4 | String validate;
5 | String seccode;
6 |
7 | CaptchaDataResponse captchaData;
8 | CaptchaResultModel(
9 | {this.validate = "", this.seccode = "", required this.captchaData});
10 | }
11 |
--------------------------------------------------------------------------------
/lib/common/models/network/login/password_login_key_hash.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class PasswordLoginKeyHashResponse {
4 | PasswordLoginKeyHashResponse({
5 | this.code,
6 | this.message,
7 | this.ttl,
8 | this.data,
9 | });
10 |
11 | int? code;
12 | String? message;
13 | int? ttl;
14 | PasswordLoginKeyHashResponseData? data;
15 |
16 | factory PasswordLoginKeyHashResponse.fromRawJson(String str) =>
17 | PasswordLoginKeyHashResponse.fromJson(json.decode(str));
18 |
19 | String toRawJson() => json.encode(toJson());
20 |
21 | factory PasswordLoginKeyHashResponse.fromJson(Map json) =>
22 | PasswordLoginKeyHashResponse(
23 | code: json["code"],
24 | message: json["message"],
25 | ttl: json["ttl"],
26 | data: json["data"] == null
27 | ? null
28 | : PasswordLoginKeyHashResponseData.fromJson(json["data"]),
29 | );
30 |
31 | Map toJson() => {
32 | "code": code,
33 | "message": message,
34 | "ttl": ttl,
35 | "data": data?.toJson(),
36 | };
37 | }
38 |
39 | class PasswordLoginKeyHashResponseData {
40 | PasswordLoginKeyHashResponseData({
41 | this.hash,
42 | this.key,
43 | });
44 |
45 | String? hash;
46 | String? key;
47 |
48 | factory PasswordLoginKeyHashResponseData.fromRawJson(String str) =>
49 | PasswordLoginKeyHashResponseData.fromJson(json.decode(str));
50 |
51 | String toRawJson() => json.encode(toJson());
52 |
53 | factory PasswordLoginKeyHashResponseData.fromJson(
54 | Map json) =>
55 | PasswordLoginKeyHashResponseData(
56 | hash: json["hash"],
57 | key: json["key"],
58 | );
59 |
60 | Map toJson() => {
61 | "hash": hash,
62 | "key": key,
63 | };
64 | }
65 |
--------------------------------------------------------------------------------
/lib/common/models/network/login/password_login_result.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class PostPasswordLoginResponse {
4 | PostPasswordLoginResponse({
5 | this.code,
6 | this.message,
7 | this.data,
8 | });
9 |
10 | int? code;
11 | String? message;
12 | PostPasswordLoginResponseData? data;
13 |
14 | factory PostPasswordLoginResponse.fromRawJson(String str) =>
15 | PostPasswordLoginResponse.fromJson(json.decode(str));
16 |
17 | String toRawJson() => json.encode(toJson());
18 |
19 | factory PostPasswordLoginResponse.fromJson(Map json) =>
20 | PostPasswordLoginResponse(
21 | code: json["code"],
22 | message: json["message"],
23 | data: json["data"] == null
24 | ? null
25 | : PostPasswordLoginResponseData.fromJson(json["data"]),
26 | );
27 |
28 | Map toJson() => {
29 | "code": code,
30 | "message": message,
31 | "data": data?.toJson(),
32 | };
33 | }
34 |
35 | class PostPasswordLoginResponseData {
36 | PostPasswordLoginResponseData({
37 | this.status,
38 | });
39 |
40 | int? status;
41 |
42 | factory PostPasswordLoginResponseData.fromRawJson(String str) =>
43 | PostPasswordLoginResponseData.fromJson(json.decode(str));
44 |
45 | String toRawJson() => json.encode(toJson());
46 |
47 | factory PostPasswordLoginResponseData.fromJson(Map json) =>
48 | PostPasswordLoginResponseData(
49 | status: json["status"],
50 | );
51 |
52 | Map toJson() => {
53 | "status": status,
54 | };
55 | }
56 |
--------------------------------------------------------------------------------
/lib/common/models/network/login/post_sms_login.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class PostSmsLoginResponse {
4 | PostSmsLoginResponse({
5 | this.code,
6 | this.message,
7 | this.data,
8 | });
9 |
10 | int? code;
11 | String? message;
12 | PostSmsLoginResponseData? data;
13 |
14 | factory PostSmsLoginResponse.fromRawJson(String str) =>
15 | PostSmsLoginResponse.fromJson(json.decode(str));
16 |
17 | String toRawJson() => json.encode(toJson());
18 |
19 | factory PostSmsLoginResponse.fromJson(Map json) =>
20 | PostSmsLoginResponse(
21 | code: json["code"],
22 | message: json["message"],
23 | data: json["data"] == null
24 | ? null
25 | : PostSmsLoginResponseData.fromJson(json["data"]),
26 | );
27 |
28 | Map toJson() => {
29 | "code": code,
30 | "message": message,
31 | "data": data?.toJson(),
32 | };
33 | }
34 |
35 | class PostSmsLoginResponseData {
36 | PostSmsLoginResponseData({
37 | this.isNew,
38 | this.status,
39 | });
40 |
41 | bool? isNew;
42 | int? status;
43 |
44 | factory PostSmsLoginResponseData.fromRawJson(String str) =>
45 | PostSmsLoginResponseData.fromJson(json.decode(str));
46 |
47 | String toRawJson() => json.encode(toJson());
48 |
49 | factory PostSmsLoginResponseData.fromJson(Map json) =>
50 | PostSmsLoginResponseData(
51 | isNew: json["is_new"],
52 | status: json["status"],
53 | );
54 |
55 | Map toJson() => {
56 | "is_new": isNew,
57 | "status": status,
58 | };
59 | }
60 |
--------------------------------------------------------------------------------
/lib/common/models/network/login/post_sms_require.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class PostSmsRequireResponse {
4 | PostSmsRequireResponse({
5 | this.code,
6 | this.message,
7 | this.data,
8 | });
9 |
10 | int? code;
11 | String? message;
12 | PostSmsRequireResponseData? data;
13 |
14 | factory PostSmsRequireResponse.fromRawJson(String str) =>
15 | PostSmsRequireResponse.fromJson(json.decode(str));
16 |
17 | String toRawJson() => json.encode(toJson());
18 |
19 | factory PostSmsRequireResponse.fromJson(Map json) =>
20 | PostSmsRequireResponse(
21 | code: json["code"],
22 | message: json["message"],
23 | data: json["data"] == null
24 | ? null
25 | : PostSmsRequireResponseData.fromJson(json["data"]),
26 | );
27 |
28 | Map toJson() => {
29 | "code": code,
30 | "message": message,
31 | "data": data?.toJson(),
32 | };
33 | }
34 |
35 | class PostSmsRequireResponseData {
36 | PostSmsRequireResponseData({
37 | this.captchaKey,
38 | });
39 |
40 | String? captchaKey;
41 |
42 | factory PostSmsRequireResponseData.fromRawJson(String str) =>
43 | PostSmsRequireResponseData.fromJson(json.decode(str));
44 |
45 | String toRawJson() => json.encode(toJson());
46 |
47 | factory PostSmsRequireResponseData.fromJson(Map json) =>
48 | PostSmsRequireResponseData(
49 | captchaKey: json["captcha_key"],
50 | );
51 |
52 | Map toJson() => {
53 | "captcha_key": captchaKey,
54 | };
55 | }
56 |
--------------------------------------------------------------------------------
/lib/common/models/network/user/user_stat.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class LoginUserStatResponse {
4 | LoginUserStatResponse({
5 | this.code,
6 | this.message,
7 | this.ttl,
8 | this.data,
9 | });
10 |
11 | int? code;
12 | String? message;
13 | int? ttl;
14 | UserStatResponseData? data;
15 |
16 | factory LoginUserStatResponse.fromRawJson(String str) =>
17 | LoginUserStatResponse.fromJson(json.decode(str));
18 |
19 | String toRawJson() => json.encode(toJson());
20 |
21 | factory LoginUserStatResponse.fromJson(Map json) =>
22 | LoginUserStatResponse(
23 | code: json["code"],
24 | message: json["message"],
25 | ttl: json["ttl"],
26 | data: json["data"] == null
27 | ? null
28 | : UserStatResponseData.fromJson(json["data"]),
29 | );
30 |
31 | Map toJson() => {
32 | "code": code,
33 | "message": message,
34 | "ttl": ttl,
35 | "data": data?.toJson(),
36 | };
37 | }
38 |
39 | class UserStatResponseData {
40 | UserStatResponseData({
41 | this.following,
42 | this.follower,
43 | this.dynamicCount,
44 | });
45 |
46 | int? following;
47 | int? follower;
48 | int? dynamicCount;
49 |
50 | factory UserStatResponseData.fromRawJson(String str) =>
51 | UserStatResponseData.fromJson(json.decode(str));
52 |
53 | String toRawJson() => json.encode(toJson());
54 |
55 | factory UserStatResponseData.fromJson(Map json) =>
56 | UserStatResponseData(
57 | following: json["following"],
58 | follower: json["follower"],
59 | dynamicCount: json["dynamic_count"],
60 | );
61 |
62 | Map toJson() => {
63 | "following": following,
64 | "follower": follower,
65 | "dynamic_count": dynamicCount,
66 | };
67 | }
68 |
--------------------------------------------------------------------------------
/lib/common/models/network/user_relations/user_realtion.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:bili_you/common/models/network/user/user_info.dart';
4 |
5 | class UserRelation {
6 | int? mid;
7 | int? attribute;
8 | int? mtime;
9 | dynamic tag;
10 | int? special;
11 | Object? contractInfo;
12 | String? uname;
13 | String? face;
14 | int? faceNft;
15 | String? sign;
16 | OfficialVerify? officialVerify;
17 | Vip? vip;
18 | String? nftIcon;
19 | String? recReason;
20 | String? trackId;
21 |
22 | UserRelation({
23 | this.mid,
24 | this.attribute,
25 | this.mtime,
26 | this.tag,
27 | this.special,
28 | this.contractInfo,
29 | this.uname,
30 | this.face,
31 | this.faceNft,
32 | this.sign,
33 | this.officialVerify,
34 | this.vip,
35 | this.nftIcon,
36 | this.recReason,
37 | this.trackId,
38 | });
39 |
40 | factory UserRelation.fromRawJson(String str) => json.decode(str);
41 | factory UserRelation.fromJson(Map json) => UserRelation(
42 | mid: json["mid"],
43 | attribute: json["attribute"],
44 | mtime: json["mtime"],
45 | tag: json["tag"],
46 | special: json["special"],
47 | contractInfo: json["contract_info"],
48 | uname: json["uname"],
49 | face: json["face"],
50 | faceNft: json["face_nft"],
51 | sign: json["sign"],
52 | officialVerify: OfficialVerify.fromJson(json["official_verify"]),
53 | vip: Vip.fromJson(json["vip"]),
54 | nftIcon: json["nft_icon"],
55 | recReason: json["rec_reason"],
56 | trackId: json["track_id"]);
57 |
58 | Map toJson() => {
59 | "mid": mid,
60 | "attribute": attribute,
61 | "mtime": mtime,
62 | "tag": tag,
63 | "special": special,
64 | "contract_info": contractInfo,
65 | "uname": uname,
66 | "face": face,
67 | "face_nft": faceNft,
68 | "sign": sign,
69 | "official_verify": officialVerify?.toJson(),
70 | "vip": vip?.toJson(),
71 | "nft_icon": nftIcon,
72 | "rec_reason": recReason,
73 | "track_id": trackId,
74 | };
75 |
76 | String toRawJson() => json.encode(toJson());
77 | }
78 |
--------------------------------------------------------------------------------
/lib/common/models/network/user_relations/user_relation_types.dart:
--------------------------------------------------------------------------------
1 | //对于查询者,被查询者的身份
2 | enum UserRelationType{
3 | following, //关注
4 | follower, //粉丝
5 | }
--------------------------------------------------------------------------------
/lib/common/utils/bvid_avid_util.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class BvidAvidUtil {
6 | static const String table =
7 | "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF";
8 | static const List seqArray = [11, 10, 3, 8, 4, 6];
9 | static const int xOr = 177451812;
10 | static const int xAdd = 8728348608;
11 | static const List defaultBvid = [
12 | 'B',
13 | 'V',
14 | '1',
15 | '',
16 | '',
17 | '4',
18 | '',
19 | '1',
20 | '',
21 | '7',
22 | '',
23 | ''
24 | ];
25 |
26 | ///avid转bvid
27 | static String av2Bvid(int av) {
28 | int newAvId = (av ^ xOr) + xAdd;
29 | List defaultBv = [];
30 | defaultBv.addAll(BvidAvidUtil.defaultBvid);
31 | for (int i = 0; i < seqArray.length; i++) {
32 | defaultBv[seqArray[i]] = table.characters
33 | .elementAt((newAvId / pow(58, i).toInt() % 58).toInt());
34 | }
35 | return defaultBv.join();
36 | }
37 |
38 | ///bvid转avid
39 | static int bvid2Av(String bvid) {
40 | int newAvId = 0;
41 | for (int i = 0; i < seqArray.length; i++) {
42 | newAvId +=
43 | (table.indexOf(bvid.characters.elementAt(seqArray[i])) * pow(58, i))
44 | .toInt();
45 | }
46 | int av = (newAvId - xAdd) ^ xOr;
47 | return av;
48 | }
49 |
50 | ///判断是否是bvid
51 | ///只是简单的通过文本判断
52 | static bool isBvid(String bvid) {
53 | bvid = bvid.toUpperCase();
54 | if (bvid.length != defaultBvid.length) return false;
55 | for (int i = 0; i < bvid.length; i++) {
56 | if (defaultBvid[i] == '') continue;
57 | if (bvid.characters.elementAt(i) != defaultBvid[i]) return false;
58 | }
59 | return true;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/common/utils/cache_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_cache_manager/flutter_cache_manager.dart';
2 |
3 | class CacheUtils {
4 | static const String userFaceKey = 'userFace';
5 | static const String othersFaceKey = 'othersFace';
6 | static const String recommendItemCoverKey = 'recommendItemCover';
7 | static const String searchResultItemCoverKey = 'searchResultItemCover';
8 | static const String relatedVideosItemCoverKey = 'relatedVideosItemCover';
9 | static const String dynamicVideoItemCoverKey = 'dynamicVideoItemCover';
10 | static const String emoteKey = 'emote';
11 | static const String bigImageKey = 'bigImageKey';
12 |
13 | static final CacheManager userFaceCacheManager =
14 | CacheManager(Config(userFaceKey));
15 | static final CacheManager othersFaceCacheManager =
16 | CacheManager(Config(othersFaceKey));
17 | static final CacheManager recommendItemCoverCacheManager =
18 | CacheManager(Config(recommendItemCoverKey));
19 | static final CacheManager searchResultItemCoverCacheManager =
20 | CacheManager(Config(searchResultItemCoverKey));
21 | static final CacheManager relatedVideosItemCoverCacheManager =
22 | CacheManager(Config(relatedVideosItemCoverKey));
23 | static final CacheManager dynamicVideoItemCoverCacheManager =
24 | CacheManager(Config(dynamicVideoItemCoverKey));
25 | static final CacheManager emoteCacheManager = CacheManager(Config(emoteKey));
26 | static final CacheManager bigImageCacheManager =
27 | CacheManager(Config(bigImageKey));
28 | static final List cacheMangerList = [
29 | userFaceCacheManager,
30 | othersFaceCacheManager,
31 | recommendItemCoverCacheManager,
32 | searchResultItemCoverCacheManager,
33 | relatedVideosItemCoverCacheManager,
34 | dynamicVideoItemCoverCacheManager,
35 | emoteCacheManager,
36 | bigImageCacheManager
37 | ];
38 |
39 | ///释放所有图像内存
40 | static void clearAllCacheImageMem() {
41 | for (var cacheManager in cacheMangerList) {
42 | cacheManager.store.emptyMemoryCache();
43 | }
44 | }
45 |
46 | ///删除所有图片缓存(除了用户头像缓存)
47 | static Future deleteAllCacheImage() async {
48 | for (var cacheManager in cacheMangerList) {
49 | //不删除用户头像
50 | if (cacheManager == userFaceCacheManager) continue;
51 | await cacheManager.store.emptyCache();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/common/utils/cookie_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/api_constants.dart';
2 |
3 | import 'http_utils.dart';
4 |
5 | class CookieUtils {
6 | static Future getCsrf() async {
7 | //从cookie中获取csrf需要的数据
8 | for (var i in (await HttpUtils.cookieManager.cookieJar
9 | .loadForRequest(Uri.parse(ApiConstants.bilibiliBase)))) {
10 | if (i.name == 'bili_jct') {
11 | return i.value;
12 | }
13 | }
14 | return '';
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/common/utils/fullscreen.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:auto_orientation/auto_orientation.dart';
4 | import 'package:device_info_plus/device_info_plus.dart';
5 | import 'package:flutter/services.dart';
6 |
7 | //进入全屏显示
8 | Future enterFullScreen() async {
9 | await SystemChrome.setEnabledSystemUIMode(
10 | SystemUiMode.immersiveSticky,
11 | );
12 | }
13 |
14 | //退出全屏显示
15 | Future exitFullScreen() async {
16 | late SystemUiMode mode;
17 | if ((Platform.isAndroid &&
18 | (await DeviceInfoPlugin().androidInfo).version.sdkInt >= 29) ||
19 | !Platform.isAndroid) {
20 | mode = SystemUiMode.edgeToEdge;
21 | } else {
22 | mode = SystemUiMode.manual;
23 | }
24 | await SystemChrome.setEnabledSystemUIMode(mode,
25 | overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]);
26 | }
27 |
28 | //横屏
29 | Future landScape() async {
30 | if (Platform.isAndroid || Platform.isIOS) {
31 | await AutoOrientation.landscapeAutoMode(forceSensor: true);
32 | }
33 | }
34 |
35 | //竖屏
36 | Future portraitUp() async {
37 | await SystemChrome.setPreferredOrientations([
38 | DeviceOrientation.portraitUp,
39 | ]);
40 | }
41 |
--------------------------------------------------------------------------------
/lib/common/utils/index.dart:
--------------------------------------------------------------------------------
1 | export 'bili_you_storage.dart';
2 | export 'fullscreen.dart';
3 | export 'settings.dart';
4 | export 'string_format_utils.dart';
5 |
--------------------------------------------------------------------------------
/lib/common/values/hero_tag_id.dart:
--------------------------------------------------------------------------------
1 | class HeroTagId {
2 | static int id = 0;
3 | static int lastId = 0;
4 | }
5 |
--------------------------------------------------------------------------------
/lib/common/values/index.dart:
--------------------------------------------------------------------------------
1 | export '../utils/cache_util.dart';
2 | export 'coutry_id.dart';
3 |
--------------------------------------------------------------------------------
/lib/common/widget/icon_text_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class IconTextButton extends StatelessWidget {
4 | const IconTextButton({
5 | super.key,
6 | required this.onPressed,
7 | required this.icon,
8 | required this.text,
9 | this.selected = false,
10 | });
11 | final Function()? onPressed;
12 | final Widget icon;
13 | final Text? text;
14 |
15 | ///是否被选上
16 | final bool selected;
17 | @override
18 | Widget build(BuildContext context) {
19 | return ElevatedButton(
20 | style: ButtonStyle(
21 | visualDensity: VisualDensity.comfortable,
22 | foregroundColor: selected
23 | ? MaterialStatePropertyAll(Theme.of(context).colorScheme.onPrimary)
24 | : null,
25 | backgroundColor: selected
26 | ? MaterialStatePropertyAll(Theme.of(context).colorScheme.primary)
27 | : null,
28 | elevation: const MaterialStatePropertyAll(0),
29 | padding: const MaterialStatePropertyAll(
30 | EdgeInsets.only(left: 10, right: 10, bottom: 0, top: 0)),
31 | minimumSize: const MaterialStatePropertyAll(Size(10, 10)),
32 | ),
33 | onPressed: onPressed ?? () {},
34 | child: FittedBox(
35 | child: Column(
36 | mainAxisAlignment: MainAxisAlignment.center,
37 | children: [icon, if (text != null) text!],
38 | ),
39 | ),
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/common/widget/index.dart:
--------------------------------------------------------------------------------
1 | export 'bangumi_tile_item.dart';
2 | export 'video_audio_player.dart';
3 | export 'video_tile_item.dart';
4 |
5 |
--------------------------------------------------------------------------------
/lib/common/widget/radio_list_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class RadioListDialog extends StatefulWidget {
4 | const RadioListDialog(
5 | {super.key,
6 | required this.title,
7 | required this.itemNameValueMap,
8 | required this.groupValue,
9 | this.onChanged});
10 | final String title;
11 | final Map itemNameValueMap;
12 | final T groupValue;
13 | final Function(T? value)? onChanged;
14 |
15 | @override
16 | State> createState() => _RadioListDialogState();
17 | }
18 |
19 | class _RadioListDialogState extends State> {
20 | late List items;
21 | @override
22 | void initState() {
23 | items = [];
24 | widget.itemNameValueMap.forEach((title, value) {
25 | items.add(RadioListTile(
26 | value: value,
27 | groupValue: widget.groupValue,
28 | title: Text(title),
29 | onChanged: (value) {
30 | widget.onChanged?.call(value);
31 | setState(() {});
32 | },
33 | ));
34 | });
35 | super.initState();
36 | }
37 |
38 | @override
39 | Widget build(BuildContext context) {
40 | return AlertDialog(
41 | scrollable: true,
42 | title: Text(widget.title),
43 | content: Column(children: items),
44 | actions: [
45 | TextButton(
46 | onPressed: () => Navigator.of(context).pop(),
47 | child: const Text('取消'))
48 | ],
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/common/widget/settings_label.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class SettingsLabel extends StatelessWidget {
4 | const SettingsLabel({super.key, required this.text});
5 | final String text;
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Padding(
10 | padding: const EdgeInsets.only(left: 16, right: 16),
11 | child: Text(
12 | text,
13 | style: TextStyle(color: Theme.of(context).colorScheme.primary),
14 | ),
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lib/common/widget/settings_radios_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/widget/radio_list_dialog.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class SettingsRadiosTile extends StatefulWidget {
5 | const SettingsRadiosTile(
6 | {super.key,
7 | required this.title,
8 | required this.subTitle,
9 | required this.buildTrailingText,
10 | required this.itemNameValue,
11 | required this.buildGroupValue,
12 | required this.applyValue});
13 | final String title;
14 | final String subTitle;
15 |
16 | ///当前已选择项的名称
17 | final String Function() buildTrailingText;
18 |
19 | ///项的(名称--值)数据表
20 | final Map itemNameValue;
21 |
22 | ///当前选择项的值
23 | final T Function() buildGroupValue;
24 |
25 | ///使当前选择值生效的回调函数
26 | final Function(T value) applyValue;
27 |
28 | @override
29 | State> createState() => _SettingsRadiosTileState();
30 | }
31 |
32 | class _SettingsRadiosTileState extends State> {
33 | @override
34 | Widget build(BuildContext context) {
35 | return ListTile(
36 | title: Text(widget.title),
37 | subtitle: Text(widget.subTitle),
38 | trailing: Text(widget.buildTrailingText()),
39 | onTap: () {
40 | showDialog(
41 | context: context,
42 | builder: (context) => RadioListDialog(
43 | title: widget.title,
44 | itemNameValueMap: widget.itemNameValue,
45 | groupValue: widget.buildGroupValue(),
46 | onChanged: (value) {
47 | if (value != null) widget.applyValue(value);
48 | Navigator.of(context).pop();
49 | setState(
50 | () {},
51 | );
52 | },
53 | ),
54 | );
55 | },
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/common/widget/settings_slider_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/utils/index.dart';
2 | import 'package:bili_you/common/widget/slider_dialog.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class SettingsSliderTile extends StatefulWidget {
6 | const SettingsSliderTile(
7 | {super.key,
8 | required this.title,
9 | required this.subTitle,
10 | required this.settingsKey,
11 | required this.defualtValue,
12 | required this.min,
13 | required this.max,
14 | this.divisions,
15 | required this.buildLabel});
16 | final String title;
17 | final String subTitle;
18 | final String settingsKey;
19 | final double defualtValue;
20 |
21 | final double min;
22 | final double max;
23 | final int? divisions;
24 |
25 | ///构建trailing和slider的label
26 | final String Function(double selectingValue)? buildLabel;
27 |
28 | @override
29 | State createState() => _SettingsSliderTileState();
30 | }
31 |
32 | class _SettingsSliderTileState extends State {
33 | @override
34 | Widget build(BuildContext context) {
35 | double initValue = SettingsUtil.getValue(widget.settingsKey,
36 | defaultValue: widget.defualtValue);
37 | return ListTile(
38 | title: Text(widget.title),
39 | subtitle: Text(widget.subTitle),
40 | trailing: widget.buildLabel != null
41 | ? StatefulBuilder(builder: (context, setState) {
42 | return Text(widget.buildLabel!.call(initValue));
43 | })
44 | : null,
45 | onTap: () {
46 | showDialog(
47 | context: context,
48 | builder: (context) => SliderDialog(
49 | title: widget.title,
50 | initValue: initValue,
51 | min: widget.min,
52 | max: widget.max,
53 | divisions: widget.divisions,
54 | buildLabel: widget.buildLabel,
55 | onOk: (selectingValue) async {
56 | await SettingsUtil.setValue(widget.settingsKey, selectingValue);
57 | setState(() {});
58 | },
59 | ),
60 | );
61 | },
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/common/widget/settings_switch_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/utils/settings.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class SettingsSwitchTile extends StatelessWidget {
5 | const SettingsSwitchTile(
6 | {super.key,
7 | required this.title,
8 | required this.subTitle,
9 | required this.settingsKey,
10 | required this.defualtValue,
11 | this.apply});
12 | final String title;
13 | final String subTitle;
14 | final String settingsKey;
15 | final bool defualtValue;
16 |
17 | ///在开关切换且设置保存后进行调用,提供给外部进行应用该设置项
18 | final Function()? apply;
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return ListTile(
23 | title: Text(title),
24 | subtitle: Text(subTitle),
25 | trailing: StatefulBuilder(builder: (context, setState) {
26 | return Switch(
27 | value: SettingsUtil.getValue(settingsKey, defaultValue: defualtValue),
28 | onChanged: (value) async {
29 | await SettingsUtil.setValue(settingsKey, value);
30 | setState(() {});
31 | apply?.call();
32 | },
33 | );
34 | }),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/common/widget/tag.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class TextTag extends StatelessWidget {
4 | final String text;
5 |
6 | const TextTag({Key? key, required this.text}) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Card(
11 | color: Theme.of(context).colorScheme.secondary,
12 | child: Text(
13 | ' $text ',
14 | style: TextStyle(
15 | color: Theme.of(context).colorScheme.onSecondary,
16 | fontSize: 10,
17 | fontWeight: FontWeight.bold,
18 | ),
19 | ),
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/index.dart:
--------------------------------------------------------------------------------
1 | export 'common/index.dart';
2 | export 'main.dart';
3 |
--------------------------------------------------------------------------------
/lib/pages/about/index.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/lib/pages/about/index.dart
--------------------------------------------------------------------------------
/lib/pages/bili_live/controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 |
3 | import 'package:bili_you/common/api/index.dart';
4 | import 'package:bili_you/common/utils/http_utils.dart';
5 | import 'package:bili_you/common/widget/video_audio_player.dart';
6 | import 'package:get/get.dart';
7 | import 'package:media_kit/media_kit.dart';
8 |
9 | class BiliLivePageController extends GetxController {
10 | BiliLivePageController({required this.roomId});
11 | final int roomId;
12 | Future init() async {
13 | await PlayersSingleton().dispose();
14 | await PlayersSingleton().init();
15 | PlayersSingleton().count++;
16 | await onRefresh();
17 | }
18 |
19 | Future onRefresh() async {
20 | var response =
21 | await HttpUtils().get(ApiConstants.livePlayUrl, queryParameters: {
22 | 'room_id': roomId,
23 | 'protocol': '0, 1',
24 | 'format': '0, 1, 2',
25 | 'codec': '0, 1',
26 | 'qn': 250,
27 | 'platform': 'web',
28 | 'ptype': 8,
29 | 'dolby': 5,
30 | 'panorama': 1
31 | });
32 | log(response.data['code'].toString());
33 | log(response.data['message']);
34 | String baseUrl = response.data['data']['playurl_info']['playurl']['stream']
35 | [0]['format'][0]['codec'][0]['base_url'];
36 | String host = response.data['data']['playurl_info']['playurl']['stream'][0]
37 | ['format'][0]['codec'][0]['url_info'][0]['host'];
38 | String extra = response.data['data']['playurl_info']['playurl']['stream'][0]
39 | ['format'][0]['codec'][0]['url_info'][0]['extra'];
40 |
41 | await PlayersSingleton().player!.open(
42 | Media(host + baseUrl + extra,
43 | httpHeaders: {'referer': 'https://live.bilibili.com'}),
44 | );
45 | await PlayersSingleton().player!.play();
46 | }
47 |
48 | @override
49 | void onClose() {
50 | PlayersSingleton().dispose();
51 | super.onClose();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/pages/bili_live/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/index.dart';
2 | import 'package:bili_you/common/models/local/live/live_room_card_info.dart';
3 | import 'package:bili_you/pages/bili_live/controller.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:get/get.dart';
6 | import 'package:media_kit_video/media_kit_video.dart';
7 |
8 | class BiliLivePage extends StatefulWidget {
9 | const BiliLivePage({super.key, required this.info});
10 | final LiveRoomCardInfo info;
11 |
12 | @override
13 | State createState() => _BiliLivePageState();
14 | }
15 |
16 | class _BiliLivePageState extends State {
17 | late final BiliLivePageController controller;
18 | @override
19 | void initState() {
20 | controller = Get.put(BiliLivePageController(roomId: widget.info.roomId));
21 | super.initState();
22 | }
23 |
24 | @override
25 | void dispose() {
26 | controller.dispose();
27 | super.dispose();
28 | }
29 |
30 | @override
31 | Widget build(BuildContext context) {
32 | return Scaffold(
33 | appBar: AppBar(
34 | title: Text(widget.info.title),
35 | ),
36 | body: Center(
37 | child: FutureBuilder(
38 | future: controller.init(),
39 | builder: (context, snapshot) {
40 | if (snapshot.connectionState == ConnectionState.done) {
41 | return Video(
42 | controller: VideoController(
43 | PlayersSingleton().player!,
44 | configuration: VideoControllerConfiguration(
45 | enableHardwareAcceleration: SettingsUtil.getValue(
46 | SettingsStorageKeys.isHardwareDecode,
47 | defaultValue: true)),
48 | ),
49 | );
50 | } else {
51 | return const CircularProgressIndicator();
52 | }
53 | },
54 | )));
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/pages/bili_video/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/pages/bili_video/widgets/bili_video_player/bili_danmaku.dart';
2 | import 'package:bili_you/pages/bili_video/widgets/bili_video_player/bili_video_player.dart';
3 | import 'package:bili_you/pages/bili_video/widgets/bili_video_player/bili_video_player_panel.dart';
4 | import 'package:bili_you/pages/bili_video/widgets/reply/index.dart';
5 | import 'package:flutter/material.dart';
6 | import 'package:get/get.dart';
7 |
8 | class BiliVideoController extends GetxController
9 | with GetTickerProviderStateMixin {
10 | BiliVideoController({
11 | required this.bvid,
12 | required this.cid,
13 | this.ssid,
14 | this.progress,
15 | required this.isBangumi,
16 | });
17 | String bvid;
18 | late String oldBvid;
19 | int cid;
20 | int? ssid;
21 | int? progress;
22 | bool isBangumi;
23 |
24 | late BiliVideoPlayerController biliVideoPlayerController;
25 | late BiliVideoPlayerPanelController biliVideoPlayerPanelController;
26 | late BiliDanmakuController biliDanmakuController;
27 | late final TabController tabController;
28 |
29 | Future changeVideoPart(String bvid, int cid) async {
30 | this.cid = cid;
31 | this.bvid = bvid;
32 | biliVideoPlayerController.bvid = bvid;
33 | biliVideoPlayerController.cid = cid;
34 | await biliVideoPlayerController.changeCid(bvid, cid);
35 | }
36 |
37 | refreshReply() {
38 | Get.find(tag: 'ReplyPage:$oldBvid').bvid = bvid;
39 | Get.find(tag: 'ReplyPage:$oldBvid')
40 | .refreshController
41 | .callRefresh();
42 | }
43 |
44 | @override
45 | void onInit() {
46 | oldBvid = bvid;
47 | tabController = TabController(
48 | length: 2,
49 | vsync: this,
50 | animationDuration: const Duration(milliseconds: 200));
51 | biliVideoPlayerController = BiliVideoPlayerController(
52 | bvid: bvid,
53 | cid: cid,
54 | initVideoPosition:
55 | progress != null ? Duration(seconds: progress!) : Duration.zero);
56 | biliVideoPlayerPanelController =
57 | BiliVideoPlayerPanelController(biliVideoPlayerController);
58 | biliDanmakuController = BiliDanmakuController(biliVideoPlayerController);
59 | super.onInit();
60 | }
61 |
62 | @override
63 | void onClose() {
64 | biliVideoPlayerController.dispose();
65 | super.onClose();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/pages/bili_video/index.dart:
--------------------------------------------------------------------------------
1 | library video_play;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/bili_video/widgets/introduction/index.dart:
--------------------------------------------------------------------------------
1 | library introduction;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/bili_video/widgets/reply/index.dart:
--------------------------------------------------------------------------------
1 | library reply;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/bili_video1/bili_media_content.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/video/video_play_info.dart';
2 |
3 | class BiliMediaContent extends VideoPlayInfo {
4 | BiliMediaContent(
5 | {required super.supportVideoQualities,
6 | required super.supportAudioQualities,
7 | required super.timeLength,
8 | required super.videos,
9 | required super.audios,
10 | required super.lastPlayCid,
11 | required super.lastPlayTime,
12 | required super.minBufferTime});
13 | }
14 |
--------------------------------------------------------------------------------
/lib/pages/bili_video1/bili_media_content_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/pages/bili_video1/bili_media_content.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 |
4 | class BiliMediaContentCubit extends Cubit {
5 | BiliMediaContentCubit(super.initialState);
6 | }
7 |
--------------------------------------------------------------------------------
/lib/pages/bili_video1/bili_media_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/index.dart';
2 | import 'package:bili_you/common/utils/index.dart';
3 |
4 | import 'package:flutter_bloc/flutter_bloc.dart';
5 |
6 | import 'bili_media_content.dart';
7 |
8 | class BiliMedia {
9 | String bvid;
10 | int cid;
11 | int? ssid;
12 | int? epid;
13 | bool isBangumi;
14 | int? progress;
15 | String? cover;
16 |
17 | BiliMedia(
18 | {required this.bvid,
19 | required this.cid,
20 | this.ssid,
21 | this.epid,
22 | this.isBangumi = false,
23 | this.progress,
24 | this.cover});
25 | }
26 |
27 | class BiliMediaCubit extends Cubit {
28 | BiliMediaCubit(super.initialState);
29 | Future getVideoPlayInfo() async {
30 | var videoPlayInfo =
31 | await VideoPlayApi.getVideoPlay(bvid: state.bvid, cid: state.cid);
32 | //找出最符合设置的清晰度/解码格式
33 | var seletedVideoQuality = SettingsUtil.getPreferVideoQuality();
34 | var seletedAudioQuality = SettingsUtil.getPreferAudioQuality();
35 | var seletedVideoCodec = SettingsUtil.getPreferVideoCodec();
36 | for (var i in videoPlayInfo.videos) {}
37 | return videoPlayInfo as BiliMediaContent;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/pages/dynamic/index.dart:
--------------------------------------------------------------------------------
1 | library dynamic;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/dynamic/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/widget/simple_easy_refresher.dart';
2 | import 'package:bili_you/pages/dynamic/widget/dynamic_author_filter.dart';
3 | import 'package:bili_you/pages/dynamic/widget/dynamic_item_card.dart';
4 | import 'package:easy_refresh/easy_refresh.dart';
5 | import 'package:flutter/material.dart';
6 | import 'package:get/get.dart';
7 |
8 | import 'index.dart';
9 |
10 | class DynamicPage extends StatefulWidget {
11 | const DynamicPage({Key? key}) : super(key: key);
12 |
13 | @override
14 | State createState() => _DynamicPageState();
15 | }
16 |
17 | class _DynamicPageState extends State {
18 | late final DynamicController controller;
19 | @override
20 | void initState() {
21 | controller = Get.put(DynamicController());
22 | super.initState();
23 | }
24 |
25 | @override
26 | void dispose() {
27 | controller.dispose();
28 | super.dispose();
29 | }
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return Scaffold(
34 | appBar: AppBar(title: const Text("动态")),
35 | body: SimpleEasyRefresher(
36 | easyRefreshController: controller.refreshController,
37 | indicatorPosition: IndicatorPosition.locator,
38 | childBuilder: (context, physics) => CustomScrollView(
39 | cacheExtent: MediaQuery.of(context).size.height,
40 | controller: controller.scrollController,
41 | physics: physics,
42 | slivers: [
43 | //up主面板
44 | DynamicAuthorFilter(
45 | authors: controller.dynamicAuthorList,
46 | onAuthorFilterApplied: controller.applyAuthorFilter,
47 | ),
48 | const HeaderLocator.sliver(),
49 | //動態内容卡片
50 | SliverList.builder(
51 | itemCount: controller.dynamicItems.length,
52 | itemBuilder: (context, index) =>
53 | DynamicItemCard(dynamicItem: controller.dynamicItems[index]),
54 | ),
55 | const FooterLocator.sliver(),
56 | ],
57 | ),
58 | onLoad: controller.onLoad,
59 | onRefresh: controller.onRefresh,
60 | ));
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/pages/dynamic/widget/dynamic_article.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/models/local/dynamic/dynamic_content.dart';
2 | import 'package:bili_you/common/widget/foldable_text.dart';
3 | import 'package:bili_you/pages/dynamic/widget/dynamic_draw.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class DynamicArticleWidget extends StatelessWidget {
7 | const DynamicArticleWidget({super.key, required this.content});
8 | final ArticleDynamicContent content;
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | ///TODO: 跳转到文章
13 | return Column(
14 | crossAxisAlignment: CrossAxisAlignment.start,
15 | children: [
16 | Text(content.title,
17 | style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold)),
18 | if ((content.title.isNotEmpty && content.text.isNotEmpty))
19 | const Padding(padding: EdgeInsets.only(top: 4)),
20 | SelectableRegion(
21 | magnifierConfiguration: const TextMagnifierConfiguration(),
22 | focusNode: FocusNode(),
23 | selectionControls: MaterialTextSelectionControls(),
24 | child: FoldableText.rich(
25 | TextSpan(text: content.text),
26 | maxLines: 6,
27 | folderTextStyle:
28 | TextStyle(color: Theme.of(context).colorScheme.primary),
29 | style: const TextStyle(fontSize: 15),
30 | )),
31 | if ((content.title.isNotEmpty || content.text.isNotEmpty) &&
32 | content.draws.isNotEmpty)
33 | const Padding(padding: EdgeInsets.only(top: 4)),
34 | DynamicDrawWidget(
35 | content: DrawDynamicContent(
36 | description: content.description,
37 | emotes: content.emotes,
38 | draws: content.draws)),
39 | ],
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/pages/history/history_controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 |
3 | import 'package:bili_you/common/api/history_api.dart';
4 | import 'package:bili_you/common/models/local/history/video_view_history_item.dart';
5 | import 'package:bili_you/common/values/index.dart';
6 | import 'package:easy_refresh/easy_refresh.dart';
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_cache_manager/flutter_cache_manager.dart';
9 | import 'package:get/get.dart';
10 |
11 | class HistoryController extends GetxController {
12 | HistoryController();
13 | EasyRefreshController easyRefreshController = EasyRefreshController(
14 | controlFinishLoad: true, controlFinishRefresh: true);
15 | int max = 0;
16 | int viewAt = 0;
17 | ScrollController scrollController = ScrollController();
18 | List videoViewHistoryItems = [];
19 | CacheManager cacheManager = CacheUtils.searchResultItemCoverCacheManager;
20 |
21 | Future _loadVideoViewHistoryItemList() async {
22 | late List list;
23 | try {
24 | if (max == 0 && viewAt == 0) {
25 | list = await HistoryApi.getVideoViewHistory();
26 | } else {
27 | list = await HistoryApi.getVideoViewHistory(max: max, viewAt: viewAt);
28 | }
29 | if (list.isNotEmpty) {
30 | max = list.last.oid;
31 | viewAt = list.last.viewAt;
32 | }
33 | } catch (e) {
34 | log(e.toString());
35 | return false;
36 | }
37 | videoViewHistoryItems.addAll(list);
38 | return true;
39 | }
40 | Future onLoad() async {
41 | if (await _loadVideoViewHistoryItemList()) {
42 | easyRefreshController.finishLoad(IndicatorResult.success);
43 | easyRefreshController.resetFooter();
44 | } else {
45 | easyRefreshController.finishLoad(IndicatorResult.fail);
46 | }
47 | }
48 |
49 | Future onRefresh() async {
50 | videoViewHistoryItems.clear();
51 | max = 0;
52 | viewAt = 0;
53 | await cacheManager.emptyCache();
54 | if (await _loadVideoViewHistoryItemList()) {
55 | easyRefreshController.finishRefresh(IndicatorResult.success);
56 | } else {
57 | easyRefreshController.finishRefresh(IndicatorResult.fail);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/pages/history/history_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/values/hero_tag_id.dart';
2 | import 'package:bili_you/common/widget/simple_easy_refresher.dart';
3 | import 'package:bili_you/common/widget/video_view_history_tile.dart';
4 | import 'package:bili_you/pages/history/history_controller.dart';
5 | import 'package:flutter/material.dart';
6 | import 'package:get/get.dart';
7 |
8 | class HistoryPage extends StatefulWidget {
9 | const HistoryPage({super.key});
10 |
11 | @override
12 | State createState() => _HistoryPageState();
13 | }
14 |
15 | class _HistoryPageState extends State {
16 | late HistoryController controller;
17 | @override
18 | void initState() {
19 | controller = Get.put(HistoryController());
20 | super.initState();
21 | }
22 |
23 | @override
24 | void dispose() {
25 | controller.dispose();
26 | super.dispose();
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | return Scaffold(
32 | appBar: AppBar(title: const Text('历史记录')),
33 | body: SimpleEasyRefresher(
34 | onLoad: controller.onLoad, //加載更多
35 | onRefresh: controller.onRefresh, //刷新
36 | easyRefreshController: controller.easyRefreshController,
37 | childBuilder: (context, physics) => ListView.builder(
38 | padding: const EdgeInsets.all(12),
39 | addAutomaticKeepAlives: false,
40 | addRepaintBoundaries: false,
41 | physics: physics,
42 | itemCount: controller.videoViewHistoryItems.length,
43 | controller: controller.scrollController,
44 | itemBuilder: (context, index) => Padding(
45 | padding: const EdgeInsets.only(bottom: 10),
46 | child: VideoViewHistoryTile(
47 | videoViewHistoryItem: controller.videoViewHistoryItems[index],
48 | cacheManager: controller.cacheManager,
49 | heroTagId: HeroTagId.id++),
50 | ),
51 | ),
52 | ),
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/pages/home/index.dart:
--------------------------------------------------------------------------------
1 | library home;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/home/widgets/user_menu/index.dart:
--------------------------------------------------------------------------------
1 | library user_face;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/live_tab_page/controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 |
3 | import 'package:bili_you/common/api/live_api.dart';
4 | import 'package:bili_you/common/models/local/live/live_room_card_info.dart';
5 | import 'package:bili_you/common/utils/bili_you_storage.dart';
6 | import 'package:bili_you/common/utils/settings.dart';
7 | import 'package:easy_refresh/easy_refresh.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:get/get.dart';
10 |
11 | class LiveTabPageController extends GetxController {
12 | var refreshController = EasyRefreshController(
13 | controlFinishLoad: true, controlFinishRefresh: true);
14 | var scrollController = ScrollController();
15 | int currentPageNum = 1;
16 | RxList infoList = [].obs;
17 | int columnCount = 2;
18 | @override
19 | void onInit() {
20 | columnCount = SettingsUtil.getValue(
21 | SettingsStorageKeys.recommendColumnCount,
22 | defaultValue: 2);
23 | super.onInit();
24 | }
25 |
26 | void animateToTop() {
27 | scrollController.animateTo(0,
28 | duration: const Duration(milliseconds: 500), curve: Curves.linear);
29 | }
30 |
31 | Future _loadInfos() async {
32 | try {
33 | infoList.addAll(await LiveApi.getUserRecommendLive(
34 | pageNum: currentPageNum, pageSize: 30));
35 | currentPageNum++;
36 | return true;
37 | } catch (e) {
38 | log("LiveTabPageController:$e");
39 | }
40 | return false;
41 | }
42 |
43 | Future onRefresh() async {
44 | infoList.clear();
45 | currentPageNum = 1;
46 | if (await _loadInfos()) {
47 | refreshController.finishRefresh(IndicatorResult.success);
48 | } else {
49 | refreshController.finishRefresh(IndicatorResult.fail);
50 | }
51 | }
52 |
53 | Future onLoad() async {
54 | if (await _loadInfos()) {
55 | refreshController.finishLoad(IndicatorResult.success);
56 | } else {
57 | refreshController.finishLoad(IndicatorResult.fail);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/pages/live_tab_page/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/values/hero_tag_id.dart';
2 | import 'package:bili_you/common/widget/live_room_card.dart';
3 | import 'package:bili_you/common/widget/simple_easy_refresher.dart';
4 | import 'package:bili_you/pages/live_tab_page/controller.dart';
5 | import 'package:flutter/widgets.dart';
6 | import 'package:get/get.dart';
7 |
8 | class LiveTabPage extends StatefulWidget {
9 | const LiveTabPage({super.key});
10 |
11 | @override
12 | State createState() => _LiveTabPageState();
13 | }
14 |
15 | class _LiveTabPageState extends State
16 | with AutomaticKeepAliveClientMixin {
17 | late LiveTabPageController controller;
18 | @override
19 | void initState() {
20 | controller = Get.put(LiveTabPageController());
21 | super.initState();
22 | }
23 |
24 | @override
25 | void dispose() {
26 | controller.dispose();
27 | super.dispose();
28 | }
29 |
30 | @override
31 | Widget build(BuildContext context) {
32 | super.build(context);
33 | return SimpleEasyRefresher(
34 | onRefresh: controller.onRefresh,
35 | onLoad: controller.onLoad,
36 | easyRefreshController: controller.refreshController,
37 | childBuilder: (context, physics) => GridView.builder(
38 | controller: controller.scrollController,
39 | physics: physics,
40 | padding: const EdgeInsets.all(12),
41 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
42 | crossAxisSpacing: 12,
43 | mainAxisSpacing: 12,
44 | crossAxisCount: controller.columnCount,
45 | mainAxisExtent: (MediaQuery.of(context).size.width /
46 | controller.columnCount) *
47 | 10 /
48 | 16 +
49 | 45 * MediaQuery.of(context).textScaleFactor),
50 | itemCount: controller.infoList.length,
51 | itemBuilder: (context, index) => LiveRoomCard(
52 | info: controller.infoList[index], heroTagId: HeroTagId.id++),
53 | ));
54 | }
55 |
56 | @override
57 | bool get wantKeepAlive => true;
58 | }
59 |
--------------------------------------------------------------------------------
/lib/pages/login/password_login/index.dart:
--------------------------------------------------------------------------------
1 | library password_login;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/login/password_login/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import 'index.dart';
5 |
6 | class PasswordLoginPage extends GetView {
7 | const PasswordLoginPage({Key? key}) : super(key: key);
8 |
9 | // 主视图
10 | Widget _buildView(context) {
11 | var outlineInputBorder = OutlineInputBorder(
12 | borderRadius: const BorderRadius.all(Radius.circular(10)),
13 | borderSide: BorderSide(color: Theme.of(context).colorScheme.outline));
14 | return Padding(
15 | padding: const EdgeInsets.all(20),
16 | child: Center(
17 | child: Column(children: [
18 | const SizedBox(
19 | height: 20,
20 | ),
21 | TextField(
22 | onChanged: (value) {
23 | controller.account = value;
24 | },
25 | decoration:
26 | InputDecoration(labelText: "账号", border: outlineInputBorder),
27 | ),
28 | const SizedBox(
29 | height: 20,
30 | ),
31 | TextField(
32 | onChanged: (value) {
33 | controller.password = value;
34 | },
35 | decoration:
36 | InputDecoration(labelText: "密码", border: outlineInputBorder),
37 | ),
38 | const SizedBox(
39 | height: 20,
40 | ),
41 | OutlinedButton(
42 | onPressed: () {
43 | controller.startLogin();
44 | },
45 | child: const Text("登录"))
46 | ]),
47 | ),
48 | );
49 | }
50 |
51 | @override
52 | Widget build(BuildContext context) {
53 | return GetBuilder(
54 | init: PasswordLoginController(),
55 | id: "password_login",
56 | builder: (_) {
57 | return Scaffold(
58 | appBar: AppBar(title: const Text("密码登录")),
59 | body: _buildView(context),
60 | );
61 | },
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/pages/login/qrcode_login/controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:developer';
3 |
4 | import 'package:bili_you/common/api/index.dart';
5 | import 'package:bili_you/common/models/local/login/login_qrcode_info.dart';
6 | import 'package:bili_you/common/models/local/login/login_qrcode_stat.dart';
7 | import 'package:bili_you/pages/login/controller.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:get/get.dart';
10 |
11 | class QRcodeLoginController extends GetxController {
12 | late LoginQrcodeStat stat;
13 | late LoginQRcodeInfo info;
14 | Timer? timer;
15 |
16 | Future getQRcodeInfo() async {
17 | timer?.cancel();
18 | timer = null;
19 | info = await LoginApi.getQRcode();
20 |
21 | ///每秒钟检查是否扫码登录成功
22 | timer = Timer.periodic(const Duration(seconds: 1), (timer) async {
23 | log('a');
24 | stat = await LoginApi.checkQRcodeLogin(qrcodeKey: info.qrcodeKey);
25 | if (stat == LoginQrcodeStat.loginSuccess) {
26 | //成功时
27 | await onLoginSuccess(await LoginApi.getLoginUserInfo(),
28 | await LoginApi.getLoginUserStat());
29 | Navigator.of(Get.context!).popUntil((route) => route.isFirst);
30 | await Get.rawSnackbar(message: "登录成功!").show();
31 | } else if (stat == LoginQrcodeStat.qrcodeInvalid) {
32 | //二维码失效时,弹出提示
33 | await Get.rawSnackbar(message: "二维码失效!请点击二维码进行刷新!").show();
34 | }
35 | });
36 | }
37 |
38 | ///手动检查登录状态
39 | Future checkQRcodeLoginStat() async {
40 | stat = await LoginApi.checkQRcodeLogin(qrcodeKey: info.qrcodeKey);
41 | if (stat == LoginQrcodeStat.loginSuccess) {
42 | await onLoginSuccess(
43 | await LoginApi.getLoginUserInfo(), await LoginApi.getLoginUserStat());
44 | Navigator.of(Get.context!).popUntil((route) => route.isFirst);
45 | await Get.rawSnackbar(message: "登录成功!").show();
46 | } else {
47 | await Get.rawSnackbar(message: stat.message).show();
48 | }
49 | }
50 |
51 | @override
52 | void onClose() {
53 | timer?.cancel();
54 | timer = null;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/pages/login/qrcode_login/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/pages/login/qrcode_login/controller.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:get/get.dart';
4 | import 'package:qr_flutter/qr_flutter.dart';
5 |
6 | class QrcodeLogin extends StatefulWidget {
7 | const QrcodeLogin({super.key});
8 |
9 | @override
10 | State createState() => _QrcodeLoginState();
11 | }
12 |
13 | class _QrcodeLoginState extends State {
14 | late final QRcodeLoginController controller;
15 | @override
16 | void initState() {
17 | controller = Get.put(QRcodeLoginController());
18 | super.initState();
19 | }
20 |
21 | @override
22 | void dispose() {
23 | controller.dispose();
24 | super.dispose();
25 | }
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return Scaffold(
30 | appBar: AppBar(
31 | title: const Text('二维码登录'),
32 | actions: [
33 | TextButton(
34 | onPressed: () async {
35 | await controller.checkQRcodeLoginStat();
36 | },
37 | child: const Text("手动检查登录状态")),
38 | ],
39 | ),
40 | body: FutureBuilder(
41 | future: controller.getQRcodeInfo(),
42 | builder: (context, snapshot) {
43 | if (snapshot.connectionState == ConnectionState.done) {
44 | return GestureDetector(
45 | child: QrImageView(
46 | data: controller.info.url,
47 | backgroundColor: Colors.white,
48 | ),
49 | onTap: () {
50 | setState(() {});
51 | },
52 | );
53 | } else {
54 | return const CircularProgressIndicator();
55 | }
56 | },
57 | ),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/pages/login/sms_login/index.dart:
--------------------------------------------------------------------------------
1 | library phone_login;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/login/sms_login/widgets/error/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class ErrorController extends GetxController {
4 | ErrorController();
5 |
6 | _initData() {
7 | update(["error"]);
8 | }
9 |
10 | void onTap() {}
11 |
12 | // @override
13 | // void onInit() {
14 | // super.onInit();
15 | // }
16 |
17 | @override
18 | void onReady() {
19 | super.onReady();
20 | _initData();
21 | }
22 |
23 | // @override
24 | // void onClose() {
25 | // super.onClose();
26 | // }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/pages/login/sms_login/widgets/error/index.dart:
--------------------------------------------------------------------------------
1 | library error;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/login/sms_login/widgets/error/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import 'index.dart';
5 |
6 | class ErrorPage extends GetView {
7 | const ErrorPage({Key? key, required this.message}) : super(key: key);
8 | final String message;
9 |
10 | // 主视图
11 | Widget _buildView() {
12 | return Center(
13 | child: Text(message),
14 | );
15 | }
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return GetBuilder(
20 | init: ErrorController(),
21 | id: "error",
22 | builder: (_) {
23 | return Scaffold(
24 | appBar: AppBar(title: const Text("错误")),
25 | body: SafeArea(
26 | child: _buildView(),
27 | ),
28 | );
29 | },
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/pages/main/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import '../home/view.dart';
4 | import '../dynamic/view.dart';
5 |
6 | class MainController extends GetxController {
7 | MainController();
8 | var selectedIndex = 0.obs;
9 |
10 | List pages = [
11 | const HomePage(),
12 | const DynamicPage(),
13 | ];
14 |
15 | _initData() {
16 | // update(["main"]);
17 | }
18 |
19 | void onTap() {}
20 |
21 | // @override
22 | // void onInit() {
23 | // super.onInit();
24 | // }
25 |
26 | @override
27 | void onReady() {
28 | super.onReady();
29 | _initData();
30 | }
31 |
32 | // @override
33 | // void onClose() {
34 | // super.onClose();
35 | // }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/pages/main/index.dart:
--------------------------------------------------------------------------------
1 | library main;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/popular_video/controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 |
3 | import 'package:bili_you/common/api/index.dart';
4 | import 'package:bili_you/common/models/local/video_tile/video_tile_info.dart';
5 | import 'package:easy_refresh/easy_refresh.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:get/get.dart';
8 |
9 | class PopularVideoController extends GetxController {
10 | PopularVideoController();
11 | var refreshController = EasyRefreshController(
12 | controlFinishLoad: true, controlFinishRefresh: true);
13 | var scrollController = ScrollController();
14 | int currentPageNum = 1;
15 | RxList infoList = [].obs;
16 |
17 | void animateToTop() {
18 | scrollController.animateTo(0,
19 | duration: const Duration(milliseconds: 500), curve: Curves.linear);
20 | }
21 |
22 | Future _loadInfos() async {
23 | try {
24 | infoList.addAll(await HomeApi.getPopularVideos(pageNum: currentPageNum));
25 | currentPageNum++;
26 | return true;
27 | } catch (e) {
28 | log("PopularVideoController:$e");
29 | }
30 | return false;
31 | }
32 |
33 | Future onRefresh() async {
34 | infoList.clear();
35 | currentPageNum = 1;
36 | if (await _loadInfos()) {
37 | refreshController.finishRefresh(IndicatorResult.success);
38 | } else {
39 | refreshController.finishRefresh(IndicatorResult.fail);
40 | }
41 | }
42 |
43 | Future onLoad() async {
44 | if (await _loadInfos()) {
45 | refreshController.finishLoad(IndicatorResult.success);
46 | } else {
47 | refreshController.finishLoad(IndicatorResult.fail);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/pages/popular_video/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/values/hero_tag_id.dart';
2 | import 'package:bili_you/common/widget/simple_easy_refresher.dart';
3 | import 'package:bili_you/index.dart';
4 | import 'package:bili_you/pages/bili_video/view.dart';
5 | import 'package:bili_you/pages/popular_video/controller.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:get/get.dart';
8 |
9 | class PopularVideoPage extends StatefulWidget {
10 | const PopularVideoPage({super.key});
11 |
12 | @override
13 | State createState() => _PopularVideoPageState();
14 | }
15 |
16 | class _PopularVideoPageState extends State
17 | with AutomaticKeepAliveClientMixin {
18 | late PopularVideoController controller;
19 |
20 | @override
21 | void initState() {
22 | controller = Get.put(PopularVideoController());
23 | super.initState();
24 | }
25 |
26 | @override
27 | void dispose() {
28 | controller.dispose();
29 | super.dispose();
30 | }
31 |
32 | @override
33 | Widget build(BuildContext context) {
34 | super.build(context);
35 | return SimpleEasyRefresher(
36 | onRefresh: controller.onRefresh,
37 | onLoad: controller.onLoad,
38 | easyRefreshController: controller.refreshController,
39 | childBuilder: (context, physics) => ListView.builder(
40 | padding: const EdgeInsets.all(12),
41 | controller: controller.scrollController,
42 | itemCount: controller.infoList.length,
43 | physics: physics,
44 | itemBuilder: (context, index) {
45 | var i = controller.infoList[index];
46 | var heroTagId = HeroTagId.id++;
47 | return Padding(
48 | padding: const EdgeInsets.only(bottom: 10),
49 | child: VideoTileItem.fromVideoTileInfo(i,
50 | cacheManager: CacheUtils.relatedVideosItemCoverCacheManager,
51 | heroTagId: heroTagId, onTap: (context) {
52 | HeroTagId.lastId = heroTagId;
53 | Navigator.of(context).push(GetPageRoute(
54 | page: () => BiliVideoPage(
55 | key: ValueKey("BiliVideoPage:${i.bvid}"),
56 | bvid: i.bvid,
57 | cid: i.cid,
58 | ),
59 | ));
60 | }),
61 | );
62 | },
63 | ),
64 | );
65 | }
66 |
67 | @override
68 | bool get wantKeepAlive => true;
69 | }
70 |
--------------------------------------------------------------------------------
/lib/pages/recommend/controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 |
3 | import 'package:bili_you/common/models/local/home/recommend_item_info.dart';
4 | import 'package:bili_you/common/utils/index.dart';
5 | import 'package:bili_you/common/utils/cache_util.dart';
6 | import 'package:easy_refresh/easy_refresh.dart';
7 | import 'package:flutter/widgets.dart';
8 | import 'package:flutter_cache_manager/flutter_cache_manager.dart';
9 | import 'package:get/get.dart';
10 | import 'package:bili_you/common/api/home_api.dart';
11 |
12 | class RecommendController extends GetxController {
13 | RecommendController();
14 | List recommendItems = [];
15 |
16 | ScrollController scrollController = ScrollController();
17 | EasyRefreshController refreshController = EasyRefreshController(
18 | controlFinishLoad: true, controlFinishRefresh: true);
19 | int refreshIdx = 0;
20 | CacheManager cacheManager = CacheUtils.recommendItemCoverCacheManager;
21 | int recommendColumnCount = 2;
22 |
23 | @override
24 | void onInit() {
25 | recommendColumnCount = SettingsUtil.getValue(
26 | SettingsStorageKeys.recommendColumnCount,
27 | defaultValue: 2);
28 | super.onInit();
29 | }
30 |
31 | void animateToTop() {
32 | scrollController.animateTo(0,
33 | duration: const Duration(milliseconds: 500), curve: Curves.linear);
34 | }
35 |
36 | //加载并追加视频推荐
37 | Future _addRecommendItems() async {
38 | try {
39 | recommendItems.addAll(await HomeApi.getRecommendVideoItems(
40 | num: 30, refreshIdx: refreshIdx));
41 | } catch (e) {
42 | log("加载推荐视频失败:${e.toString()}");
43 | return false;
44 | }
45 | refreshIdx += 1;
46 | return true;
47 | }
48 |
49 | Future onRefresh() async {
50 | recommendItems.clear();
51 | await cacheManager.emptyCache();
52 | if (await _addRecommendItems()) {
53 | refreshController.finishRefresh(IndicatorResult.success);
54 | } else {
55 | refreshController.finishRefresh(IndicatorResult.fail);
56 | }
57 | }
58 |
59 | Future onLoad() async {
60 | if (await _addRecommendItems()) {
61 | refreshController.finishLoad(IndicatorResult.success);
62 | refreshController.resetFooter();
63 | } else {
64 | refreshController.finishLoad(IndicatorResult.fail);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/pages/recommend/index.dart:
--------------------------------------------------------------------------------
1 | library recommend;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/relation/controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 |
3 | import 'package:bili_you/common/api/realtions_api.dart';
4 | import 'package:bili_you/common/models/network/user_relations/user_realtion.dart';
5 | import 'package:bili_you/common/models/network/user_relations/user_relation_types.dart';
6 | import 'package:bili_you/common/values/index.dart';
7 | import 'package:easy_refresh/easy_refresh.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_cache_manager/flutter_cache_manager.dart';
10 | import 'package:get/get.dart';
11 |
12 | class RealtionController extends GetxController {
13 | RealtionController({required this.mid, required this.type});
14 | final int mid;
15 | final UserRelationType type;
16 |
17 | EasyRefreshController easyRefreshController = EasyRefreshController(
18 | controlFinishLoad: true, controlFinishRefresh: true);
19 |
20 | int ps = 20;
21 | int pn = 1;
22 |
23 | ScrollController scrollController = ScrollController();
24 | List relationsItems = [];
25 | CacheManager cacheManager = CacheUtils.searchResultItemCoverCacheManager;
26 |
27 | Future _loadList() async {
28 | late List list;
29 | try {
30 | switch (type) {
31 | case UserRelationType.following:
32 | list = await RelationApi.getFollowingList(vmid: mid, ps: ps, pn: pn);
33 | break;
34 | case UserRelationType.follower:
35 | list = await RelationApi.getFollowersList(vmid: mid, ps: ps, pn: pn);
36 | }
37 |
38 | pn++;
39 | } catch (e) {
40 | log(e.toString());
41 | return false;
42 | }
43 | relationsItems.addAll(list);
44 | return true;
45 | }
46 |
47 | Future onLoad() async {
48 | if (await _loadList()) {
49 | easyRefreshController.finishLoad(IndicatorResult.success);
50 | easyRefreshController.resetFooter();
51 | } else {
52 | easyRefreshController.finishLoad(IndicatorResult.fail);
53 | }
54 | }
55 |
56 | Future onRefresh() async {
57 | relationsItems.clear();
58 | pn = 1;
59 | await cacheManager.emptyCache();
60 | if (await _loadList()) {
61 | easyRefreshController.finishRefresh(IndicatorResult.success);
62 | } else {
63 | easyRefreshController.finishRefresh(IndicatorResult.fail);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/pages/relation/index.dart:
--------------------------------------------------------------------------------
1 | library following;
2 |
3 | export './controller.dart';
4 | export './view.dart';
--------------------------------------------------------------------------------
/lib/pages/search_input/index.dart:
--------------------------------------------------------------------------------
1 | library search;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/search_result/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/api/search_api.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:get/get.dart';
4 |
5 | class SearchResultController extends GetxController
6 | with GetSingleTickerProviderStateMixin {
7 | SearchResultController({required this.keyWord});
8 | late TabController tabController;
9 | static int searchResultCount = 0;
10 | //tagId用来给tab使用,使同一个搜索界面下tab的tagName可以确定,以便使用Get.find获得对应的controller
11 | final tagId = searchResultCount++;
12 | int currentSelectedTabIndex = 0;
13 | String keyWord;
14 |
15 | //根据tab的index获取该搜索页面下该tab的tagName
16 | String getTabTagNameByIndex(int index) {
17 | return '${SearchType.values[index].name}:$tagId';
18 | }
19 |
20 | @override
21 | void onInit() {
22 | tabController = TabController(
23 | length: 5, vsync: this, initialIndex: currentSelectedTabIndex);
24 | super.onInit();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/pages/search_result/index.dart:
--------------------------------------------------------------------------------
1 | library search_result;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/settings_page/others_settings_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/widget/settings_label.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:get/get.dart';
4 |
5 | import 'cache_management_page.dart';
6 |
7 | class OthersSettingsPage extends StatelessWidget {
8 | const OthersSettingsPage({super.key});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Scaffold(
13 | appBar: AppBar(
14 | title: const Text("其他设置"),
15 | ),
16 | body: ListView(children: [
17 | const SettingsLabel(
18 | text: '缓存',
19 | ),
20 | ListTile(
21 | title: const Text(
22 | "缓存管理",
23 | ),
24 | onTap: () {
25 | Navigator.of(context).push(GetPageRoute(
26 | page: () => const CacheManagementPage(),
27 | ));
28 | },
29 | )
30 | ]),
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/pages/settings_page/settings_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/pages/settings_page/appearance_settings_page.dart';
2 | import 'package:bili_you/pages/settings_page/common_settings_page.dart';
3 | import 'package:bili_you/pages/settings_page/others_settings_page.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:get/get.dart';
6 |
7 | class SettingsPage extends StatelessWidget {
8 | const SettingsPage({super.key});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | Color iconColor = Theme.of(context).colorScheme.primary;
13 | return Scaffold(
14 | appBar: AppBar(title: const Text("设置")),
15 | body: ListView(children: [
16 | ListTile(
17 | leading: Icon(Icons.tune_outlined, color: iconColor),
18 | title: const Text("通用"),
19 | onTap: () => Navigator.of(context).push(GetPageRoute(
20 | page: () => const CommonSettingsPage(),
21 | )),
22 | ),
23 | ListTile(
24 | leading: Icon(Icons.color_lens_outlined, color: iconColor),
25 | title: const Text("外观"),
26 | onTap: () => Navigator.of(context)
27 | .push(GetPageRoute(page: () => const AppearanceSettingsPage())),
28 | ),
29 | ListTile(
30 | leading: Icon(Icons.more_horiz_outlined, color: iconColor),
31 | title: const Text("其他"),
32 | onTap: () => Navigator.of(context).push(GetPageRoute(
33 | page: () => const OthersSettingsPage(),
34 | ))),
35 | ]),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/pages/splash/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class SplashController extends GetxController {
4 | SplashController();
5 |
6 | _initData() {
7 | // update(["splash"]);
8 | }
9 |
10 | void onTap() {}
11 |
12 | // @override
13 | // void onInit() {
14 | // super.onInit();
15 | // }
16 |
17 | @override
18 | void onReady() {
19 | super.onReady();
20 | _initData();
21 | }
22 |
23 | // @override
24 | // void onClose() {
25 | // super.onClose();
26 | // }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/pages/splash/index.dart:
--------------------------------------------------------------------------------
1 | library splash;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/splash/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:bili_you/pages/main/view.dart';
4 |
5 | import 'index.dart';
6 |
7 | class SplashPage extends GetView {
8 | const SplashPage({Key? key}) : super(key: key);
9 |
10 | Widget _buildView() {
11 | //暂时先不写splash屏画面,让它直接跳转到主页面
12 | return const MainPage();
13 | }
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return GetBuilder(
18 | init: SplashController(),
19 | id: "splash",
20 | builder: (splashController) {
21 | return _buildView();
22 | },
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/pages/ui_test/index.dart:
--------------------------------------------------------------------------------
1 | library ui_test;
2 |
3 | export './controller.dart';
4 | export './view.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/ui_test/test_widget/media_kit_test_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:bili_you/common/index.dart';
2 | import 'package:bili_you/common/utils/bvid_avid_util.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:media_kit/media_kit.dart';
5 | import 'package:media_kit_video/media_kit_video.dart';
6 |
7 | class BiliVideoPlayer extends StatefulWidget {
8 | const BiliVideoPlayer({super.key});
9 |
10 | @override
11 | State createState() => _BiliVideoPlayerState();
12 | }
13 |
14 | class _BiliVideoPlayerState extends State {
15 | final Player videopPlayer =
16 | Player(configuration: const PlayerConfiguration());
17 | VideoController? controller;
18 | @override
19 | void initState() {
20 | Future.microtask(() async {
21 | String bvid = BvidAvidUtil.av2Bvid(170001);
22 | var videoPlayerInfo = await VideoPlayApi.getVideoPlay(
23 | bvid: bvid, cid: await VideoInfoApi.getFirstCid(bvid: bvid));
24 | const String name = 'http-header-fields';
25 | var kvArray = [];
26 | VideoPlayApi.videoPlayerHttpHeaders
27 | .forEach((key, value) => kvArray.add('$key: $value'));
28 | final data = kvArray.join(',');
29 | if (videopPlayer.platform is libmpvPlayer) {
30 | await (videopPlayer.platform as libmpvPlayer).setProperty(name, data);
31 | await (videopPlayer.platform as libmpvPlayer).setProperty('audio-files',
32 | videoPlayerInfo.audios.first.urls.first.replaceAll(':', '\\:'));
33 | await videopPlayer.setVolume(100);
34 | await videopPlayer.open(Media(videoPlayerInfo.videos.first.urls.first));
35 | }
36 | controller = VideoController(
37 | videopPlayer,
38 | );
39 | await videopPlayer.play();
40 | setState(() {});
41 | });
42 | super.initState();
43 | }
44 |
45 | @override
46 | void dispose() {
47 | Future.microtask(() async {
48 | await videopPlayer.dispose();
49 | // controller?.dispose();
50 | });
51 | super.dispose();
52 | }
53 |
54 | @override
55 | Widget build(BuildContext context) {
56 | return Video(controller: controller!);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/pages/ui_test/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import 'index.dart';
5 |
6 | class UiTestPage extends StatefulWidget {
7 | const UiTestPage({Key? key}) : super(key: key);
8 |
9 | @override
10 | State createState() => _UiTestPageState();
11 | }
12 |
13 | class _UiTestPageState extends State {
14 | late final UiTestController controller;
15 | @override
16 | void initState() {
17 | controller = Get.put(UiTestController());
18 | super.initState();
19 | }
20 |
21 | @override
22 | void dispose() {
23 | controller.dispose();
24 | super.dispose();
25 | }
26 |
27 | Widget _buildView(BuildContext context) {
28 | return ListView.builder(
29 | itemCount: controller.listTiles.length,
30 | itemBuilder: (context, index) => controller.listTiles[index],
31 | );
32 | }
33 |
34 | @override
35 | Widget build(BuildContext context) {
36 | return Scaffold(
37 | appBar: AppBar(title: const Text("ui_test")),
38 | body: _buildView(context),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/pages/user_space/controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 |
3 | import 'package:bili_you/common/api/user_space_api.dart';
4 | import 'package:bili_you/common/models/local/user_space/user_video_search.dart';
5 | import 'package:bili_you/common/utils/cache_util.dart';
6 | import 'package:easy_refresh/easy_refresh.dart';
7 | import 'package:flutter_cache_manager/flutter_cache_manager.dart';
8 | import 'package:get/get.dart';
9 |
10 | class UserSpacePageController extends GetxController {
11 | UserSpacePageController({required this.mid});
12 | EasyRefreshController refreshController = EasyRefreshController(
13 | controlFinishLoad: true, controlFinishRefresh: true);
14 | CacheManager cacheManager = CacheUtils.searchResultItemCoverCacheManager;
15 | final int mid;
16 | int currentPage = 1;
17 | List searchItems = [];
18 |
19 | Future loadVideoItemWidgtLists() async {
20 | late UserVideoSearch userVideoSearch;
21 | try {
22 | userVideoSearch =
23 | await UserSpaceApi.getUserVideoSearch(mid: mid, pageNum: currentPage);
24 | } catch (e) {
25 | log("loadVideoItemWidgtLists:$e");
26 | return false;
27 | }
28 | searchItems.addAll(userVideoSearch.videos);
29 | currentPage++;
30 | return true;
31 | }
32 |
33 | Future onLoad() async {
34 | if (await loadVideoItemWidgtLists()) {
35 | refreshController.finishLoad(IndicatorResult.success);
36 | refreshController.resetFooter();
37 | } else {
38 | refreshController.finishLoad(IndicatorResult.fail);
39 | }
40 | }
41 |
42 | Future onRefresh() async {
43 | await cacheManager.emptyCache();
44 | searchItems.clear();
45 | currentPage = 1;
46 | bool success = await loadVideoItemWidgtLists();
47 | if (success) {
48 | refreshController.finishRefresh(IndicatorResult.success);
49 | } else {
50 | refreshController.finishRefresh(IndicatorResult.fail);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/linux/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral
2 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | void fl_register_plugins(FlPluginRegistry* registry) {
15 | g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
16 | fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin");
17 | dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);
18 | g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar =
19 | fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin");
20 | media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar);
21 | g_autoptr(FlPluginRegistrar) media_kit_video_registrar =
22 | fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin");
23 | media_kit_video_plugin_register_with_registrar(media_kit_video_registrar);
24 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
25 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
26 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
27 | }
28 |
--------------------------------------------------------------------------------
/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 | dynamic_color
7 | media_kit_libs_linux
8 | media_kit_video
9 | url_launcher_linux
10 | )
11 |
12 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
13 | media_kit_native_event_loop
14 | )
15 |
16 | set(PLUGIN_BUNDLED_LIBRARIES)
17 |
18 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
19 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
20 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
23 | endforeach(plugin)
24 |
25 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
26 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
27 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
28 | endforeach(ffi_plugin)
29 |
--------------------------------------------------------------------------------
/linux/main.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | int main(int argc, char** argv) {
4 | g_autoptr(MyApplication) app = my_application_new();
5 | return g_application_run(G_APPLICATION(app), argc, argv);
6 | }
7 |
--------------------------------------------------------------------------------
/linux/my_application.h:
--------------------------------------------------------------------------------
1 | #ifndef FLUTTER_MY_APPLICATION_H_
2 | #define FLUTTER_MY_APPLICATION_H_
3 |
4 | #include
5 |
6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 | GtkApplication)
8 |
9 | /**
10 | * my_application_new:
11 | *
12 | * Creates a new Flutter-based application.
13 | *
14 | * Returns: a new #MyApplication.
15 | */
16 | MyApplication* my_application_new();
17 |
18 | #endif // FLUTTER_MY_APPLICATION_H_
19 |
--------------------------------------------------------------------------------
/macos/-configuration:
--------------------------------------------------------------------------------
1 | Command line invocation:
2 | /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -project Runner.xcodeproj -scheme bili_you Release
3 |
4 | User defaults from command line:
5 | IDEPackageSupportUseBuiltinSCM = YES
6 |
7 |
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/dgph
7 | **/xcuserdata/
8 |
--------------------------------------------------------------------------------
/macos/.xcodeproj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/macos/.xcodeproj
--------------------------------------------------------------------------------
/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/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 | import connectivity_plus
9 | import device_info_plus
10 | import dynamic_color
11 | import media_kit_libs_macos_video
12 | import media_kit_video
13 | import package_info_plus
14 | import path_provider_foundation
15 | import screen_brightness_macos
16 | import share_plus
17 | import sqflite
18 | import url_launcher_macos
19 | import wakelock_plus
20 |
21 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
22 | ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
23 | DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
24 | DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
25 | MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
26 | MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
27 | FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
28 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
29 | ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin"))
30 | SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
31 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
32 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
33 | WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
34 | }
35 |
--------------------------------------------------------------------------------
/macos/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '11.0'
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 | target 'RunnerTests' do
35 | inherit! :search_paths
36 | end
37 | end
38 |
39 | post_install do |installer|
40 | installer.pods_project.targets.each do |target|
41 | flutter_additional_macos_build_settings(target)
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/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/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "version": 1,
4 | "author": "xcode"
5 | },
6 | "images": [
7 | {
8 | "size": "16x16",
9 | "idiom": "mac",
10 | "filename": "app_icon_16.png",
11 | "scale": "1x"
12 | },
13 | {
14 | "size": "16x16",
15 | "idiom": "mac",
16 | "filename": "app_icon_32.png",
17 | "scale": "2x"
18 | },
19 | {
20 | "size": "32x32",
21 | "idiom": "mac",
22 | "filename": "app_icon_32.png",
23 | "scale": "1x"
24 | },
25 | {
26 | "size": "32x32",
27 | "idiom": "mac",
28 | "filename": "app_icon_64.png",
29 | "scale": "2x"
30 | },
31 | {
32 | "size": "128x128",
33 | "idiom": "mac",
34 | "filename": "app_icon_128.png",
35 | "scale": "1x"
36 | },
37 | {
38 | "size": "128x128",
39 | "idiom": "mac",
40 | "filename": "app_icon_256.png",
41 | "scale": "2x"
42 | },
43 | {
44 | "size": "256x256",
45 | "idiom": "mac",
46 | "filename": "app_icon_256.png",
47 | "scale": "1x"
48 | },
49 | {
50 | "size": "256x256",
51 | "idiom": "mac",
52 | "filename": "app_icon_512.png",
53 | "scale": "2x"
54 | },
55 | {
56 | "size": "512x512",
57 | "idiom": "mac",
58 | "filename": "app_icon_512.png",
59 | "scale": "1x"
60 | },
61 | {
62 | "size": "512x512",
63 | "idiom": "mac",
64 | "filename": "app_icon_1024.png",
65 | "scale": "2x"
66 | }
67 | ]
68 | }
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/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 = bili_you
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.lucinhu.biliYou
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.lucinhu. 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.client
10 |
11 | com.apple.security.network.server
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/macos/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | $(PRODUCT_COPYRIGHT)
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 |
32 |
33 |
--------------------------------------------------------------------------------
/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/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 |
12 |
13 |
--------------------------------------------------------------------------------
/macos/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import FlutterMacOS
2 | import Cocoa
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/scripts/bili_you.AppDir/AppRun:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd "$(dirname "$0")"
3 | exec ./opt/bili_you
4 |
--------------------------------------------------------------------------------
/scripts/bili_you.AppDir/bili_you.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Categories=AudioVideo;
3 | Comment[zh_CN]=第三方b站客户端
4 | Comment=Three party bilibili client.
5 | Exec=/opt/bili_you
6 | Icon=/opt/data/flutter_assets/assets/icon/bili
7 | Name[zh_CN]=BiliYou
8 | Name=BiliYou
9 | Terminal=false
10 | Type=Application
11 |
--------------------------------------------------------------------------------
/scripts/build.sh:
--------------------------------------------------------------------------------
1 | flutter build apk --target-platform android-arm64 --split-per-abi
--------------------------------------------------------------------------------
/scripts/build_linux_appimage.sh:
--------------------------------------------------------------------------------
1 | # 该脚本需要在项目根目录执行
2 | echo 编译linux版AppImage包到build目录...
3 | flutter build linux --release
4 | rm -rf scripts/bili_you.AppDir/opt/
5 | cp -r build/linux/x64/release/bundle/ scripts/bili_you.AppDir/opt/
6 | appimagetool scripts/bili_you.AppDir build/BiliYou-x86_64.AppImage
7 | rm -rf scripts/bili_you.AppDir/opt/
8 | rm scripts/bili_you.AppDir/.DirIcon
9 |
--------------------------------------------------------------------------------
/scripts/run_flutter_laucher_icons.sh:
--------------------------------------------------------------------------------
1 | flutter pub run flutter_launcher_icons
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | bili_you
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bili_you",
3 | "short_name": "bili_you",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#hexcode",
7 | "theme_color": "#hexcode",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
--------------------------------------------------------------------------------
/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | void RegisterPlugins(flutter::PluginRegistry* registry) {
18 | ConnectivityPlusWindowsPluginRegisterWithRegistrar(
19 | registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
20 | DynamicColorPluginCApiRegisterWithRegistrar(
21 | registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
22 | MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar(
23 | registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi"));
24 | MediaKitVideoPluginCApiRegisterWithRegistrar(
25 | registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi"));
26 | ScreenBrightnessWindowsPluginRegisterWithRegistrar(
27 | registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin"));
28 | SharePlusWindowsPluginCApiRegisterWithRegistrar(
29 | registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
30 | UrlLauncherWindowsRegisterWithRegistrar(
31 | registry->GetRegistrarForPlugin("UrlLauncherWindows"));
32 | }
33 |
--------------------------------------------------------------------------------
/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 | connectivity_plus
7 | dynamic_color
8 | media_kit_libs_windows_video
9 | media_kit_video
10 | screen_brightness_windows
11 | share_plus
12 | url_launcher_windows
13 | )
14 |
15 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
16 | media_kit_native_event_loop
17 | )
18 |
19 | set(PLUGIN_BUNDLED_LIBRARIES)
20 |
21 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
23 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
26 | endforeach(plugin)
27 |
28 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
29 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
30 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
31 | endforeach(ffi_plugin)
32 |
--------------------------------------------------------------------------------
/windows/runner/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | project(runner LANGUAGES CXX)
3 |
4 | # Define the application target. To change its name, change BINARY_NAME in the
5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
6 | # work.
7 | #
8 | # Any new source files that you add to the application should be added here.
9 | add_executable(${BINARY_NAME} WIN32
10 | "flutter_window.cpp"
11 | "main.cpp"
12 | "utils.cpp"
13 | "win32_window.cpp"
14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
15 | "Runner.rc"
16 | "runner.exe.manifest"
17 | )
18 |
19 | # Apply the standard set of build settings. This can be removed for applications
20 | # that need different build settings.
21 | apply_standard_settings(${BINARY_NAME})
22 |
23 | # Add preprocessor definitions for the build version.
24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
29 |
30 | # Disable Windows macros that collide with C++ standard library functions.
31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
32 |
33 | # Add dependency libraries and include directories. Add any application-specific
34 | # dependencies here.
35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
38 |
39 | # Run the Flutter tool portions of the build. This must not be removed.
40 | add_dependencies(${BINARY_NAME} flutter_assemble)
41 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.cpp:
--------------------------------------------------------------------------------
1 | #include "flutter_window.h"
2 |
3 | #include
4 |
5 | #include "flutter/generated_plugin_registrant.h"
6 |
7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project)
8 | : project_(project) {}
9 |
10 | FlutterWindow::~FlutterWindow() {}
11 |
12 | bool FlutterWindow::OnCreate() {
13 | if (!Win32Window::OnCreate()) {
14 | return false;
15 | }
16 |
17 | RECT frame = GetClientArea();
18 |
19 | // The size here must match the window dimensions to avoid unnecessary surface
20 | // creation / destruction in the startup path.
21 | flutter_controller_ = std::make_unique(
22 | frame.right - frame.left, frame.bottom - frame.top, project_);
23 | // Ensure that basic setup of the controller was successful.
24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) {
25 | return false;
26 | }
27 | RegisterPlugins(flutter_controller_->engine());
28 | SetChildContent(flutter_controller_->view()->GetNativeWindow());
29 |
30 | flutter_controller_->engine()->SetNextFrameCallback([&]() {
31 | this->Show();
32 | });
33 |
34 | return true;
35 | }
36 |
37 | void FlutterWindow::OnDestroy() {
38 | if (flutter_controller_) {
39 | flutter_controller_ = nullptr;
40 | }
41 |
42 | Win32Window::OnDestroy();
43 | }
44 |
45 | LRESULT
46 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
47 | WPARAM const wparam,
48 | LPARAM const lparam) noexcept {
49 | // Give Flutter, including plugins, an opportunity to handle window messages.
50 | if (flutter_controller_) {
51 | std::optional result =
52 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
53 | lparam);
54 | if (result) {
55 | return *result;
56 | }
57 | }
58 |
59 | switch (message) {
60 | case WM_FONTCHANGE:
61 | flutter_controller_->engine()->ReloadSystemFonts();
62 | break;
63 | }
64 |
65 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
66 | }
67 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "win32_window.h"
10 |
11 | // A window that does nothing but host a Flutter view.
12 | class FlutterWindow : public Win32Window {
13 | public:
14 | // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 | explicit FlutterWindow(const flutter::DartProject& project);
16 | virtual ~FlutterWindow();
17 |
18 | protected:
19 | // Win32Window:
20 | bool OnCreate() override;
21 | void OnDestroy() override;
22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 | LPARAM const lparam) noexcept override;
24 |
25 | private:
26 | // The project to run.
27 | flutter::DartProject project_;
28 |
29 | // The Flutter instance hosted by this window.
30 | std::unique_ptr flutter_controller_;
31 | };
32 |
33 | #endif // RUNNER_FLUTTER_WINDOW_H_
34 |
--------------------------------------------------------------------------------
/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "utils.h"
7 |
8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 | _In_ wchar_t *command_line, _In_ int show_command) {
10 | // Attach to console when present (e.g., 'flutter run') or create a
11 | // new console when running with a debugger.
12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 | CreateAndAttachConsole();
14 | }
15 |
16 | // Initialize COM, so that it is available for use in the library and/or
17 | // plugins.
18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 |
20 | flutter::DartProject project(L"data");
21 |
22 | std::vector command_line_arguments =
23 | GetCommandLineArguments();
24 |
25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 |
27 | FlutterWindow window(project);
28 | Win32Window::Point origin(10, 10);
29 | Win32Window::Size size(1280, 720);
30 | if (!window.Create(L"bili_you", origin, size)) {
31 | return EXIT_FAILURE;
32 | }
33 | window.SetQuitOnClose(true);
34 |
35 | ::MSG msg;
36 | while (::GetMessage(&msg, nullptr, 0, 0)) {
37 | ::TranslateMessage(&msg);
38 | ::DispatchMessage(&msg);
39 | }
40 |
41 | ::CoUninitialize();
42 | return EXIT_SUCCESS;
43 | }
44 |
--------------------------------------------------------------------------------
/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucinhu/bili_you/ea34e1a06b6947e62473a107454d0f273a391498/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/windows/runner/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | void CreateAndAttachConsole() {
11 | if (::AllocConsole()) {
12 | FILE *unused;
13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 | _dup2(_fileno(stdout), 1);
15 | }
16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 | _dup2(_fileno(stdout), 2);
18 | }
19 | std::ios::sync_with_stdio();
20 | FlutterDesktopResyncOutputStreams();
21 | }
22 | }
23 |
24 | std::vector GetCommandLineArguments() {
25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 | int argc;
27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 | if (argv == nullptr) {
29 | return std::vector();
30 | }
31 |
32 | std::vector command_line_arguments;
33 |
34 | // Skip the first argument as it's the binary name.
35 | for (int i = 1; i < argc; i++) {
36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 | }
38 |
39 | ::LocalFree(argv);
40 |
41 | return command_line_arguments;
42 | }
43 |
44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 | if (utf16_string == nullptr) {
46 | return std::string();
47 | }
48 | int target_length = ::WideCharToMultiByte(
49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 | -1, nullptr, 0, nullptr, nullptr);
51 | std::string utf8_string;
52 | if (target_length == 0 || target_length > utf8_string.max_size()) {
53 | return utf8_string;
54 | }
55 | utf8_string.resize(target_length);
56 | int converted_length = ::WideCharToMultiByte(
57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
58 | -1, utf8_string.data(),
59 | target_length, nullptr, nullptr);
60 | if (converted_length == 0) {
61 | return std::string();
62 | }
63 | return utf8_string;
64 | }
65 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------