├── .github ├── dependabot.yml └── workflows │ └── package.yml ├── .gitignore ├── LICENSE ├── README.md ├── music_channel ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── lib │ └── music_channel.dart ├── pubspec.lock ├── pubspec.yaml └── status.txt ├── music_channel_ios ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── ios │ ├── .gitignore │ ├── Assets │ │ └── .gitkeep │ ├── Classes │ │ ├── MusicChannelIosPlugin.h │ │ ├── MusicChannelIosPlugin.m │ │ └── SwiftMusicChannelIosPlugin.swift │ └── music_channel_ios.podspec ├── lib │ └── music_channel_ios.dart └── pubspec.yaml ├── music_channel_macos ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── lib │ └── music_channel_macos.dart ├── macos │ ├── Classes │ │ └── MusicChannelMacosPlugin.swift │ └── music_channel_macos.podspec └── pubspec.yaml ├── music_channel_web ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── lib │ ├── music_channel_web.dart │ ├── music_data.dart │ └── music_player.dart └── pubspec.yaml ├── music_channel_windows ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── lib │ └── music_channel_windows.dart ├── pubspec.yaml └── windows │ ├── .gitignore │ ├── CMakeLists.txt │ ├── include │ └── music_channel_windows │ │ └── music_channel_windows_plugin.h │ └── music_channel_windows_plugin.cpp ├── music_platform_interface ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── lib │ ├── music_model.dart │ ├── music_platform_interface.dart │ ├── music_play_mode.dart │ ├── music_status.dart │ └── unimplemented_music.dart └── pubspec.yaml ├── pic ├── a.gif ├── a.jpg ├── b.gif ├── b.jpg ├── c.gif ├── c.jpg └── d.jpg └── yunshu_music ├── .dockerignore ├── .gitignore ├── .metadata ├── AudioEffect.txt ├── Dockerfile ├── LICENSE ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle.kts │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── top │ │ │ │ └── itning │ │ │ │ └── yunshu_music │ │ │ │ ├── MainActivity.java │ │ │ │ ├── channel │ │ │ │ └── MusicChannel.java │ │ │ │ ├── service │ │ │ │ ├── MediaPlayerImpl.java │ │ │ │ ├── MusicBrowserService.java │ │ │ │ ├── MusicNotificationService.java │ │ │ │ ├── MusicPlayDataService.java │ │ │ │ └── MusicPlayMode.java │ │ │ │ └── util │ │ │ │ ├── HttpClient.java │ │ │ │ └── MusicAppGlideModule.java │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ ├── default_cover.jpg │ │ │ ├── launch_background.xml │ │ │ ├── outline_skip_next.xml │ │ │ ├── outline_skip_previous.xml │ │ │ ├── pause_black.xml │ │ │ └── play_black.xml │ │ │ ├── layout │ │ │ └── layout_widget.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ ├── values │ │ │ └── styles.xml │ │ │ └── xml │ │ │ └── network_security_config.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle.kts ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle.kts ├── asserts ├── fonts │ ├── LXGWWenKaiMono-Regular.ttf │ └── Roboto.ttf ├── icon │ ├── app_icon.ico │ └── launcher_icon.png └── images │ └── default_cover.jpg ├── buildAll.cmd ├── buildAndroid.cmd ├── buildWeb.cmd ├── buildWindows.cmd ├── 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-1024.png │ │ ├── icon-20-ipad.png │ │ ├── icon-20@2x-ipad.png │ │ ├── icon-20@2x.png │ │ ├── icon-20@3x.png │ │ ├── icon-29-ipad.png │ │ ├── icon-29.png │ │ ├── icon-29@2x-ipad.png │ │ ├── icon-29@2x.png │ │ ├── icon-29@3x.png │ │ ├── icon-40.png │ │ ├── icon-40@2x.png │ │ ├── icon-40@3x.png │ │ ├── icon-60@2x.png │ │ ├── icon-60@3x.png │ │ ├── icon-76.png │ │ ├── icon-76@2x.png │ │ └── icon-83.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 ├── lib ├── component │ ├── image_fade.dart │ ├── lyric │ │ ├── lyric.dart │ │ ├── lyric_controller.dart │ │ ├── lyric_painter.dart │ │ ├── lyric_util.dart │ │ └── lyric_widget.dart │ ├── rotate_cover_image_widget.dart │ └── volume_slider.dart ├── generated │ └── json │ │ ├── base │ │ ├── json_convert_content.dart │ │ └── json_field.dart │ │ ├── music_entity.g.dart │ │ └── search_result_entity.g.dart ├── hotkey │ ├── action.dart │ └── intent.dart ├── main.dart ├── method_channel │ └── music_channel.dart ├── net │ ├── http_helper.dart │ └── model │ │ ├── music_entity.dart │ │ └── search_result_entity.dart ├── page │ ├── login │ │ └── login_page.dart │ ├── music_list │ │ ├── component │ │ │ ├── music_list.dart │ │ │ ├── music_list_item.dart │ │ │ ├── music_mini_play_controller_widget.dart │ │ │ └── music_search_delegate.dart │ │ └── music_index_page.dart │ ├── music_play │ │ ├── component │ │ │ ├── cover_page.dart │ │ │ ├── lyric_page.dart │ │ │ ├── player_page_bottom_navigation_bar.dart │ │ │ ├── player_page_controller.dart │ │ │ ├── player_page_progress.dart │ │ │ └── title_music_info.dart │ │ └── music_play_page.dart │ └── setting │ │ └── app_setting_page.dart ├── provider │ ├── cache_model.dart │ ├── login_model.dart │ ├── music_data_model.dart │ ├── music_list_status_model.dart │ ├── play_status_model.dart │ ├── search_model.dart │ ├── setting_model.dart │ ├── theme_model.dart │ └── volume_data_model.dart └── util │ ├── common_utils.dart │ └── log_console.dart ├── macos ├── .gitignore ├── 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 ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart ├── web ├── favicon.ico ├── 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/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | enable-beta-ecosystems: true 8 | updates: 9 | - package-ecosystem: "pub" 10 | directory: "/yunshu_music" 11 | schedule: 12 | interval: "daily" 13 | - package-ecosystem: "pub" 14 | directory: "/music_channel" 15 | schedule: 16 | interval: "daily" 17 | - package-ecosystem: "pub" 18 | directory: "/music_channel_macos" 19 | schedule: 20 | interval: "daily" 21 | - package-ecosystem: "pub" 22 | directory: "/music_channel_ios" 23 | schedule: 24 | interval: "daily" 25 | - package-ecosystem: "pub" 26 | directory: "/music_channel_web" 27 | schedule: 28 | interval: "daily" 29 | - package-ecosystem: "pub" 30 | directory: "/music_channel_windows" 31 | schedule: 32 | interval: "daily" 33 | - package-ecosystem: "pub" 34 | directory: "/music_platform_interface" 35 | schedule: 36 | interval: "daily" 37 | -------------------------------------------------------------------------------- /.github/workflows/package.yml: -------------------------------------------------------------------------------- 1 | name: Flutter Package 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | workflow_dispatch: 8 | 9 | env: 10 | FLUTTER_VERSION: "3.32.1" 11 | 12 | jobs: 13 | build_web: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout the code 18 | uses: actions/checkout@v2 19 | 20 | - name: Install and set Flutter version 21 | uses: subosito/flutter-action@v2 22 | with: 23 | flutter-version: ${{ env.FLUTTER_VERSION }} 24 | #channel: 'stable' 25 | 26 | - name: Restore packages 27 | run: | 28 | cd yunshu_music 29 | flutter pub get 30 | 31 | - name: Build Web App 32 | run: | 33 | cd yunshu_music 34 | flutter build web --release 35 | 36 | - name: Zip 37 | uses: thedoctor0/zip-release@master 38 | with: 39 | filename: 'web.zip' 40 | path: 'yunshu_music/build/web' 41 | 42 | - name: Create Github Release 43 | uses: ncipollo/release-action@v1 44 | with: 45 | artifacts: "web.zip" 46 | token: ${{ secrets.GITHUB_TOKEN }} 47 | draft: true 48 | allowUpdates: true 49 | 50 | build_android: 51 | runs-on: ubuntu-latest 52 | 53 | steps: 54 | - name: Checkout the code 55 | uses: actions/checkout@v2 56 | 57 | - name: Setup Java to compile Android project 58 | uses: actions/setup-java@v1 59 | with: 60 | java-version: "17.x" 61 | 62 | - name: Install and set Flutter version 63 | uses: subosito/flutter-action@v2 64 | with: 65 | flutter-version: ${{ env.FLUTTER_VERSION }} 66 | #channel: 'stable' 67 | - name: Create the Keystore 68 | env: 69 | KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} 70 | KEY_PROPERTIES: ${{ secrets.KEY_PROPERTIES }} 71 | run: | 72 | # import keystore from secrets 73 | cd yunshu_music 74 | ls -all 75 | echo $KEYSTORE_BASE64 | base64 -di > android/app/key.jks 76 | echo $KEY_PROPERTIES | base64 -di > android/key.properties 77 | 78 | - name: Restore packages 79 | run: | 80 | cd yunshu_music 81 | flutter pub get 82 | 83 | - name: Build Android App 84 | run: | 85 | cd yunshu_music 86 | flutter build apk --release --split-per-abi 87 | 88 | - name: Create Github Release 89 | uses: ncipollo/release-action@v1 90 | with: 91 | artifacts: "yunshu_music/build/app/outputs/apk/release/*.apk" 92 | token: ${{ secrets.GITHUB_TOKEN }} 93 | draft: true 94 | allowUpdates: true 95 | 96 | build_windows: 97 | runs-on: windows-latest 98 | 99 | steps: 100 | - name: Checkout the code 101 | uses: actions/checkout@v2 102 | 103 | - name: Install and set Flutter version 104 | uses: subosito/flutter-action@v2 105 | with: 106 | flutter-version: ${{ env.FLUTTER_VERSION }} 107 | #channel: 'stable' 108 | 109 | - name: Restore packages 110 | run: | 111 | cd yunshu_music 112 | flutter pub get 113 | 114 | - name: Build Windows App 115 | run: | 116 | cd yunshu_music 117 | flutter build windows --release 118 | Compress-Archive -Path .\build\windows\x64\runner\Release\* -DestinationPath windows.zip 119 | 120 | - name: Create Github Release 121 | uses: ncipollo/release-action@v1 122 | with: 123 | artifacts: "yunshu_music/windows.zip" 124 | token: ${{ secrets.GITHUB_TOKEN }} 125 | draft: true 126 | allowUpdates: true 127 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /music_channel/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 25 | /pubspec.lock 26 | **/doc/api/ 27 | .dart_tool/ 28 | .packages 29 | build/ 30 | -------------------------------------------------------------------------------- /music_channel/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 097d3313d8e2c7f901932d63e537c1acefb87800 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /music_channel/README.md: -------------------------------------------------------------------------------- 1 | 音乐平台接口 2 | 3 | 不同平台有不同的实现 -------------------------------------------------------------------------------- /music_channel/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /music_channel/lib/music_channel.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:music_platform_interface/music_platform_interface.dart'; 4 | 5 | Future init( 6 | StreamController metadataEventController, 7 | StreamController playbackStateController, 8 | StreamController volumeStateController) { 9 | return MusicPlatform.instance.init( 10 | metadataEventController, playbackStateController, volumeStateController); 11 | } 12 | 13 | Future initMethod(List musicList) { 14 | return MusicPlatform.instance.initMethod(musicList); 15 | } 16 | 17 | Future playFromId(String id) { 18 | return MusicPlatform.instance.playFromId(id); 19 | } 20 | 21 | Future play() { 22 | return MusicPlatform.instance.play(); 23 | } 24 | 25 | Future pause() { 26 | return MusicPlatform.instance.pause(); 27 | } 28 | 29 | Future skipToPrevious() { 30 | return MusicPlatform.instance.skipToPrevious(); 31 | } 32 | 33 | Future skipToNext() { 34 | return MusicPlatform.instance.skipToNext(); 35 | } 36 | 37 | Future seekTo(Duration position) { 38 | return MusicPlatform.instance.seekTo(position); 39 | } 40 | 41 | Future setPlayMode(String mode) { 42 | return MusicPlatform.instance.setPlayMode(mode); 43 | } 44 | 45 | Future getPlayMode() { 46 | return MusicPlatform.instance.getPlayMode(); 47 | } 48 | 49 | Future> getPlayList() { 50 | return MusicPlatform.instance.getPlayList(); 51 | } 52 | 53 | Future delPlayListByMediaId(String mediaId) { 54 | return MusicPlatform.instance.delPlayListByMediaId(mediaId); 55 | } 56 | 57 | Future clearPlayList() { 58 | return MusicPlatform.instance.clearPlayList(); 59 | } 60 | 61 | Future setVolume(double value) { 62 | return MusicPlatform.instance.setVolume(value); 63 | } 64 | -------------------------------------------------------------------------------- /music_channel/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: music_channel 2 | description: A new Flutter project. 3 | version: 0.0.1 4 | homepage: 5 | 6 | environment: 7 | sdk: ^3.8.1 8 | flutter: '>=3.3.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | music_channel_web: 14 | path: ../music_channel_web 15 | music_channel_windows: 16 | path: ../music_channel_windows 17 | music_channel_macos: 18 | path: ../music_channel_macos 19 | music_channel_ios: 20 | path: ../music_channel_ios 21 | music_platform_interface: 22 | path: ../music_platform_interface 23 | 24 | dev_dependencies: 25 | flutter_test: 26 | sdk: flutter 27 | 28 | # For information on the generic Dart part of this file, see the 29 | # following page: https://dart.dev/tools/pub/pubspec 30 | 31 | # The following section is specific to Flutter. 32 | flutter: 33 | plugin: 34 | platforms: 35 | web: 36 | default_package: music_channel_web 37 | windows: 38 | default_package: music_channel_windows 39 | macos: 40 | default_package: music_channel_macos 41 | ios: 42 | default_package: music_channel_ios -------------------------------------------------------------------------------- /music_channel/status.txt: -------------------------------------------------------------------------------- 1 | STATE_BUFFERING 2 | Constant Value: 6 (0x00000006) 3 | 4 | STATE_CONNECTING 5 | Constant Value: 8 (0x00000008) 6 | 7 | STATE_ERROR 8 | Constant Value: 7 (0x00000007) 9 | 10 | STATE_FAST_FORWARDING 11 | Constant Value: 4 (0x00000004) 12 | 13 | STATE_NONE 14 | Constant Value: 0 (0x00000000) 15 | 16 | STATE_PAUSED 17 | Constant Value: 2 (0x00000002) 18 | 19 | STATE_PLAYING 20 | Constant Value: 3 (0x00000003) 21 | 22 | STATE_REWINDING 23 | Constant Value: 5 (0x00000005) 24 | 25 | STATE_SKIPPING_TO_NEXT 26 | Constant Value: 10 (0x0000000a) 27 | 28 | STATE_SKIPPING_TO_PREVIOUS 29 | Constant Value: 9 (0x00000009) 30 | 31 | STATE_SKIPPING_TO_QUEUE_ITEM 32 | Constant Value: 11 (0x0000000b) 33 | 34 | STATE_STOPPED 35 | Constant Value: 1 (0x00000001) -------------------------------------------------------------------------------- /music_channel_ios/.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 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /music_channel_ios/.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: fb57da5f945d02ef4f98dfd9409a72b7cce74268 8 | channel: stable 9 | 10 | project_type: plugin 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268 17 | base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268 18 | - platform: ios 19 | create_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268 20 | base_revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268 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 | -------------------------------------------------------------------------------- /music_channel_ios/README.md: -------------------------------------------------------------------------------- 1 | 音乐平台接口 ios端实现 -------------------------------------------------------------------------------- /music_channel_ios/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /music_channel_ios/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /music_channel_ios/ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/music_channel_ios/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /music_channel_ios/ios/Classes/MusicChannelIosPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MusicChannelIosPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /music_channel_ios/ios/Classes/MusicChannelIosPlugin.m: -------------------------------------------------------------------------------- 1 | #import "MusicChannelIosPlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "music_channel_ios-Swift.h" 9 | #endif 10 | 11 | @implementation MusicChannelIosPlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftMusicChannelIosPlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /music_channel_ios/ios/music_channel_ios.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint music_channel_ios.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'music_channel_ios' 7 | s.version = '0.0.1' 8 | s.summary = 'YunShu Music For IOS' 9 | s.description = <<-DESC 10 | YunShu Music For IOS 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '9.0' 19 | 20 | # Flutter.framework does not contain a i386 slice. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /music_channel_ios/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: music_channel_ios 2 | description: YunShu Music For IOS 3 | version: 0.0.1 4 | homepage: 5 | 6 | environment: 7 | sdk: ^3.8.1 8 | flutter: '>=3.3.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | music_platform_interface: 14 | path: ../music_platform_interface 15 | shared_preferences: ^2.5.3 16 | audioplayers: ^6.4.0 17 | 18 | dev_dependencies: 19 | flutter_test: 20 | sdk: flutter 21 | flutter_lints: ^6.0.0 22 | 23 | flutter: 24 | plugin: 25 | implements: music_channel 26 | platforms: 27 | ios: 28 | pluginClass: MusicChannelIosPlugin 29 | dartPluginClass: MusicChannelIos 30 | -------------------------------------------------------------------------------- /music_channel_macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 25 | /pubspec.lock 26 | **/doc/api/ 27 | .dart_tool/ 28 | .packages 29 | build/ 30 | -------------------------------------------------------------------------------- /music_channel_macos/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 5464c5bac742001448fe4fc0597be939379f88ea 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /music_channel_macos/README.md: -------------------------------------------------------------------------------- 1 | 音乐平台接口 macos端实现 -------------------------------------------------------------------------------- /music_channel_macos/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /music_channel_macos/macos/Classes/MusicChannelMacosPlugin.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | public class MusicChannelMacosPlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | let channel = FlutterMethodChannel(name: "music_channel_macos", binaryMessenger: registrar.messenger) 7 | let instance = MusicChannelMacosPlugin() 8 | registrar.addMethodCallDelegate(instance, channel: channel) 9 | } 10 | 11 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 12 | switch call.method { 13 | case "getPlatformVersion": 14 | result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString) 15 | default: 16 | result(FlutterMethodNotImplemented) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /music_channel_macos/macos/music_channel_macos.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint music_channel_macos.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'music_channel_macos' 7 | s.version = '0.0.1' 8 | s.summary = 'A new Flutter project.' 9 | s.description = <<-DESC 10 | A new Flutter project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'FlutterMacOS' 18 | 19 | s.platform = :osx, '10.11' 20 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } 21 | s.swift_version = '5.0' 22 | end 23 | -------------------------------------------------------------------------------- /music_channel_macos/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: music_channel_macos 2 | description: A new Flutter project. 3 | version: 0.0.1 4 | homepage: 5 | 6 | environment: 7 | sdk: ^3.8.1 8 | flutter: '>=3.3.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | music_platform_interface: 14 | path: ../music_platform_interface 15 | window_size: 16 | git: 17 | url: https://github.com/google/flutter-desktop-embedding.git 18 | path: plugins/window_size 19 | shared_preferences: ^2.5.3 20 | system_tray: ^2.0.3 21 | window_manager: ^0.5.0 22 | audioplayers: ^6.4.0 23 | 24 | dev_dependencies: 25 | flutter_test: 26 | sdk: flutter 27 | flutter_lints: ^6.0.0 28 | 29 | flutter: 30 | plugin: 31 | implements: music_channel 32 | platforms: 33 | macos: 34 | pluginClass: MusicChannelMacosPlugin 35 | dartPluginClass: MusicChannelMacOS -------------------------------------------------------------------------------- /music_channel_web/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 25 | /pubspec.lock 26 | **/doc/api/ 27 | .dart_tool/ 28 | .packages 29 | build/ 30 | -------------------------------------------------------------------------------- /music_channel_web/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 097d3313d8e2c7f901932d63e537c1acefb87800 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /music_channel_web/README.md: -------------------------------------------------------------------------------- 1 | 音乐平台接口 Web端实现 -------------------------------------------------------------------------------- /music_channel_web/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /music_channel_web/lib/music_channel_web.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; 4 | import 'package:music_channel_web/music_data.dart'; 5 | import 'package:music_channel_web/music_player.dart'; 6 | import 'package:music_platform_interface/music_model.dart'; 7 | import 'package:music_platform_interface/music_platform_interface.dart'; 8 | import 'package:music_platform_interface/music_play_mode.dart'; 9 | 10 | class MusicChannel extends MusicPlatform { 11 | static MusicChannel? _instance; 12 | 13 | static MusicChannel get() { 14 | _instance ??= MusicChannel(); 15 | return _instance!; 16 | } 17 | 18 | static void registerWith(Registrar registrar) { 19 | MusicPlatform.instance = MusicChannel.get(); 20 | } 21 | 22 | late StreamController metadataEventController; 23 | late StreamController playbackStateController; 24 | late StreamController volumeController; 25 | 26 | @override 27 | Future init( 28 | StreamController metadataEventController, 29 | StreamController playbackStateController, 30 | StreamController volumeController) async { 31 | this.metadataEventController = metadataEventController; 32 | this.playbackStateController = playbackStateController; 33 | this.volumeController = volumeController; 34 | } 35 | 36 | @override 37 | Future delPlayListByMediaId(String mediaId) async { 38 | MusicData.get().delPlayListByMediaId(mediaId); 39 | } 40 | 41 | @override 42 | Future clearPlayList() async { 43 | MusicData.get().clearPlayList(); 44 | } 45 | 46 | @override 47 | Future getPlayList() async { 48 | return MusicData.get().playList.map((e) => e.toMetaDataMap()).toList(); 49 | } 50 | 51 | @override 52 | Future getPlayMode() async { 53 | return MusicData.get().playMode.name().toLowerCase(); 54 | } 55 | 56 | @override 57 | Future initMethod(List musicList) async { 58 | List musics = musicList.map((item) => Music.fromMap(item)).toList(); 59 | try { 60 | MusicData.get().addMusic(musics); 61 | MusicPlayer.get() 62 | .onPlayFromMediaId(MusicData.get().nowPlayMusic!.musicId!); 63 | } catch (e) { 64 | print(e); 65 | } 66 | } 67 | 68 | @override 69 | Future pause() async { 70 | MusicPlayer.get().onPause(); 71 | } 72 | 73 | @override 74 | Future play() async { 75 | MusicPlayer.get().onPlay(); 76 | } 77 | 78 | @override 79 | Future playFromId(String id) async { 80 | MusicPlayer.get().onPlayFromMediaId(id); 81 | } 82 | 83 | @override 84 | Future seekTo(Duration position) async { 85 | MusicPlayer.get().onSeekTo(position.inMilliseconds); 86 | } 87 | 88 | @override 89 | Future setPlayMode(String mode) async { 90 | MusicData.get().playMode = valueOf(mode.toString().toUpperCase()); 91 | } 92 | 93 | @override 94 | Future skipToNext() async { 95 | MusicPlayer.get().onSkipToNext(true); 96 | } 97 | 98 | @override 99 | Future skipToPrevious() async { 100 | MusicPlayer.get().onSkipToPrevious(true); 101 | } 102 | 103 | @override 104 | Future setVolume(double value) async { 105 | MusicPlayer.get().setVolume(value); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /music_channel_web/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: music_channel_web 2 | description: A new Flutter project. 3 | version: 0.0.1 4 | homepage: 5 | 6 | environment: 7 | sdk: ">=2.16.1 <3.0.0" 8 | flutter: ">=1.17.0" 9 | 10 | flutter: 11 | plugin: 12 | implements: music_channel 13 | platforms: 14 | web: 15 | pluginClass: MusicChannel 16 | fileName: music_channel_web.dart 17 | 18 | dependencies: 19 | flutter: 20 | sdk: flutter 21 | flutter_web_plugins: 22 | sdk: flutter 23 | music_platform_interface: 24 | path: ../music_platform_interface 25 | 26 | dev_dependencies: 27 | flutter_test: 28 | sdk: flutter 29 | flutter_lints: ^2.0.1 30 | 31 | 32 | -------------------------------------------------------------------------------- /music_channel_windows/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 25 | /pubspec.lock 26 | **/doc/api/ 27 | .dart_tool/ 28 | .packages 29 | build/ 30 | -------------------------------------------------------------------------------- /music_channel_windows/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 097d3313d8e2c7f901932d63e537c1acefb87800 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /music_channel_windows/README.md: -------------------------------------------------------------------------------- 1 | 音乐平台接口 Windows端实现 -------------------------------------------------------------------------------- /music_channel_windows/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /music_channel_windows/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: music_channel_windows 2 | description: A new Flutter project. 3 | version: 0.0.1 4 | homepage: 5 | 6 | environment: 7 | sdk: ^3.8.1 8 | flutter: '>=3.3.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | music_platform_interface: 14 | path: ../music_platform_interface 15 | window_size: 16 | git: 17 | url: https://github.com/google/flutter-desktop-embedding.git 18 | path: plugins/window_size 19 | shared_preferences: ^2.5.3 20 | windows_taskbar: ^1.1.2 21 | system_tray: ^2.0.3 22 | window_manager: ^0.5.0 23 | audioplayers: ^6.4.0 24 | 25 | dev_dependencies: 26 | flutter_test: 27 | sdk: flutter 28 | flutter_lints: ^6.0.0 29 | 30 | # For information on the generic Dart part of this file, see the 31 | # following page: https://dart.dev/tools/pub/pubspec 32 | 33 | # The following section is specific to Flutter. 34 | flutter: 35 | plugin: 36 | implements: music_channel 37 | platforms: 38 | windows: 39 | pluginClass: MusicChannelWindowsPlugin 40 | dartPluginClass: MusicChannelWindows -------------------------------------------------------------------------------- /music_channel_windows/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ 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 | -------------------------------------------------------------------------------- /music_channel_windows/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | set(PROJECT_NAME "music_channel_windows") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | # This value is used when generating builds using this plugin, so it must 6 | # not be changed 7 | set(PLUGIN_NAME "music_channel_windows_plugin") 8 | 9 | add_library(${PLUGIN_NAME} SHARED 10 | "music_channel_windows_plugin.cpp" 11 | ) 12 | apply_standard_settings(${PLUGIN_NAME}) 13 | set_target_properties(${PLUGIN_NAME} PROPERTIES 14 | CXX_VISIBILITY_PRESET hidden) 15 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 16 | target_include_directories(${PLUGIN_NAME} INTERFACE 17 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 18 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) 19 | 20 | # List of absolute paths to libraries that should be bundled with the plugin 21 | set(music_channel_windows_bundled_libraries 22 | "" 23 | PARENT_SCOPE 24 | ) 25 | -------------------------------------------------------------------------------- /music_channel_windows/windows/include/music_channel_windows/music_channel_windows_plugin.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_PLUGIN_MUSIC_CHANNEL_WINDOWS_PLUGIN_H_ 2 | #define FLUTTER_PLUGIN_MUSIC_CHANNEL_WINDOWS_PLUGIN_H_ 3 | 4 | #include 5 | 6 | #ifdef FLUTTER_PLUGIN_IMPL 7 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) 8 | #else 9 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) 10 | #endif 11 | 12 | #if defined(__cplusplus) 13 | extern "C" { 14 | #endif 15 | 16 | FLUTTER_PLUGIN_EXPORT void MusicChannelWindowsPluginRegisterWithRegistrar( 17 | FlutterDesktopPluginRegistrarRef registrar); 18 | 19 | #if defined(__cplusplus) 20 | } // extern "C" 21 | #endif 22 | 23 | #endif // FLUTTER_PLUGIN_MUSIC_CHANNEL_WINDOWS_PLUGIN_H_ 24 | -------------------------------------------------------------------------------- /music_channel_windows/windows/music_channel_windows_plugin.cpp: -------------------------------------------------------------------------------- 1 | #include "include/music_channel_windows/music_channel_windows_plugin.h" 2 | 3 | // This must be included before many other Windows headers. 4 | #include 5 | 6 | // For getPlatformVersion; remove unless needed for your plugin implementation. 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace { 18 | 19 | class MusicChannelWindowsPlugin : public flutter::Plugin { 20 | public: 21 | static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); 22 | 23 | MusicChannelWindowsPlugin(); 24 | 25 | virtual ~MusicChannelWindowsPlugin(); 26 | 27 | private: 28 | // Called when a method is called on this plugin's channel from Dart. 29 | void HandleMethodCall( 30 | const flutter::MethodCall &method_call, 31 | std::unique_ptr> result); 32 | }; 33 | 34 | // static 35 | void MusicChannelWindowsPlugin::RegisterWithRegistrar( 36 | flutter::PluginRegistrarWindows *registrar) { 37 | auto channel = 38 | std::make_unique>( 39 | registrar->messenger(), "music_channel_windows", 40 | &flutter::StandardMethodCodec::GetInstance()); 41 | 42 | auto plugin = std::make_unique(); 43 | 44 | channel->SetMethodCallHandler( 45 | [plugin_pointer = plugin.get()](const auto &call, auto result) { 46 | plugin_pointer->HandleMethodCall(call, std::move(result)); 47 | }); 48 | 49 | registrar->AddPlugin(std::move(plugin)); 50 | } 51 | 52 | MusicChannelWindowsPlugin::MusicChannelWindowsPlugin() {} 53 | 54 | MusicChannelWindowsPlugin::~MusicChannelWindowsPlugin() {} 55 | 56 | void MusicChannelWindowsPlugin::HandleMethodCall( 57 | const flutter::MethodCall &method_call, 58 | std::unique_ptr> result) { 59 | if (method_call.method_name().compare("getPlatformVersion") == 0) { 60 | std::ostringstream version_stream; 61 | version_stream << "Windows "; 62 | if (IsWindows10OrGreater()) { 63 | version_stream << "10+"; 64 | } else if (IsWindows8OrGreater()) { 65 | version_stream << "8"; 66 | } else if (IsWindows7OrGreater()) { 67 | version_stream << "7"; 68 | } 69 | result->Success(flutter::EncodableValue(version_stream.str())); 70 | } else { 71 | result->NotImplemented(); 72 | } 73 | } 74 | 75 | } // namespace 76 | 77 | void MusicChannelWindowsPluginRegisterWithRegistrar( 78 | FlutterDesktopPluginRegistrarRef registrar) { 79 | MusicChannelWindowsPlugin::RegisterWithRegistrar( 80 | flutter::PluginRegistrarManager::GetInstance() 81 | ->GetRegistrar(registrar)); 82 | } 83 | -------------------------------------------------------------------------------- /music_platform_interface/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 25 | /pubspec.lock 26 | **/doc/api/ 27 | .dart_tool/ 28 | .packages 29 | build/ 30 | -------------------------------------------------------------------------------- /music_platform_interface/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 097d3313d8e2c7f901932d63e537c1acefb87800 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /music_platform_interface/README.md: -------------------------------------------------------------------------------- 1 | 音乐平台接口 接口层&公共层 -------------------------------------------------------------------------------- /music_platform_interface/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /music_platform_interface/lib/music_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:music_platform_interface/music_status.dart'; 2 | 3 | class Music { 4 | String? musicId; 5 | String? name; 6 | String? singer; 7 | String? lyricId; 8 | int? type; 9 | String? musicUri; 10 | String? lyricUri; 11 | String? coverUri; 12 | 13 | static Music fromMap(dynamic item) { 14 | Music music = Music(); 15 | music.musicId = item['musicId']; 16 | music.name = item['name']; 17 | music.singer = item['singer']; 18 | music.lyricId = item['lyricId']; 19 | music.type = item['type']; 20 | music.musicUri = item['musicUri']; 21 | music.lyricUri = item['lyricUri']; 22 | music.coverUri = item['coverUri']; 23 | return music; 24 | } 25 | 26 | Map toMetaDataMap() { 27 | return { 28 | 'title': name ?? '', 29 | 'subTitle': singer ?? '', 30 | 'mediaId': musicId ?? '' 31 | }; 32 | } 33 | 34 | @override 35 | bool operator ==(Object other) => 36 | identical(this, other) || 37 | other is Music && 38 | runtimeType == other.runtimeType && 39 | musicId == other.musicId; 40 | 41 | @override 42 | int get hashCode => musicId.hashCode; 43 | } 44 | 45 | class MusicMetaData { 46 | final Map _map = { 47 | 'duration': 0, 48 | 'title': '', 49 | 'subTitle': '', 50 | 'mediaId': '', 51 | 'musicUri': '', 52 | 'lyricUri': '' 53 | }; 54 | 55 | int duration = 0; 56 | String title = ''; 57 | String subTitle = ''; 58 | String mediaId = ''; 59 | String coverUri = ''; 60 | String musicUri = ''; 61 | String lyricUri = ''; 62 | 63 | void from(Music music) { 64 | title = music.name ?? ''; 65 | subTitle = music.singer ?? ''; 66 | mediaId = music.musicId ?? ''; 67 | coverUri = music.coverUri ?? ''; 68 | musicUri = music.musicUri ?? ''; 69 | lyricUri = music.lyricUri ?? ''; 70 | } 71 | 72 | Map toMap() { 73 | _map['duration'] = duration; 74 | _map['title'] = title; 75 | _map['subTitle'] = subTitle; 76 | _map['mediaId'] = mediaId; 77 | _map['coverUri'] = coverUri; 78 | _map['musicUri'] = musicUri; 79 | _map['lyricUri'] = lyricUri; 80 | return _map; 81 | } 82 | } 83 | 84 | class PlaybackState { 85 | final Map _map = { 86 | 'bufferedPosition': 0, 87 | 'position': 0, 88 | 'state': -1 89 | }; 90 | int bufferedPosition = 0; 91 | int position = 0; 92 | MusicStatus state = MusicStatus.none; 93 | 94 | Map toMap() { 95 | _map['bufferedPosition'] = bufferedPosition; 96 | _map['position'] = position; 97 | _map['state'] = state.index; 98 | return _map; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /music_platform_interface/lib/music_platform_interface.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:music_platform_interface/unimplemented_music.dart'; 4 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 5 | 6 | abstract class MusicPlatform extends PlatformInterface { 7 | MusicPlatform() : super(token: _token); 8 | 9 | static final Object _token = Object(); 10 | static MusicPlatform _instance = UnimplementedMusic(); 11 | 12 | static MusicPlatform get instance => _instance; 13 | 14 | static set instance(MusicPlatform instance) { 15 | PlatformInterface.verify(instance, _token); 16 | _instance = instance; 17 | } 18 | 19 | Future init(StreamController metadataEventController, 20 | StreamController playbackStateController, 21 | StreamController volumeController); 22 | 23 | Future initMethod(List musicList); 24 | 25 | Future playFromId(String id); 26 | 27 | Future play(); 28 | 29 | Future pause(); 30 | 31 | Future skipToPrevious(); 32 | 33 | Future skipToNext(); 34 | 35 | Future seekTo(Duration position); 36 | 37 | Future setPlayMode(String mode); 38 | 39 | Future getPlayMode(); 40 | 41 | Future> getPlayList(); 42 | 43 | Future delPlayListByMediaId(String mediaId); 44 | 45 | Future clearPlayList(); 46 | 47 | Future setVolume(double value); 48 | } 49 | -------------------------------------------------------------------------------- /music_platform_interface/lib/music_play_mode.dart: -------------------------------------------------------------------------------- 1 | enum MusicPlayMode { SEQUENCE, RANDOMLY, LOOP } 2 | 3 | extension MusicPlayModeExtension on MusicPlayMode { 4 | String name() { 5 | switch (index) { 6 | case 0: 7 | return 'SEQUENCE'; 8 | case 1: 9 | return 'RANDOMLY'; 10 | case 2: 11 | return 'LOOP'; 12 | default: 13 | return 'SEQUENCE'; 14 | } 15 | } 16 | } 17 | 18 | MusicPlayMode valueOf(String name) { 19 | switch (name) { 20 | case 'SEQUENCE': 21 | return MusicPlayMode.SEQUENCE; 22 | case 'RANDOMLY': 23 | return MusicPlayMode.RANDOMLY; 24 | case 'LOOP': 25 | return MusicPlayMode.LOOP; 26 | default: 27 | return MusicPlayMode.SEQUENCE; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /music_platform_interface/lib/music_status.dart: -------------------------------------------------------------------------------- 1 | enum MusicStatus { 2 | // 0 3 | none, 4 | // 1 5 | stopped, 6 | // 2 7 | paused, 8 | // 3 9 | playing, 10 | // 4 11 | fastForwarding, 12 | // 5 13 | rewinding, 14 | // 6 15 | buffering, 16 | // 7 17 | error, 18 | // 8 19 | connecting, 20 | // 9 21 | skippingToPrevious, 22 | // 10 23 | skippingToNext, 24 | // 11 25 | skippingToQueueItem 26 | } 27 | -------------------------------------------------------------------------------- /music_platform_interface/lib/unimplemented_music.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:music_platform_interface/music_platform_interface.dart'; 4 | 5 | class UnimplementedMusic extends MusicPlatform { 6 | @override 7 | Future delPlayListByMediaId(String mediaId) { 8 | throw UnimplementedError(); 9 | } 10 | 11 | @override 12 | Future getPlayList() { 13 | throw UnimplementedError(); 14 | } 15 | 16 | @override 17 | Future getPlayMode() { 18 | throw UnimplementedError(); 19 | } 20 | 21 | @override 22 | Future init( 23 | StreamController metadataEventController, 24 | StreamController playbackStateController, 25 | StreamController volumeController) { 26 | throw UnimplementedError(); 27 | } 28 | 29 | @override 30 | Future initMethod(List> musicList) { 31 | throw UnimplementedError(); 32 | } 33 | 34 | @override 35 | Future pause() { 36 | throw UnimplementedError(); 37 | } 38 | 39 | @override 40 | Future play() { 41 | throw UnimplementedError(); 42 | } 43 | 44 | @override 45 | Future playFromId(String id) { 46 | throw UnimplementedError(); 47 | } 48 | 49 | @override 50 | Future seekTo(Duration position) { 51 | throw UnimplementedError(); 52 | } 53 | 54 | @override 55 | Future setPlayMode(String mode) { 56 | throw UnimplementedError(); 57 | } 58 | 59 | @override 60 | Future skipToNext() { 61 | throw UnimplementedError(); 62 | } 63 | 64 | @override 65 | Future skipToPrevious() { 66 | throw UnimplementedError(); 67 | } 68 | 69 | @override 70 | Future setVolume(double value) { 71 | throw UnimplementedError(); 72 | } 73 | 74 | @override 75 | Future clearPlayList() { 76 | throw UnimplementedError(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /music_platform_interface/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: music_platform_interface 2 | description: A new Flutter project. 3 | version: 0.0.1 4 | homepage: 5 | 6 | environment: 7 | sdk: ^3.8.1 8 | flutter: '>=3.3.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | plugin_platform_interface: ^2.1.8 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | flutter_lints: ^6.0.0 19 | 20 | # For information on the generic Dart part of this file, see the 21 | # following page: https://dart.dev/tools/pub/pubspec 22 | 23 | # The following section is specific to Flutter. 24 | flutter: 25 | 26 | # To add assets to your package, add an assets section, like this: 27 | # assets: 28 | # - images/a_dot_burr.jpeg 29 | # - images/a_dot_ham.jpeg 30 | # 31 | # For details regarding assets in packages, see 32 | # https://flutter.dev/assets-and-images/#from-packages 33 | # 34 | # An image asset can refer to one or more resolution-specific "variants", see 35 | # https://flutter.dev/assets-and-images/#resolution-aware. 36 | 37 | # To add custom fonts to your package, add a fonts section here, 38 | # in this "flutter" section. Each entry in this list should have a 39 | # "family" key with the font family name, and a "fonts" key with a 40 | # list giving the asset and other descriptors for the font. For 41 | # example: 42 | # fonts: 43 | # - family: Schyler 44 | # fonts: 45 | # - asset: fonts/Schyler-Regular.ttf 46 | # - asset: fonts/Schyler-Italic.ttf 47 | # style: italic 48 | # - family: Trajan Pro 49 | # fonts: 50 | # - asset: fonts/TrajanPro.ttf 51 | # - asset: fonts/TrajanPro_Bold.ttf 52 | # weight: 700 53 | # 54 | # For details regarding fonts in packages, see 55 | # https://flutter.dev/custom-fonts/#from-packages 56 | -------------------------------------------------------------------------------- /pic/a.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/pic/a.gif -------------------------------------------------------------------------------- /pic/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/pic/a.jpg -------------------------------------------------------------------------------- /pic/b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/pic/b.gif -------------------------------------------------------------------------------- /pic/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/pic/b.jpg -------------------------------------------------------------------------------- /pic/c.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/pic/c.gif -------------------------------------------------------------------------------- /pic/c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/pic/c.jpg -------------------------------------------------------------------------------- /pic/d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/pic/d.jpg -------------------------------------------------------------------------------- /yunshu_music/.dockerignore: -------------------------------------------------------------------------------- 1 | build/ 2 | !build/web/ 3 | android/ 4 | asserts/ 5 | ios/ 6 | lib/ 7 | macos/ 8 | web/ 9 | windows/ 10 | .dart_tool/ 11 | .idea/ 12 | .flutter-plugins 13 | .flutter-plugins-dependencies 14 | .metadata 15 | analysis_options.yaml 16 | AudioEffect.txt 17 | build*.cmd 18 | LICENSE 19 | pubspec.lock 20 | pubspec.yaml -------------------------------------------------------------------------------- /yunshu_music/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | 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 | -------------------------------------------------------------------------------- /yunshu_music/.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: ffccd96b62ee8cec7740dab303538c5fc26ac543 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 17 | base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 18 | - platform: windows 19 | create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 20 | base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543 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 | -------------------------------------------------------------------------------- /yunshu_music/AudioEffect.txt: -------------------------------------------------------------------------------- 1 | AcousticEchoCanceler 回音消除 2 | AutomaticGainControl 自动增益控制(AGC)。 自动增益控制(AGC)是一种音频预处理,通过升高或降低麦克风输入以匹配预设电平来自动标准化捕捉信号的输出,以便输出信号电平几乎恒定。 3 | BassBoost 低音增强 4 | DynamicsProcessing 动态处理? 5 | EnvironmentalReverb 境混响控制器 6 | Equalizer 均衡器 7 | HapticGenerator 触觉生成,音频转震动? 8 | LoudnessEnhancer 响度增强器 9 | NoiseSuppressor 噪声抑制器 10 | PresetReverb 输出混合辅助效果 11 | Virtualizer 音频虚拟化 -------------------------------------------------------------------------------- /yunshu_music/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:latest 2 | COPY build/web /usr/share/nginx/html 3 | LABEL com.centurylinklabs.watchtower.enable="false" -------------------------------------------------------------------------------- /yunshu_music/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.Properties 2 | import java.io.FileInputStream 3 | 4 | plugins { 5 | id("com.android.application") 6 | id("kotlin-android") 7 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 8 | id("dev.flutter.flutter-gradle-plugin") 9 | } 10 | 11 | val keystoreProperties = Properties() 12 | val keystorePropertiesFile = rootProject.file("key.properties") 13 | if (keystorePropertiesFile.exists()) { 14 | keystoreProperties.load(FileInputStream(keystorePropertiesFile)) 15 | } 16 | 17 | android { 18 | namespace = "top.itning.yunshu_music" 19 | compileSdk = flutter.compileSdkVersion 20 | ndkVersion = flutter.ndkVersion 21 | 22 | compileOptions { 23 | sourceCompatibility = JavaVersion.VERSION_11 24 | targetCompatibility = JavaVersion.VERSION_11 25 | } 26 | 27 | kotlinOptions { 28 | jvmTarget = JavaVersion.VERSION_11.toString() 29 | } 30 | 31 | defaultConfig { 32 | applicationId = "top.itning.yunshu_music" 33 | minSdk = 28 34 | targetSdk = flutter.targetSdkVersion 35 | versionCode = flutter.versionCode 36 | versionName = flutter.versionName 37 | } 38 | 39 | signingConfigs { 40 | create("release") { 41 | keyAlias = keystoreProperties["keyAlias"] as String? 42 | keyPassword = keystoreProperties["keyPassword"] as String? 43 | storeFile = if (keystoreProperties["storeFile"] != null) file(keystoreProperties["storeFile"] as String) else null 44 | storePassword = keystoreProperties["storePassword"] as String? 45 | } 46 | } 47 | 48 | buildTypes { 49 | release { 50 | signingConfig = signingConfigs.getByName("release") 51 | isMinifyEnabled = true 52 | isShrinkResources = true 53 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source = "../.." 60 | } 61 | 62 | dependencies { 63 | implementation("com.squareup.okhttp3:okhttp:4.12.0") 64 | implementation("com.google.android.exoplayer:exoplayer-core:2.19.1") 65 | implementation("com.google.android.exoplayer:extension-okhttp:2.19.1") 66 | implementation("androidx.media2:media2-session:1.3.0") 67 | implementation("com.tencent:mmkv-static:2.2.2") 68 | implementation("com.github.bumptech.glide:glide:4.16.0") 69 | implementation("com.github.bumptech.glide:okhttp3-integration:4.16.0") 70 | annotationProcessor("com.github.bumptech.glide:compiler:4.16.0") 71 | } -------------------------------------------------------------------------------- /yunshu_music/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | # 代码混淆压缩比,在0~7之间,默认为5,一般不做修改 23 | -optimizationpasses 5 24 | 25 | # 混合时不使用大小写混合,混合后的类名为小写 26 | -dontusemixedcaseclassnames 27 | 28 | # 指定不去忽略非公共库的类 29 | -dontskipnonpubliclibraryclasses 30 | 31 | # 这句话能够使我们的项目混淆后产生映射文件 32 | # 包含有类名->混淆后类名的映射关系 33 | -verbose 34 | 35 | # 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。 36 | -dontpreverify 37 | 38 | # 忽略警告,继续执行 39 | -ignorewarnings 40 | 41 | # 指定混淆是采用的算法,后面的参数是一个过滤器 42 | # 这个过滤器是谷歌推荐的算法,一般不做更改 43 | -optimizations !code/simplification/cast,!field/*,!class/merging/* 44 | 45 | -dontwarn javax.annotation.** 46 | -dontwarn javax.inject.** 47 | 48 | # Ignore annotation used for build tooling. 49 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 50 | 51 | # Ignore JSR 305 annotations for embedding nullability information. 52 | -dontwarn javax.annotation.** 53 | 54 | # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath. 55 | -dontwarn kotlin.Unit 56 | 57 | # Glide 58 | -keep public class * implements com.bumptech.glide.module.GlideModule 59 | -keep class * extends com.bumptech.glide.module.AppGlideModule { 60 | (...); 61 | } 62 | -keep public enum com.bumptech.glide.load.ImageHeaderParser$** { 63 | **[] $VALUES; 64 | public *; 65 | } 66 | -keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { 67 | *** rewind(); 68 | } 69 | -keep public class * implements com.bumptech.glide.module.GlideModule 70 | -keep public class * extends com.bumptech.glide.module.AppGlideModule 71 | -keep public enum com.bumptech.glide.load.ImageHeaderParser$** { 72 | **[] $VALUES; 73 | public *; 74 | } -------------------------------------------------------------------------------- /yunshu_music/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 27 | 31 | 34 | 39 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 52 | 53 | 56 | 57 | 58 | 59 | 60 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/java/top/itning/yunshu_music/channel/MusicChannel.java: -------------------------------------------------------------------------------- 1 | package top.itning.yunshu_music.channel; 2 | 3 | import io.flutter.plugin.common.MethodChannel; 4 | import top.itning.yunshu_music.service.MusicPlayDataService; 5 | 6 | /** 7 | * @author itning 8 | * @since 2021/10/13 15:39 9 | */ 10 | public class MusicChannel { 11 | public static MethodChannel methodChannel; 12 | public static MusicPlayDataService musicPlayDataService = new MusicPlayDataService(); 13 | } 14 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/java/top/itning/yunshu_music/service/MusicPlayMode.java: -------------------------------------------------------------------------------- 1 | package top.itning.yunshu_music.service; 2 | 3 | import android.support.v4.media.session.PlaybackStateCompat; 4 | 5 | /** 6 | * @author itning 7 | * @since 2021/10/12 15:05 8 | */ 9 | public enum MusicPlayMode { 10 | SEQUENCE, 11 | RANDOMLY, 12 | LOOP, 13 | ; 14 | 15 | public static MusicPlayMode fromRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) { 16 | switch (repeatMode) { 17 | case PlaybackStateCompat.REPEAT_MODE_ONE: 18 | return MusicPlayMode.LOOP; 19 | case PlaybackStateCompat.REPEAT_MODE_INVALID: 20 | case PlaybackStateCompat.REPEAT_MODE_NONE: 21 | case PlaybackStateCompat.REPEAT_MODE_ALL: 22 | case PlaybackStateCompat.REPEAT_MODE_GROUP: 23 | default: 24 | return MusicPlayMode.SEQUENCE; 25 | } 26 | } 27 | 28 | public static MusicPlayMode fromShuffleMode(@PlaybackStateCompat.ShuffleMode int shuffleMode) { 29 | switch (shuffleMode) { 30 | case PlaybackStateCompat.SHUFFLE_MODE_ALL: 31 | case PlaybackStateCompat.SHUFFLE_MODE_GROUP: 32 | return MusicPlayMode.RANDOMLY; 33 | case PlaybackStateCompat.SHUFFLE_MODE_INVALID: 34 | case PlaybackStateCompat.SHUFFLE_MODE_NONE: 35 | default: 36 | return MusicPlayMode.SEQUENCE; 37 | } 38 | } 39 | 40 | public static MusicPlayMode getNext(MusicPlayMode nowMode) { 41 | switch (nowMode) { 42 | case SEQUENCE: 43 | return MusicPlayMode.RANDOMLY; 44 | case RANDOMLY: 45 | return MusicPlayMode.LOOP; 46 | case LOOP: 47 | default: 48 | return MusicPlayMode.SEQUENCE; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/java/top/itning/yunshu_music/util/HttpClient.java: -------------------------------------------------------------------------------- 1 | package top.itning.yunshu_music.util; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import okhttp3.Call; 6 | import okhttp3.OkHttpClient; 7 | 8 | /** 9 | * @author itning 10 | * @since 2021/10/20 17:09 11 | */ 12 | public class HttpClient { 13 | 14 | public static final OkHttpClient OK_HTTP_CLIENT = okHttpClient(); 15 | 16 | private static OkHttpClient okHttpClient() { 17 | return new OkHttpClient.Builder() 18 | // 设置ping信号发送时间间隔,该选项一般用于维持Websocket/Http2长连接,发送心跳包。默认值为0表示禁用心跳机制。 19 | .pingInterval(2, TimeUnit.SECONDS) 20 | .connectTimeout(10, TimeUnit.SECONDS) 21 | .readTimeout(10, TimeUnit.SECONDS) 22 | .writeTimeout(5, TimeUnit.SECONDS) 23 | // 是否允许OkHttp自动执行失败重连,默认为true。当设置为true时,okhttp会在以下几种可能的请求失败的情况下恢复连接并重新请求:1.IP地址不可达;2.过久的池化连接;3.代理服务器不可达。 24 | .retryOnConnectionFailure(true) 25 | .build(); 26 | } 27 | 28 | public static Call.Factory getCallFactory() { 29 | return OK_HTTP_CLIENT; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/java/top/itning/yunshu_music/util/MusicAppGlideModule.java: -------------------------------------------------------------------------------- 1 | package top.itning.yunshu_music.util; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | import com.bumptech.glide.Glide; 8 | import com.bumptech.glide.Registry; 9 | import com.bumptech.glide.annotation.GlideModule; 10 | import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader; 11 | import com.bumptech.glide.load.model.GlideUrl; 12 | import com.bumptech.glide.module.AppGlideModule; 13 | 14 | import java.io.InputStream; 15 | 16 | /** 17 | * @author itning 18 | * @since 2021/10/20 16:49 19 | */ 20 | @GlideModule 21 | public class MusicAppGlideModule extends AppGlideModule { 22 | 23 | @Override 24 | public boolean isManifestParsingEnabled() { 25 | return false; 26 | } 27 | 28 | @Override 29 | public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) { 30 | registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(HttpClient.getCallFactory())); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/drawable/default_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/drawable/default_cover.jpg -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/drawable/outline_skip_next.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/drawable/outline_skip_previous.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/drawable/pause_black.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/drawable/play_black.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-hdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-hdpi/launcher_icon.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-mdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-mdpi/launcher_icon.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /yunshu_music/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /yunshu_music/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() 9 | rootProject.layout.buildDirectory.value(newBuildDir) 10 | 11 | subprojects { 12 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 13 | project.layout.buildDirectory.value(newSubprojectBuildDir) 14 | } 15 | subprojects { 16 | project.evaluationDependsOn(":app") 17 | } 18 | 19 | tasks.register("clean") { 20 | delete(rootProject.layout.buildDirectory) 21 | } 22 | -------------------------------------------------------------------------------- /yunshu_music/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /yunshu_music/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-8.12-all.zip 6 | -------------------------------------------------------------------------------- /yunshu_music/android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = run { 3 | val properties = java.util.Properties() 4 | file("local.properties").inputStream().use { properties.load(it) } 5 | val flutterSdkPath = properties.getProperty("flutter.sdk") 6 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 7 | flutterSdkPath 8 | } 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 21 | id("com.android.application") version "8.7.3" apply false 22 | id("org.jetbrains.kotlin.android") version "2.1.0" apply false 23 | } 24 | 25 | include(":app") 26 | -------------------------------------------------------------------------------- /yunshu_music/asserts/fonts/LXGWWenKaiMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/asserts/fonts/LXGWWenKaiMono-Regular.ttf -------------------------------------------------------------------------------- /yunshu_music/asserts/fonts/Roboto.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/asserts/fonts/Roboto.ttf -------------------------------------------------------------------------------- /yunshu_music/asserts/icon/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/asserts/icon/app_icon.ico -------------------------------------------------------------------------------- /yunshu_music/asserts/icon/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/asserts/icon/launcher_icon.png -------------------------------------------------------------------------------- /yunshu_music/asserts/images/default_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/asserts/images/default_cover.jpg -------------------------------------------------------------------------------- /yunshu_music/buildAll.cmd: -------------------------------------------------------------------------------- 1 | flutter clean&&flutter build web --web-renderer canvaskit --release&&flutter build apk --release --split-per-abi&&flutter build windows --release -------------------------------------------------------------------------------- /yunshu_music/buildAndroid.cmd: -------------------------------------------------------------------------------- 1 | flutter clean&&flutter build apk --release --split-per-abi -------------------------------------------------------------------------------- /yunshu_music/buildWeb.cmd: -------------------------------------------------------------------------------- 1 | flutter clean&&flutter build web --web-renderer canvaskit --release --dart-define=FLUTTER_WEB_CANVASKIT_URL="./canvaskit/" -------------------------------------------------------------------------------- /yunshu_music/buildWindows.cmd: -------------------------------------------------------------------------------- 1 | flutter clean&&flutter build windows --release -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | zh_CN 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /yunshu_music/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /yunshu_music/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /yunshu_music/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '16.4' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | target.build_configurations.each do |config| 41 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ 42 | '$(inherited)', 43 | 'AUDIO_SESSION_MICROPHONE=0' 44 | ] 45 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.4' 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /yunshu_music/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - audioplayers_darwin (0.0.1): 3 | - Flutter 4 | - Flutter (1.0.0) 5 | - music_channel_ios (0.0.1): 6 | - Flutter 7 | - package_info_plus (0.4.5): 8 | - Flutter 9 | - path_provider_foundation (0.0.1): 10 | - Flutter 11 | - FlutterMacOS 12 | - shared_preferences_foundation (0.0.1): 13 | - Flutter 14 | - FlutterMacOS 15 | - sqflite_darwin (0.0.4): 16 | - Flutter 17 | - FlutterMacOS 18 | - url_launcher_ios (0.0.1): 19 | - Flutter 20 | 21 | DEPENDENCIES: 22 | - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) 23 | - Flutter (from `Flutter`) 24 | - music_channel_ios (from `.symlinks/plugins/music_channel_ios/ios`) 25 | - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) 26 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) 27 | - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) 28 | - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) 29 | - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) 30 | 31 | EXTERNAL SOURCES: 32 | audioplayers_darwin: 33 | :path: ".symlinks/plugins/audioplayers_darwin/ios" 34 | Flutter: 35 | :path: Flutter 36 | music_channel_ios: 37 | :path: ".symlinks/plugins/music_channel_ios/ios" 38 | package_info_plus: 39 | :path: ".symlinks/plugins/package_info_plus/ios" 40 | path_provider_foundation: 41 | :path: ".symlinks/plugins/path_provider_foundation/darwin" 42 | shared_preferences_foundation: 43 | :path: ".symlinks/plugins/shared_preferences_foundation/darwin" 44 | sqflite_darwin: 45 | :path: ".symlinks/plugins/sqflite_darwin/darwin" 46 | url_launcher_ios: 47 | :path: ".symlinks/plugins/url_launcher_ios/ios" 48 | 49 | SPEC CHECKSUMS: 50 | audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 51 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 52 | music_channel_ios: 1d8db7ef624436903d31504c0bbe714b56445cf9 53 | package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 54 | path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 55 | shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 56 | sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d 57 | url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe 58 | 59 | PODFILE CHECKSUM: 31b0799760445319acd5bf496b2e28795aebee54 60 | 61 | COCOAPODS: 1.12.0 62 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 55 | 57 | 63 | 64 | 65 | 66 | 72 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | UIApplication.shared.beginReceivingRemoteControlEvents() 12 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "size": "20x20", 5 | "idiom": "iphone", 6 | "filename": "icon-20@2x.png", 7 | "scale": "2x" 8 | }, 9 | { 10 | "size": "20x20", 11 | "idiom": "iphone", 12 | "filename": "icon-20@3x.png", 13 | "scale": "3x" 14 | }, 15 | { 16 | "size": "29x29", 17 | "idiom": "iphone", 18 | "filename": "icon-29.png", 19 | "scale": "1x" 20 | }, 21 | { 22 | "size": "29x29", 23 | "idiom": "iphone", 24 | "filename": "icon-29@2x.png", 25 | "scale": "2x" 26 | }, 27 | { 28 | "size": "29x29", 29 | "idiom": "iphone", 30 | "filename": "icon-29@3x.png", 31 | "scale": "3x" 32 | }, 33 | { 34 | "size": "40x40", 35 | "idiom": "iphone", 36 | "filename": "icon-40@2x.png", 37 | "scale": "2x" 38 | }, 39 | { 40 | "size": "40x40", 41 | "idiom": "iphone", 42 | "filename": "icon-40@3x.png", 43 | "scale": "3x" 44 | }, 45 | { 46 | "size": "60x60", 47 | "idiom": "iphone", 48 | "filename": "icon-60@2x.png", 49 | "scale": "2x" 50 | }, 51 | { 52 | "size": "60x60", 53 | "idiom": "iphone", 54 | "filename": "icon-60@3x.png", 55 | "scale": "3x" 56 | }, 57 | { 58 | "size": "20x20", 59 | "idiom": "ipad", 60 | "filename": "icon-20-ipad.png", 61 | "scale": "1x" 62 | }, 63 | { 64 | "size": "20x20", 65 | "idiom": "ipad", 66 | "filename": "icon-20@2x-ipad.png", 67 | "scale": "2x" 68 | }, 69 | { 70 | "size": "29x29", 71 | "idiom": "ipad", 72 | "filename": "icon-29-ipad.png", 73 | "scale": "1x" 74 | }, 75 | { 76 | "size": "29x29", 77 | "idiom": "ipad", 78 | "filename": "icon-29@2x-ipad.png", 79 | "scale": "2x" 80 | }, 81 | { 82 | "size": "40x40", 83 | "idiom": "ipad", 84 | "filename": "icon-40.png", 85 | "scale": "1x" 86 | }, 87 | { 88 | "size": "40x40", 89 | "idiom": "ipad", 90 | "filename": "icon-40@2x.png", 91 | "scale": "2x" 92 | }, 93 | { 94 | "size": "76x76", 95 | "idiom": "ipad", 96 | "filename": "icon-76.png", 97 | "scale": "1x" 98 | }, 99 | { 100 | "size": "76x76", 101 | "idiom": "ipad", 102 | "filename": "icon-76@2x.png", 103 | "scale": "2x" 104 | }, 105 | { 106 | "size": "83.5x83.5", 107 | "idiom": "ipad", 108 | "filename": "icon-83.5@2x.png", 109 | "scale": "2x" 110 | }, 111 | { 112 | "size": "1024x1024", 113 | "idiom": "ios-marketing", 114 | "filename": "icon-1024.png", 115 | "scale": "1x" 116 | } 117 | ], 118 | "info": { 119 | "version": 1, 120 | "author": "icon.wuruihong.com" 121 | } 122 | } -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-1024.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20-ipad.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@2x-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@2x-ipad.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29-ipad.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@2x-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@2x-ipad.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-76.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /yunshu_music/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. -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | 云舒音乐 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | yunshu_music 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(FLUTTER_BUILD_NUMBER) 27 | LSRequiresIPhoneOS 28 | 29 | UIBackgroundModes 30 | 31 | audio 32 | fetch 33 | processing 34 | 35 | UILaunchStoryboardName 36 | LaunchScreen 37 | UIMainStoryboardFile 38 | Main 39 | UISupportedInterfaceOrientations 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationLandscapeLeft 43 | UIInterfaceOrientationLandscapeRight 44 | 45 | UISupportedInterfaceOrientations~ipad 46 | 47 | UIInterfaceOrientationPortrait 48 | UIInterfaceOrientationPortraitUpsideDown 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UIViewControllerBasedStatusBarAppearance 53 | 54 | UIApplicationSupportsIndirectInputEvents 55 | 56 | NSAppTransportSecurity 57 | 58 | NSAllowsArbitraryLoads 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /yunshu_music/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /yunshu_music/lib/component/lyric/lyric.dart: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright [2018] [Caijinglong] 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | 修改说明: 17 | 1. 适配dart空安全 18 | 2. 注释修改 19 | */ 20 | class Lyric { 21 | String lyric; 22 | Duration startTime; 23 | Duration? endTime; 24 | bool isRemark; 25 | 26 | Lyric( 27 | this.lyric, { 28 | required this.startTime, 29 | this.endTime, 30 | this.isRemark = false, 31 | }); 32 | 33 | @override 34 | String toString() { 35 | return 'Lyric{lyric: $lyric, startTime: $startTime, endTime: $endTime}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /yunshu_music/lib/component/lyric/lyric_controller.dart: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright [2018] [Caijinglong] 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | 修改说明: 17 | 1. 适配dart空安全 18 | 2. 注释修改 19 | */ 20 | import 'dart:async'; 21 | 22 | import 'package:flutter/material.dart'; 23 | 24 | class LyricController extends ChangeNotifier { 25 | /// 当前进度 26 | Duration progress = const Duration(); 27 | 28 | //滑动保持器 29 | Timer? draggingTimer; 30 | 31 | //滑动保持时间 32 | Duration? draggingTimerDuration; 33 | 34 | bool _isDragging = false; 35 | 36 | bool get isDragging => _isDragging; 37 | 38 | set isDragging(bool value) { 39 | _isDragging = value; 40 | notifyListeners(); 41 | } 42 | 43 | void reset() { 44 | progress = const Duration(); 45 | draggingTimer = null; 46 | draggingTimerDuration = null; 47 | _isDragging = false; 48 | draggingOffset = null; 49 | previousRowOffset = 0; 50 | oldLine = 0; 51 | draggingLine = 0; 52 | } 53 | 54 | late Duration draggingProgress; 55 | 56 | late Function draggingComplete; 57 | 58 | double? draggingOffset; 59 | 60 | //动画 存放上一次偏移量 61 | double previousRowOffset = 0; 62 | 63 | int oldLine = 0; 64 | int draggingLine = 0; 65 | } 66 | -------------------------------------------------------------------------------- /yunshu_music/lib/component/rotate_cover_image_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:yunshu_music/component/image_fade.dart'; 4 | import 'package:yunshu_music/provider/play_status_model.dart'; 5 | 6 | import '../provider/setting_model.dart'; 7 | 8 | /// 可旋转的封面图Widget 9 | class RotateCoverImageWidget extends StatefulWidget { 10 | final double width; 11 | final double height; 12 | final ImageProvider image; 13 | final Duration duration; 14 | 15 | const RotateCoverImageWidget({ 16 | super.key, 17 | required this.width, 18 | required this.height, 19 | required this.image, 20 | required this.duration, 21 | }); 22 | 23 | @override 24 | State createState() => _RotateCoverImageWidgetState(); 25 | } 26 | 27 | class _RotateCoverImageWidgetState extends State 28 | with SingleTickerProviderStateMixin { 29 | /// 封面旋转动画控制器 30 | late AnimationController _coverController; 31 | 32 | @override 33 | void initState() { 34 | super.initState(); 35 | _coverController = AnimationController( 36 | duration: widget.duration, 37 | vsync: this, 38 | ); 39 | } 40 | 41 | @override 42 | void dispose() { 43 | _coverController.dispose(); 44 | super.dispose(); 45 | } 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return Selector( 50 | builder: (_, value, Widget? child) { 51 | final enableRotation = context 52 | .read() 53 | .enableMusicCoverRotating; 54 | if (enableRotation) { 55 | value ? _coverController.repeat() : _coverController.stop(); 56 | } else { 57 | _coverController.stop(); // 强制停止旋转 58 | } 59 | return child!; 60 | }, 61 | selector: (_, model) => model.isPlayNow, 62 | child: RepaintBoundary( 63 | child: RotationTransition( 64 | alignment: Alignment.center, 65 | turns: _coverController, 66 | child: ClipOval( 67 | child: ImageFade( 68 | fit: BoxFit.cover, 69 | width: widget.width, 70 | height: widget.height, 71 | image: widget.image, 72 | ), 73 | ), 74 | ), 75 | ), 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /yunshu_music/lib/component/volume_slider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:yunshu_music/method_channel/music_channel.dart'; 4 | import 'package:yunshu_music/provider/volume_data_model.dart'; 5 | 6 | class VolumeSlider extends StatelessWidget { 7 | const VolumeSlider({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Row( 12 | mainAxisAlignment: MainAxisAlignment.center, 13 | children: [ 14 | const Icon(Icons.volume_mute, size: 20.0, color: Colors.white), 15 | Selector( 16 | builder: (_, value, _) { 17 | return Slider( 18 | activeColor: Colors.white, 19 | inactiveColor: Colors.grey, 20 | value: value, 21 | max: 1.0, 22 | min: 0.0, 23 | onChanged: (value) async { 24 | await MusicChannel.get().setVolume(value); 25 | }, 26 | ); 27 | }, 28 | selector: (_, model) => model.volume, 29 | ), 30 | const Icon(Icons.volume_up, size: 20.0, color: Colors.white), 31 | ], 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /yunshu_music/lib/generated/json/base/json_field.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: non_constant_identifier_names 2 | // ignore_for_file: camel_case_types 3 | // ignore_for_file: prefer_single_quotes 4 | 5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost. 6 | 7 | class JsonSerializable { 8 | const JsonSerializable(); 9 | } 10 | 11 | class JSONField { 12 | //Specify the parse field name 13 | final String? name; 14 | 15 | //Whether to participate in toJson 16 | final bool? serialize; 17 | 18 | //Whether to participate in fromMap 19 | final bool? deserialize; 20 | 21 | //Enumeration or not 22 | final bool? isEnum; 23 | 24 | const JSONField({this.name, this.serialize, this.deserialize, this.isEnum}); 25 | } 26 | -------------------------------------------------------------------------------- /yunshu_music/lib/generated/json/music_entity.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:yunshu_music/generated/json/base/json_convert_content.dart'; 2 | import 'package:yunshu_music/net/model/music_entity.dart'; 3 | 4 | MusicEntity $MusicEntityFromJson(Map json) { 5 | final MusicEntity musicEntity = MusicEntity(); 6 | final int? code = jsonConvert.convert(json['code']); 7 | if (code != null) { 8 | musicEntity.code = code; 9 | } 10 | final String? msg = jsonConvert.convert(json['msg']); 11 | if (msg != null) { 12 | musicEntity.msg = msg; 13 | } 14 | final List? data = jsonConvert.convertListNotNull( 15 | json['data'], 16 | ); 17 | if (data != null) { 18 | musicEntity.data = data; 19 | } 20 | return musicEntity; 21 | } 22 | 23 | Map $MusicEntityToJson(MusicEntity entity) { 24 | final Map data = {}; 25 | data['code'] = entity.code; 26 | data['msg'] = entity.msg; 27 | data['data'] = entity.data?.map((v) => v.toJson()).toList(); 28 | return data; 29 | } 30 | 31 | MusicData $MusicDataFromJson(Map json) { 32 | final MusicData musicData = MusicData(); 33 | final String? musicId = jsonConvert.convert(json['musicId']); 34 | if (musicId != null) { 35 | musicData.musicId = musicId; 36 | } 37 | final String? name = jsonConvert.convert(json['name']); 38 | if (name != null) { 39 | musicData.name = name; 40 | } 41 | final String? singer = jsonConvert.convert(json['singer']); 42 | if (singer != null) { 43 | musicData.singer = singer; 44 | } 45 | final String? lyricId = jsonConvert.convert(json['lyricId']); 46 | if (lyricId != null) { 47 | musicData.lyricId = lyricId; 48 | } 49 | final int? type = jsonConvert.convert(json['type']); 50 | if (type != null) { 51 | musicData.type = type; 52 | } 53 | final String? musicUri = jsonConvert.convert(json['musicUri']); 54 | if (musicUri != null) { 55 | musicData.musicUri = musicUri; 56 | } 57 | final String? lyricUri = jsonConvert.convert(json['lyricUri']); 58 | if (lyricUri != null) { 59 | musicData.lyricUri = lyricUri; 60 | } 61 | final String? coverUri = jsonConvert.convert(json['coverUri']); 62 | if (coverUri != null) { 63 | musicData.coverUri = coverUri; 64 | } 65 | return musicData; 66 | } 67 | 68 | Map $MusicDataToJson(MusicData entity) { 69 | final Map data = {}; 70 | data['musicId'] = entity.musicId; 71 | data['name'] = entity.name; 72 | data['singer'] = entity.singer; 73 | data['lyricId'] = entity.lyricId; 74 | data['type'] = entity.type; 75 | data['musicUri'] = entity.musicUri; 76 | data['lyricUri'] = entity.lyricUri; 77 | data['coverUri'] = entity.coverUri; 78 | return data; 79 | } 80 | -------------------------------------------------------------------------------- /yunshu_music/lib/generated/json/search_result_entity.g.dart: -------------------------------------------------------------------------------- 1 | import 'package:yunshu_music/generated/json/base/json_convert_content.dart'; 2 | import 'package:yunshu_music/net/model/search_result_entity.dart'; 3 | 4 | SearchResultEntity $SearchResultEntityFromJson(Map json) { 5 | final SearchResultEntity searchResultEntity = SearchResultEntity(); 6 | final int? code = jsonConvert.convert(json['code']); 7 | if (code != null) { 8 | searchResultEntity.code = code; 9 | } 10 | final String? msg = jsonConvert.convert(json['msg']); 11 | if (msg != null) { 12 | searchResultEntity.msg = msg; 13 | } 14 | final List? data = jsonConvert 15 | .convertListNotNull(json['data']); 16 | if (data != null) { 17 | searchResultEntity.data = data; 18 | } 19 | return searchResultEntity; 20 | } 21 | 22 | Map $SearchResultEntityToJson(SearchResultEntity entity) { 23 | final Map data = {}; 24 | data['code'] = entity.code; 25 | data['msg'] = entity.msg; 26 | data['data'] = entity.data?.map((v) => v.toJson()).toList(); 27 | return data; 28 | } 29 | 30 | SearchResultData $SearchResultDataFromJson(Map json) { 31 | final SearchResultData searchResultData = SearchResultData(); 32 | final String? musicId = jsonConvert.convert(json['musicId']); 33 | if (musicId != null) { 34 | searchResultData.musicId = musicId; 35 | } 36 | final String? name = jsonConvert.convert(json['name']); 37 | if (name != null) { 38 | searchResultData.name = name; 39 | } 40 | final String? singer = jsonConvert.convert(json['singer']); 41 | if (singer != null) { 42 | searchResultData.singer = singer; 43 | } 44 | final String? lyricId = jsonConvert.convert(json['lyricId']); 45 | if (lyricId != null) { 46 | searchResultData.lyricId = lyricId; 47 | } 48 | final int? type = jsonConvert.convert(json['type']); 49 | if (type != null) { 50 | searchResultData.type = type; 51 | } 52 | final String? musicUri = jsonConvert.convert(json['musicUri']); 53 | if (musicUri != null) { 54 | searchResultData.musicUri = musicUri; 55 | } 56 | final String? lyricUri = jsonConvert.convert(json['lyricUri']); 57 | if (lyricUri != null) { 58 | searchResultData.lyricUri = lyricUri; 59 | } 60 | final String? coverUri = jsonConvert.convert(json['coverUri']); 61 | if (coverUri != null) { 62 | searchResultData.coverUri = coverUri; 63 | } 64 | final List? highlightFields = jsonConvert.convertListNotNull( 65 | json['highlightFields'], 66 | ); 67 | if (highlightFields != null) { 68 | searchResultData.highlightFields = highlightFields; 69 | } 70 | return searchResultData; 71 | } 72 | 73 | Map $SearchResultDataToJson(SearchResultData entity) { 74 | final Map data = {}; 75 | data['musicId'] = entity.musicId; 76 | data['name'] = entity.name; 77 | data['singer'] = entity.singer; 78 | data['lyricId'] = entity.lyricId; 79 | data['type'] = entity.type; 80 | data['musicUri'] = entity.musicUri; 81 | data['lyricUri'] = entity.lyricUri; 82 | data['coverUri'] = entity.coverUri; 83 | data['highlightFields'] = entity.highlightFields; 84 | return data; 85 | } 86 | -------------------------------------------------------------------------------- /yunshu_music/lib/hotkey/action.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:yunshu_music/hotkey/intent.dart'; 3 | import 'package:yunshu_music/provider/music_data_model.dart'; 4 | import 'package:yunshu_music/provider/play_status_model.dart'; 5 | import 'package:yunshu_music/util/common_utils.dart'; 6 | 7 | class PlayPauseAction extends Action { 8 | PlayPauseAction(); 9 | 10 | @override 11 | Object? invoke(covariant PlayPauseIntent intent) { 12 | LogHelper.get().debug('PlayPauseAction trigger'); 13 | PlayStatusModel status = PlayStatusModel.get(); 14 | status.setPlay(!status.isPlayNow); 15 | return null; 16 | } 17 | } 18 | 19 | class PreviousAction extends Action { 20 | PreviousAction(); 21 | 22 | @override 23 | Object? invoke(covariant PreviousIntent intent) { 24 | LogHelper.get().debug('PreviousAction trigger'); 25 | MusicDataModel.get().toPrevious(); 26 | return null; 27 | } 28 | } 29 | 30 | class NextAction extends Action { 31 | NextAction(); 32 | 33 | @override 34 | Object? invoke(covariant NextIntent intent) { 35 | LogHelper.get().debug('NextAction trigger'); 36 | MusicDataModel.get().toNext(); 37 | return null; 38 | } 39 | } 40 | 41 | class SeekBackAction extends Action { 42 | SeekBackAction(); 43 | 44 | @override 45 | Object? invoke(covariant SeekBackIntent intent) { 46 | LogHelper.get().debug('SeekBackAction trigger'); 47 | PlayStatusModel status = PlayStatusModel.get(); 48 | // default decrease one seconds. 49 | status.seek(status.position - const Duration(seconds: 1)); 50 | return null; 51 | } 52 | } 53 | 54 | class SeekForwardAction extends Action { 55 | SeekForwardAction(); 56 | 57 | @override 58 | Object? invoke(covariant SeekForwardIntent intent) { 59 | LogHelper.get().debug('SeekForwardAction trigger'); 60 | PlayStatusModel status = PlayStatusModel.get(); 61 | // default add one seconds. 62 | status.seek(status.position + const Duration(seconds: 1)); 63 | return null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /yunshu_music/lib/hotkey/intent.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 播放暂停意图 4 | class PlayPauseIntent extends Intent { 5 | const PlayPauseIntent(); 6 | } 7 | 8 | /// 上一曲意图 9 | class PreviousIntent extends Intent { 10 | const PreviousIntent(); 11 | } 12 | 13 | /// 下一曲意图 14 | class NextIntent extends Intent { 15 | const NextIntent(); 16 | } 17 | 18 | /// 进度后退意图 19 | class SeekBackIntent extends Intent { 20 | const SeekBackIntent(); 21 | } 22 | 23 | /// 进度前进意图 24 | class SeekForwardIntent extends Intent { 25 | const SeekForwardIntent(); 26 | } 27 | -------------------------------------------------------------------------------- /yunshu_music/lib/net/model/music_entity.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:yunshu_music/generated/json/base/json_field.dart'; 4 | import 'package:yunshu_music/generated/json/music_entity.g.dart'; 5 | 6 | @JsonSerializable() 7 | class MusicEntity { 8 | int? code; 9 | String? msg; 10 | List? data; 11 | 12 | MusicEntity(); 13 | 14 | factory MusicEntity.fromJson(Map json) => 15 | $MusicEntityFromJson(json); 16 | 17 | Map toJson() => $MusicEntityToJson(this); 18 | 19 | @override 20 | String toString() { 21 | return jsonEncode(this); 22 | } 23 | } 24 | 25 | @JsonSerializable() 26 | class MusicData { 27 | String? musicId; 28 | String? name; 29 | String? singer; 30 | String? lyricId; 31 | int? type; 32 | String? musicUri; 33 | String? lyricUri; 34 | String? coverUri; 35 | 36 | MusicData(); 37 | 38 | factory MusicData.fromJson(Map json) => 39 | $MusicDataFromJson(json); 40 | 41 | Map toJson() => $MusicDataToJson(this); 42 | 43 | @override 44 | String toString() { 45 | return jsonEncode(this); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /yunshu_music/lib/net/model/search_result_entity.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:yunshu_music/generated/json/base/json_field.dart'; 4 | import 'package:yunshu_music/generated/json/search_result_entity.g.dart'; 5 | 6 | @JsonSerializable() 7 | class SearchResultEntity { 8 | int? code; 9 | String? msg; 10 | List? data; 11 | 12 | SearchResultEntity(); 13 | 14 | factory SearchResultEntity.fromJson(Map json) => 15 | $SearchResultEntityFromJson(json); 16 | 17 | Map toJson() => $SearchResultEntityToJson(this); 18 | 19 | @override 20 | String toString() { 21 | return jsonEncode(this); 22 | } 23 | } 24 | 25 | @JsonSerializable() 26 | class SearchResultData { 27 | String? musicId; 28 | String? name; 29 | String? singer; 30 | String? lyricId; 31 | int? type; 32 | String? musicUri; 33 | String? lyricUri; 34 | String? coverUri; 35 | List? highlightFields; 36 | 37 | SearchResultData(); 38 | 39 | factory SearchResultData.fromJson(Map json) => 40 | $SearchResultDataFromJson(json); 41 | 42 | Map toJson() => $SearchResultDataToJson(this); 43 | 44 | @override 45 | String toString() { 46 | return jsonEncode(this); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /yunshu_music/lib/page/login/login_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:go_router/go_router.dart'; 3 | import 'package:yunshu_music/provider/login_model.dart'; 4 | 5 | class LoginPage extends StatefulWidget { 6 | const LoginPage({super.key}); 7 | 8 | @override 9 | State createState() => _LoginPageState(); 10 | } 11 | 12 | class _LoginPageState extends State { 13 | final GlobalKey _formKey = GlobalKey(); 14 | final TextEditingController _controller = TextEditingController(); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | String? baseUrl = LoginModel.get().getBaseUrl(); 19 | _controller.text = baseUrl ?? ''; 20 | return Scaffold( 21 | appBar: AppBar(title: const Text('设置音乐源')), 22 | body: Form( 23 | key: _formKey, 24 | autovalidateMode: AutovalidateMode.onUserInteraction, 25 | child: Column( 26 | children: [ 27 | TextFormField( 28 | autofocus: true, 29 | controller: _controller, 30 | keyboardType: TextInputType.url, 31 | textInputAction: TextInputAction.done, 32 | onEditingComplete: setBaseUrl, 33 | decoration: const InputDecoration( 34 | labelText: "音乐源", 35 | hintText: "https://example.com", 36 | prefixIcon: Icon(Icons.web), 37 | ), 38 | validator: (v) { 39 | if (v!.trim().isEmpty) { 40 | return "音乐源不能为空"; 41 | } 42 | if (!v.trim().startsWith("http://") && 43 | !v.trim().startsWith("https://")) { 44 | return "必须http/https协议开头"; 45 | } 46 | return null; 47 | }, 48 | ), 49 | Padding( 50 | padding: const EdgeInsets.only( 51 | top: 12.0, 52 | left: 12.0, 53 | right: 12.0, 54 | ), 55 | child: SizedBox( 56 | height: 35, 57 | width: double.infinity, 58 | child: ElevatedButton( 59 | onPressed: setBaseUrl, 60 | child: const Text('设置'), 61 | ), 62 | ), 63 | ), 64 | ], 65 | ), 66 | ), 67 | ); 68 | } 69 | 70 | void setBaseUrl() async { 71 | if ((_formKey.currentState as FormState).validate()) { 72 | await LoginModel.get().setBaseUrl(_controller.text.trim()); 73 | if (mounted) { 74 | if (Navigator.canPop(context)) { 75 | Navigator.pop(context); 76 | } else { 77 | context.go('/'); 78 | } 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /yunshu_music/lib/page/music_list/component/music_list_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:yunshu_music/provider/music_data_model.dart'; 4 | 5 | /// 列表项 6 | class MusicListItem extends StatelessWidget { 7 | final int index; 8 | final String? title; 9 | final String? subTitle; 10 | final IconData? rightButtonIcon; 11 | final GestureTapCallback? onTap; 12 | final GestureLongPressCallback? onLongPress; 13 | final VoidCallback? rightButtonTap; 14 | 15 | const MusicListItem({ 16 | super.key, 17 | required this.index, 18 | this.title, 19 | this.subTitle, 20 | this.rightButtonIcon, 21 | this.onTap, 22 | this.onLongPress, 23 | this.rightButtonTap, 24 | }); 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return InkWell( 29 | onLongPress: onLongPress, 30 | onTap: onTap, 31 | child: Container( 32 | margin: const EdgeInsets.only(bottom: 7.0, top: 7.0), 33 | child: Flex( 34 | direction: Axis.horizontal, 35 | children: [ 36 | Expanded(flex: 2, child: _MusicListItemIndex(index: index)), 37 | Expanded( 38 | flex: 11, 39 | child: Column( 40 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 41 | crossAxisAlignment: CrossAxisAlignment.start, 42 | children: [ 43 | Text( 44 | '$title', 45 | overflow: TextOverflow.ellipsis, 46 | style: const TextStyle(fontSize: 16.0), 47 | ), 48 | Text( 49 | '$subTitle', 50 | overflow: TextOverflow.ellipsis, 51 | style: const TextStyle(fontSize: 12.0, color: Colors.grey), 52 | ), 53 | ], 54 | ), 55 | ), 56 | Expanded( 57 | flex: 2, 58 | child: IconButton( 59 | onPressed: rightButtonTap, 60 | icon: Icon(rightButtonIcon, color: Colors.grey), 61 | ), 62 | ), 63 | ], 64 | ), 65 | ), 66 | ); 67 | } 68 | } 69 | 70 | class _MusicListItemIndex extends StatelessWidget { 71 | final int index; 72 | 73 | const _MusicListItemIndex({required this.index}); 74 | 75 | @override 76 | Widget build(BuildContext context) { 77 | return Selector( 78 | builder: (BuildContext context, i, Widget? child) { 79 | if (i != index) { 80 | return Text( 81 | '${index + 1}', 82 | textAlign: TextAlign.center, 83 | style: const TextStyle(color: Colors.grey), 84 | ); 85 | } else { 86 | return const Icon(Icons.equalizer, color: Colors.black); 87 | } 88 | }, 89 | selector: (_, model) => model.nowMusicIndex, 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /yunshu_music/lib/page/music_list/music_index_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_app_minimizer_plus/flutter_app_minimizer_plus.dart'; 4 | import 'package:go_router/go_router.dart'; 5 | import 'package:yunshu_music/hotkey/action.dart'; 6 | import 'package:yunshu_music/hotkey/intent.dart'; 7 | import 'package:yunshu_music/page/music_list/component/music_list.dart'; 8 | import 'package:yunshu_music/page/music_list/component/music_mini_play_controller_widget.dart'; 9 | import 'package:yunshu_music/page/music_list/component/music_search_delegate.dart'; 10 | import 'package:yunshu_music/util/log_console.dart'; 11 | 12 | /// 音乐列表 13 | class MusicIndexPage extends StatelessWidget { 14 | const MusicIndexPage({super.key}); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return PopScope( 19 | canPop: false, 20 | onPopInvokedWithResult: (bool didPop, Object? result) { 21 | if (!kIsWeb && !didPop) { 22 | FlutterAppMinimizerPlus.minimizeApp(); 23 | } 24 | }, 25 | child: Actions( 26 | actions: { 27 | PlayPauseIntent: PlayPauseAction(), 28 | PreviousIntent: PreviousAction(), 29 | NextIntent: NextAction(), 30 | }, 31 | child: Focus( 32 | autofocus: true, 33 | child: Scaffold( 34 | appBar: AppBar( 35 | title: const Text('云舒音乐'), 36 | actions: [ 37 | IconButton( 38 | tooltip: '搜索', 39 | onPressed: () { 40 | showSearch( 41 | context: context, 42 | delegate: MusicSearchDelegate(), 43 | ); 44 | }, 45 | icon: const Icon(Icons.search), 46 | ), 47 | PopupMenuButton( 48 | tooltip: '菜单', 49 | onSelected: (value) { 50 | if (value == '设置') { 51 | context.push('/setting'); 52 | } else { 53 | LogConsole.openLogConsole(context); 54 | } 55 | }, 56 | itemBuilder: (BuildContext context) { 57 | return {'设置', '日志'}.map((String choice) { 58 | return PopupMenuItem( 59 | value: choice, 60 | child: Text(choice), 61 | ); 62 | }).toList(); 63 | }, 64 | ), 65 | ], 66 | ), 67 | body: const MusicList(), 68 | bottomNavigationBar: const MusicMiniPlayControllerWidget(), 69 | ), 70 | ), 71 | ), 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /yunshu_music/lib/page/music_play/component/cover_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | import 'package:yunshu_music/component/rotate_cover_image_widget.dart'; 6 | import 'package:yunshu_music/provider/music_data_model.dart'; 7 | import 'package:yunshu_music/util/common_utils.dart'; 8 | 9 | /// 封面页 10 | class CoverPage extends StatefulWidget { 11 | const CoverPage({super.key}); 12 | 13 | @override 14 | State createState() => _CoverPageState(); 15 | } 16 | 17 | class _CoverPageState extends State 18 | with AutomaticKeepAliveClientMixin { 19 | @override 20 | Widget build(BuildContext context) { 21 | super.build(context); 22 | return Center( 23 | child: Selector( 24 | selector: (_, model) => model.coverBase64, 25 | builder: (_, value, _) { 26 | bool largeMode = isLargeMode(context); 27 | if (value == null) { 28 | return RotateCoverImageWidget( 29 | width: largeMode ? 325 : 225, 30 | height: largeMode ? 325 : 225, 31 | duration: const Duration(seconds: 20), 32 | image: Image.asset('asserts/images/default_cover.jpg').image, 33 | ); 34 | } else { 35 | return RotateCoverImageWidget( 36 | width: largeMode ? 325 : 225, 37 | height: largeMode ? 325 : 225, 38 | duration: const Duration(seconds: 20), 39 | image: Image.memory(value).image, 40 | ); 41 | } 42 | }, 43 | ), 44 | ); 45 | } 46 | 47 | @override 48 | bool get wantKeepAlive => true; 49 | } 50 | -------------------------------------------------------------------------------- /yunshu_music/lib/page/music_play/component/lyric_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_windowmanager_plus/flutter_windowmanager_plus.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'package:yunshu_music/component/lyric/lyric.dart'; 8 | import 'package:yunshu_music/component/lyric/lyric_controller.dart'; 9 | import 'package:yunshu_music/component/lyric/lyric_widget.dart'; 10 | import 'package:yunshu_music/component/volume_slider.dart'; 11 | import 'package:yunshu_music/provider/music_data_model.dart'; 12 | import 'package:yunshu_music/provider/play_status_model.dart'; 13 | import 'package:yunshu_music/util/common_utils.dart'; 14 | 15 | /// 歌词页 16 | class LyricPage extends StatefulWidget { 17 | const LyricPage({super.key}); 18 | 19 | @override 20 | State createState() => _LyricPageState(); 21 | } 22 | 23 | class _LyricPageState extends State 24 | with AutomaticKeepAliveClientMixin { 25 | @override 26 | void dispose() { 27 | if (!kIsWeb && Platform.isAndroid) { 28 | FlutterWindowManagerPlus.clearFlags( 29 | FlutterWindowManagerPlus.FLAG_KEEP_SCREEN_ON, 30 | ); 31 | } 32 | super.dispose(); 33 | } 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | super.build(context); 38 | return Column( 39 | children: [ 40 | if (kIsWeb || !Platform.isAndroid) const VolumeSlider(), 41 | Expanded( 42 | child: Stack( 43 | alignment: Alignment.center, 44 | children: [ 45 | Center( 46 | child: Selector?>( 47 | selector: (_, data) => data.lyricList, 48 | builder: (_, value, _) { 49 | if (null == value || value.isEmpty) { 50 | return const Text( 51 | '该歌曲暂无歌词', 52 | style: TextStyle(color: Colors.white), 53 | ); 54 | } else { 55 | return RepaintBoundary( 56 | child: LyricWidget( 57 | key: UniqueKey(), 58 | size: const Size(double.infinity, double.infinity), 59 | lyrics: value, 60 | controller: context.read(), 61 | ), 62 | ); 63 | } 64 | }, 65 | ), 66 | ), 67 | Selector( 68 | selector: (_, c) => c.isDragging, 69 | builder: (BuildContext context, value, _) { 70 | return Offstage( 71 | offstage: !value, 72 | child: GestureDetector( 73 | onTap: () { 74 | //点击选择器后移动歌词到滑动位置; 75 | context.read().draggingComplete(); 76 | //当前进度 77 | LogHelper.get().debug( 78 | "进度:${context.read().draggingProgress}", 79 | ); 80 | context.read().seek( 81 | context.read().draggingProgress, 82 | ); 83 | }, 84 | child: Row( 85 | children: const [ 86 | Icon(Icons.play_arrow, color: Colors.white), 87 | Expanded(child: Divider(color: Colors.grey)), 88 | ], 89 | ), 90 | ), 91 | ); 92 | }, 93 | ), 94 | ], 95 | ), 96 | ), 97 | ], 98 | ); 99 | } 100 | 101 | @override 102 | bool get wantKeepAlive => true; 103 | } 104 | -------------------------------------------------------------------------------- /yunshu_music/lib/page/music_play/component/player_page_bottom_navigation_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:yunshu_music/page/music_play/component/player_page_controller.dart'; 3 | import 'package:yunshu_music/page/music_play/component/player_page_progress.dart'; 4 | 5 | class PlayerPageBottomNavigationBar extends StatelessWidget { 6 | const PlayerPageBottomNavigationBar({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return SizedBox( 11 | height: 112.0, 12 | child: Column( 13 | mainAxisAlignment: MainAxisAlignment.center, 14 | children: const [PlayerPageProgress(), PlayerPageController()], 15 | ), 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /yunshu_music/lib/page/music_play/component/player_page_progress.dart: -------------------------------------------------------------------------------- 1 | import 'package:audio_video_progress_bar/audio_video_progress_bar.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:tuple/tuple.dart'; 5 | import 'package:yunshu_music/provider/play_status_model.dart'; 6 | 7 | /// 播放页进度 8 | class PlayerPageProgress extends StatelessWidget { 9 | const PlayerPageProgress({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | margin: const EdgeInsetsDirectional.only( 15 | start: 16.0, 16 | end: 16.0, 17 | bottom: 12.0, 18 | ), 19 | child: Selector>( 20 | builder: (context, value, _) => ProgressBar( 21 | timeLabelLocation: TimeLabelLocation.sides, 22 | progressBarColor: Colors.white, 23 | baseBarColor: Colors.white.withAlpha((255.0 * 0.24).round()), 24 | bufferedBarColor: Colors.white.withAlpha((255 * 0.24).round()), 25 | thumbColor: Colors.white, 26 | thumbGlowColor: Colors.white, 27 | timeLabelTextStyle: const TextStyle(color: Colors.white), 28 | thumbGlowRadius: 15.0, 29 | barHeight: 3.0, 30 | thumbRadius: 5.0, 31 | total: value.item1, 32 | progress: value.item2, 33 | buffered: value.item3, 34 | onSeek: (duration) => context.read().seek(duration), 35 | ), 36 | selector: (_, status) => 37 | Tuple3(status.duration, status.position, status.bufferedPosition), 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /yunshu_music/lib/page/music_play/component/title_music_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:yunshu_music/net/model/music_entity.dart'; 4 | import 'package:yunshu_music/provider/music_data_model.dart'; 5 | 6 | class TitleMusicInfo extends StatelessWidget { 7 | const TitleMusicInfo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Selector( 12 | selector: (_, model) => model.getNowPlayMusic(), 13 | builder: (BuildContext context, value, Widget? child) { 14 | if (value == null) { 15 | return const Text('云舒音乐'); 16 | } 17 | return Column( 18 | children: [ 19 | Text( 20 | value.name ?? '', 21 | style: const TextStyle(fontSize: 18.0, color: Colors.white), 22 | overflow: TextOverflow.ellipsis, 23 | ), 24 | Text( 25 | value.singer ?? '', 26 | style: const TextStyle(fontSize: 10.0, color: Colors.white), 27 | overflow: TextOverflow.ellipsis, 28 | ), 29 | ], 30 | ); 31 | }, 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /yunshu_music/lib/provider/login_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | 4 | class LoginModel extends ChangeNotifier { 5 | static const String _baseUrlKey = "BASE_URL"; 6 | 7 | static LoginModel? _instance; 8 | 9 | static LoginModel get() { 10 | _instance ??= LoginModel(); 11 | return _instance!; 12 | } 13 | 14 | late SharedPreferences sharedPreferences; 15 | 16 | Future init(SharedPreferences sharedPreferences) async { 17 | this.sharedPreferences = sharedPreferences; 18 | } 19 | 20 | bool isLogin() { 21 | return sharedPreferences.getString(_baseUrlKey) != null; 22 | } 23 | 24 | Future setBaseUrl(String url) async { 25 | return await sharedPreferences.setString(_baseUrlKey, url); 26 | } 27 | 28 | String? getBaseUrl() { 29 | return sharedPreferences.getString(_baseUrlKey); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /yunshu_music/lib/provider/music_list_status_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 音乐列表状态 4 | class MusicListStatusModel extends ChangeNotifier { 5 | static MusicListStatusModel? _instance; 6 | 7 | static MusicListStatusModel get() { 8 | _instance ??= MusicListStatusModel(); 9 | return _instance!; 10 | } 11 | 12 | bool _visible = true; 13 | 14 | bool get visible => _visible; 15 | 16 | set visible(bool status) { 17 | _visible = status; 18 | notifyListeners(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /yunshu_music/lib/provider/play_status_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:yunshu_music/method_channel/music_channel.dart'; 3 | import 'package:yunshu_music/provider/music_data_model.dart'; 4 | 5 | /// 播放状态 6 | class PlayStatusModel extends ChangeNotifier { 7 | static PlayStatusModel? _instance; 8 | 9 | static PlayStatusModel get() { 10 | _instance ??= PlayStatusModel(); 11 | return _instance!; 12 | } 13 | 14 | /// 播放进度,实时 15 | Duration _position = const Duration(); 16 | 17 | /// 音频持续时间 18 | Duration _duration = const Duration(); 19 | 20 | /// 缓冲时间 21 | Duration _bufferedPosition = const Duration(); 22 | 23 | int _state = 0; 24 | 25 | /// 当前播放进度 26 | Duration get position => _position; 27 | 28 | /// 当前音频时长 29 | Duration get duration => _duration; 30 | 31 | /// 缓冲时间 32 | Duration get bufferedPosition => _bufferedPosition; 33 | 34 | /// 播放器状态 35 | bool get processingState => _state == 8; 36 | 37 | /// 现在正在播放吗? 38 | bool get isPlayNow => _state == 3; 39 | 40 | PlayStatusModel() { 41 | MusicChannel.get().metadataEvent.listen((event) { 42 | _duration = Duration(milliseconds: event['duration']); 43 | MusicDataModel.get().onMetadataChange(event); 44 | notifyListeners(); 45 | }); 46 | MusicChannel.get().playbackStateEvent.listen((event) { 47 | _bufferedPosition = Duration(milliseconds: event['bufferedPosition']); 48 | _position = Duration(milliseconds: event['position']); 49 | _state = event['state']; 50 | notifyListeners(); 51 | }); 52 | } 53 | 54 | /// 手动更新播放进度 55 | Future seek(Duration? position) async { 56 | if (null == position) { 57 | return; 58 | } 59 | await MusicChannel.get().seekTo(position); 60 | } 61 | 62 | /// 设置音频源 63 | Future setSource(String musicId) async { 64 | await MusicChannel.get().playFromId(musicId); 65 | } 66 | 67 | /// 设置播放状态 68 | Future setPlay(bool needPlay) async { 69 | needPlay 70 | ? await MusicChannel.get().play() 71 | : await MusicChannel.get().pause(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /yunshu_music/lib/provider/search_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:yunshu_music/net/http_helper.dart'; 5 | import 'package:yunshu_music/net/model/music_entity.dart'; 6 | import 'package:yunshu_music/net/model/search_result_entity.dart'; 7 | import 'package:yunshu_music/provider/music_data_model.dart'; 8 | 9 | class SearchModel extends ChangeNotifier { 10 | static SearchModel? _instance; 11 | 12 | static SearchModel get() { 13 | _instance ??= SearchModel(); 14 | return _instance!; 15 | } 16 | 17 | List _searchResults = []; 18 | 19 | List get searchResults => _searchResults; 20 | 21 | Timer? _debounce; 22 | 23 | void search(String keyword) async { 24 | if (keyword.trim() == '') { 25 | _searchResults = []; 26 | return; 27 | } 28 | if (_debounce?.isActive ?? false) { 29 | _debounce?.cancel(); 30 | } 31 | _debounce = Timer(const Duration(milliseconds: 500), () async { 32 | await _innerSearch(keyword); 33 | }); 34 | } 35 | 36 | Future _innerSearch(String keyword) async { 37 | List result = MusicDataModel.get().search(keyword); 38 | SearchResultEntity? searchResultEntity = await HttpHelper.get().search( 39 | keyword, 40 | ); 41 | // 合并 42 | List data = searchResultEntity?.data ?? []; 43 | List list = [ 44 | ...(result 45 | .map((item) => SearchResultItem.fromMusicDataContent(item)) 46 | .toList()), 47 | ...(data 48 | .map((item) => SearchResultItem.fromSearchResultData(item)) 49 | .toList()), 50 | ]; 51 | _searchResults = list; 52 | notifyListeners(); 53 | } 54 | } 55 | 56 | class SearchResultItem { 57 | bool fromLyric = false; 58 | String? musicId; 59 | String? name; 60 | String? singer; 61 | String? lyricId; 62 | int? type; 63 | String? musicUri; 64 | String? lyricUri; 65 | String? coverUri; 66 | List? highlightFields; 67 | 68 | SearchResultItem( 69 | this.fromLyric, 70 | this.musicId, 71 | this.name, 72 | this.singer, 73 | this.lyricId, 74 | this.type, 75 | this.musicUri, 76 | this.lyricUri, 77 | this.coverUri, 78 | this.highlightFields, 79 | ); 80 | 81 | static SearchResultItem fromMusicDataContent(MusicData musicDataContent) { 82 | return SearchResultItem( 83 | false, 84 | musicDataContent.musicId, 85 | musicDataContent.name, 86 | musicDataContent.singer, 87 | musicDataContent.lyricId, 88 | musicDataContent.type, 89 | musicDataContent.musicUri, 90 | musicDataContent.lyricUri, 91 | musicDataContent.coverUri, 92 | null, 93 | ); 94 | } 95 | 96 | static SearchResultItem fromSearchResultData( 97 | SearchResultData searchResultData, 98 | ) { 99 | return SearchResultItem( 100 | true, 101 | searchResultData.musicId, 102 | searchResultData.name, 103 | searchResultData.singer, 104 | searchResultData.lyricId, 105 | searchResultData.type, 106 | searchResultData.musicUri, 107 | searchResultData.lyricUri, 108 | searchResultData.coverUri, 109 | searchResultData.highlightFields, 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /yunshu_music/lib/provider/setting_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | 4 | class SettingModel extends ChangeNotifier { 5 | static const String _router2PlayPageWhenClickPlayListItemKey = 6 | "ROUTER_2_PLAY_PAGE_WHEN_CLICK_PLAY_LIST_ITEM"; 7 | 8 | static const String _playPageAutoChangeLargeModeKey = 9 | "PLAY_PAGE_AUTO_CHANGE_LARGE_MODE"; 10 | 11 | static const String _useMaterial3ThemeKey = "USE_MATERIAL3_THEME"; 12 | 13 | static const String _enableMusicCoverRotatingKey = 14 | "ENABLE_MUSIC_COVER_ROTATING"; 15 | 16 | static SettingModel? _instance; 17 | 18 | static SettingModel get() { 19 | _instance ??= SettingModel(); 20 | return _instance!; 21 | } 22 | 23 | late SharedPreferences sharedPreferences; 24 | 25 | late bool _router2PlayPageWhenClickPlayListItem; 26 | 27 | late bool _playPageAutoChangeLargeMode; 28 | 29 | late bool _useMaterial3Theme; 30 | 31 | late bool _enableMusicCoverRotating; 32 | 33 | bool get router2PlayPageWhenClickPlayListItem => 34 | _router2PlayPageWhenClickPlayListItem; 35 | 36 | bool get playPageAutoChangeLargeMode => _playPageAutoChangeLargeMode; 37 | 38 | bool get useMaterial3Theme => _useMaterial3Theme; 39 | 40 | bool get enableMusicCoverRotating => _enableMusicCoverRotating; 41 | 42 | SettingModel(); 43 | 44 | Future init(SharedPreferences sharedPreferences) async { 45 | this.sharedPreferences = sharedPreferences; 46 | _router2PlayPageWhenClickPlayListItem = 47 | sharedPreferences.getBool(_router2PlayPageWhenClickPlayListItemKey) ?? 48 | true; 49 | _playPageAutoChangeLargeMode = 50 | sharedPreferences.getBool(_playPageAutoChangeLargeModeKey) ?? true; 51 | 52 | _useMaterial3Theme = 53 | sharedPreferences.getBool(_useMaterial3ThemeKey) ?? true; 54 | 55 | _enableMusicCoverRotating = 56 | sharedPreferences.getBool(_enableMusicCoverRotatingKey) ?? true; 57 | } 58 | 59 | Future setRouter2PlayPageWhenClickPlayListItem(bool enabled) async { 60 | await sharedPreferences.setBool( 61 | _router2PlayPageWhenClickPlayListItemKey, 62 | enabled, 63 | ); 64 | _router2PlayPageWhenClickPlayListItem = enabled; 65 | notifyListeners(); 66 | } 67 | 68 | Future setPlayPageAutoChangeLargeMode(bool enabled) async { 69 | await sharedPreferences.setBool(_playPageAutoChangeLargeModeKey, enabled); 70 | _playPageAutoChangeLargeMode = enabled; 71 | notifyListeners(); 72 | } 73 | 74 | Future setUseMaterial3Theme(bool enabled) async { 75 | await sharedPreferences.setBool(_useMaterial3ThemeKey, enabled); 76 | _useMaterial3Theme = enabled; 77 | notifyListeners(); 78 | } 79 | 80 | Future setEnableMusicCoverRotating(bool enabled) async { 81 | await sharedPreferences.setBool(_enableMusicCoverRotatingKey, enabled); 82 | _enableMusicCoverRotating = enabled; 83 | notifyListeners(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /yunshu_music/lib/provider/theme_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | 4 | /// 主题 5 | class ThemeModel extends ChangeNotifier { 6 | static const String _themeModeKey = "THEME_MODE"; 7 | 8 | static ThemeModel? _instance; 9 | 10 | static ThemeModel get() { 11 | _instance ??= ThemeModel(); 12 | return _instance!; 13 | } 14 | 15 | late ThemeMode _themeMode; 16 | 17 | ThemeMode get themeMode => _themeMode; 18 | 19 | Future init(SharedPreferences sharedPreferences) async { 20 | String? themeMode = sharedPreferences.getString(_themeModeKey); 21 | _themeMode = _fromString(themeMode); 22 | } 23 | 24 | ThemeMode _fromString(String? theme) { 25 | if (null == theme) { 26 | return ThemeMode.light; 27 | } 28 | switch (theme) { 29 | case 'ThemeMode.system': 30 | return ThemeMode.system; 31 | case 'ThemeMode.dark': 32 | return ThemeMode.dark; 33 | case 'ThemeMode.light': 34 | return ThemeMode.light; 35 | default: 36 | return ThemeMode.light; 37 | } 38 | } 39 | 40 | Future setDarkTheme(bool darkMode) async { 41 | await setTheme(darkMode ? ThemeMode.dark : ThemeMode.light); 42 | } 43 | 44 | Future setFollowSystemTheme(bool followSystem) async { 45 | await setTheme(followSystem ? ThemeMode.system : ThemeMode.light); 46 | } 47 | 48 | Future setTheme(ThemeMode themeMode) async { 49 | SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); 50 | await sharedPreferences.setString(_themeModeKey, themeMode.toString()); 51 | _themeMode = themeMode; 52 | notifyListeners(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /yunshu_music/lib/provider/volume_data_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | import 'package:yunshu_music/method_channel/music_channel.dart'; 6 | 7 | class VolumeDataModel extends ChangeNotifier { 8 | static const String _volumeKey = "MUSIC_VOLUME"; 9 | 10 | static VolumeDataModel? _instance; 11 | 12 | static VolumeDataModel get() { 13 | _instance ??= VolumeDataModel(); 14 | return _instance!; 15 | } 16 | 17 | late SharedPreferences sharedPreferences; 18 | 19 | double _volume = 0.0; 20 | 21 | double get volume => _volume; 22 | 23 | VolumeDataModel() { 24 | if (!kIsWeb && Platform.isAndroid) { 25 | return; 26 | } 27 | MusicChannel.get().volumeEvent.listen((event) { 28 | _volume = event; 29 | sharedPreferences.setDouble(_volumeKey, event); 30 | notifyListeners(); 31 | }); 32 | } 33 | 34 | Future init(SharedPreferences sharedPreferences) async { 35 | if (!kIsWeb && Platform.isAndroid) { 36 | return; 37 | } 38 | this.sharedPreferences = sharedPreferences; 39 | _volume = sharedPreferences.getDouble(_volumeKey) ?? 1.0; 40 | await MusicChannel.get().setVolume(_volume); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /yunshu_music/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /yunshu_music/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /yunshu_music/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /yunshu_music/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import audioplayers_darwin 9 | import music_channel_macos 10 | import package_info_plus 11 | import path_provider_foundation 12 | import screen_retriever_macos 13 | import shared_preferences_foundation 14 | import sqflite_darwin 15 | import system_tray 16 | import url_launcher_macos 17 | import window_manager 18 | import window_size 19 | 20 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 21 | AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) 22 | MusicChannelMacosPlugin.register(with: registry.registrar(forPlugin: "MusicChannelMacosPlugin")) 23 | FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) 24 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 25 | ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) 26 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 27 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 28 | SystemTrayPlugin.register(with: registry.registrar(forPlugin: "SystemTrayPlugin")) 29 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 30 | WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) 31 | WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) 32 | } 33 | -------------------------------------------------------------------------------- /yunshu_music/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '13.3' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /yunshu_music/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 false 8 | } 9 | 10 | override func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows flag: Bool) -> Bool { 11 | if !flag { 12 | for window: AnyObject in NSApplication.shared.windows { 13 | window.makeKeyAndOrderFront(self) 14 | } 15 | } 16 | return true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /yunshu_music/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 = 云舒音乐 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = top.itning.yunshuMusic 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2022 itning.top All rights reserved. 15 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | com.apple.security.network.client 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | //self.setFrame(windowFrame, display: true) 10 | self.setFrame(NSRect(x:0, y:0, width: 1200, height: 900), display: true) 11 | 12 | RegisterGeneratedPlugins(registry: flutterViewController) 13 | 14 | super.awakeFromNib() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /yunshu_music/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.server 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /yunshu_music/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: yunshu_music 2 | description: YunShu Music 3 | publish_to: 'none' 4 | version: 1.3.0+55 5 | 6 | environment: 7 | sdk: ^3.8.1 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | flutter_localizations: 13 | sdk: flutter 14 | cupertino_icons: ^1.0.8 15 | music_channel: 16 | path: ../music_channel 17 | provider: ^6.1.5 18 | tuple: ^2.0.2 19 | dio: ^5.8.0+1 20 | flutter_app_minimizer_plus: ^1.0.2 21 | shared_preferences: ^2.5.3 22 | shimmer: ^3.0.0 23 | audio_video_progress_bar: ^2.0.3 24 | sqflite: ^2.4.2 25 | url_launcher: ^6.3.1 26 | logger: ^2.5.0 27 | crypto: ^3.0.6 28 | path_provider: ^2.1.5 29 | mime_type: ^1.0.1 30 | package_info_plus: ^8.3.0 31 | flutter_update_dialog: ^2.0.0 32 | flutter_windowmanager_plus: ^1.0.1 33 | go_router: ^15.1.2 34 | windows_single_instance: ^1.0.1 35 | motion_toast: 2.14.0 36 | path: ^1.9.1 37 | 38 | dev_dependencies: 39 | flutter_test: 40 | sdk: flutter 41 | flutter_lints: ^6.0.0 42 | flutter_launcher_icons: ^0.14.3 43 | msix: ^3.16.9 44 | 45 | flutter_icons: 46 | android: "launcher_icon" 47 | ios: true 48 | image_path: "asserts/icon/launcher_icon.png" 49 | 50 | # flutter pub run msix:create 51 | msix_config: 52 | display_name: 云舒音乐 53 | publisher_display_name: itning 54 | identity_name: top.itning.yunshumusic 55 | logo_path: ./asserts/icon/launcher_icon.png 56 | capabilities: musicLibrary, internetClient 57 | languages: zh-CN 58 | store: false 59 | architecture: x64 60 | 61 | flutter: 62 | uses-material-design: true 63 | assets: 64 | - asserts/images/default_cover.jpg 65 | - asserts/icon/app_icon.ico 66 | fonts: 67 | # https://github.com/lxgw/LxgwWenKai/releases 68 | - family: LXGWWenKaiMono 69 | fonts: 70 | - asset: asserts/fonts/LXGWWenKaiMono-Regular.ttf 71 | - family: Roboto 72 | fonts: 73 | - asset: asserts/fonts/Roboto.ttf 74 | -------------------------------------------------------------------------------- /yunshu_music/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter_test/flutter_test.dart'; 9 | 10 | void main() { 11 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {}); 12 | } 13 | -------------------------------------------------------------------------------- /yunshu_music/web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/web/favicon.ico -------------------------------------------------------------------------------- /yunshu_music/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/web/favicon.png -------------------------------------------------------------------------------- /yunshu_music/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/web/icons/Icon-192.png -------------------------------------------------------------------------------- /yunshu_music/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/web/icons/Icon-512.png -------------------------------------------------------------------------------- /yunshu_music/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /yunshu_music/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /yunshu_music/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 云舒音乐 30 | 31 | 32 | 33 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /yunshu_music/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "云舒音乐", 3 | "short_name": "云舒音乐", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "云舒音乐", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(yunshu_music LANGUAGES CXX) 3 | 4 | set(BINARY_NAME "yunshu_music") 5 | 6 | cmake_policy(SET CMP0063 NEW) 7 | 8 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 9 | 10 | # Configure build options. 11 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 12 | if(IS_MULTICONFIG) 13 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 14 | CACHE STRING "" FORCE) 15 | else() 16 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 17 | set(CMAKE_BUILD_TYPE "Debug" CACHE 18 | STRING "Flutter build mode" FORCE) 19 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 20 | "Debug" "Profile" "Release") 21 | endif() 22 | endif() 23 | 24 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 25 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 26 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 27 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 28 | 29 | # Use Unicode for all projects. 30 | add_definitions(-DUNICODE -D_UNICODE) 31 | 32 | # Compilation settings that should be applied to most targets. 33 | function(APPLY_STANDARD_SETTINGS TARGET) 34 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 35 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") 36 | target_compile_options(${TARGET} PRIVATE /EHsc) 37 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 38 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 39 | endfunction() 40 | 41 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 42 | 43 | # Flutter library and tool build rules. 44 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 45 | 46 | # Application build 47 | add_subdirectory("runner") 48 | 49 | # Generated plugin build rules, which manage building the plugins and adding 50 | # them to the application. 51 | include(flutter/generated_plugins.cmake) 52 | 53 | 54 | # === Installation === 55 | # Support files are copied into place next to the executable, so that it can 56 | # run in place. This is done instead of making a separate bundle (as on Linux) 57 | # so that building and running from within Visual Studio will work. 58 | set(BUILD_BUNDLE_DIR "$") 59 | # Make the "install" step default, as it's required to run. 60 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) 61 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 62 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 63 | endif() 64 | 65 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 66 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") 67 | 68 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 69 | COMPONENT Runtime) 70 | 71 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 72 | COMPONENT Runtime) 73 | 74 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 75 | COMPONENT Runtime) 76 | 77 | if(PLUGIN_BUNDLED_LIBRARIES) 78 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 79 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 80 | COMPONENT Runtime) 81 | endif() 82 | 83 | # Fully re-copy the assets directory on each build to avoid having stale files 84 | # from a previous install. 85 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 86 | install(CODE " 87 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 88 | " COMPONENT Runtime) 89 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 90 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 91 | 92 | # Install the AOT library on non-Debug builds only. 93 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 94 | CONFIGURATIONS Profile;Release 95 | COMPONENT Runtime) 96 | -------------------------------------------------------------------------------- /yunshu_music/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 | #include 17 | #include 18 | 19 | void RegisterPlugins(flutter::PluginRegistry* registry) { 20 | AudioplayersWindowsPluginRegisterWithRegistrar( 21 | registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); 22 | MusicChannelWindowsPluginRegisterWithRegistrar( 23 | registry->GetRegistrarForPlugin("MusicChannelWindowsPlugin")); 24 | ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( 25 | registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); 26 | SystemTrayPluginRegisterWithRegistrar( 27 | registry->GetRegistrarForPlugin("SystemTrayPlugin")); 28 | UrlLauncherWindowsRegisterWithRegistrar( 29 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 30 | WindowManagerPluginRegisterWithRegistrar( 31 | registry->GetRegistrarForPlugin("WindowManagerPlugin")); 32 | WindowSizePluginRegisterWithRegistrar( 33 | registry->GetRegistrarForPlugin("WindowSizePlugin")); 34 | WindowsSingleInstancePluginRegisterWithRegistrar( 35 | registry->GetRegistrarForPlugin("WindowsSingleInstancePlugin")); 36 | WindowsTaskbarPluginRegisterWithRegistrar( 37 | registry->GetRegistrarForPlugin("WindowsTaskbarPlugin")); 38 | } 39 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | audioplayers_windows 7 | music_channel_windows 8 | screen_retriever_windows 9 | system_tray 10 | url_launcher_windows 11 | window_manager 12 | window_size 13 | windows_single_instance 14 | windows_taskbar 15 | ) 16 | 17 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 18 | ) 19 | 20 | set(PLUGIN_BUNDLED_LIBRARIES) 21 | 22 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 24 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 27 | endforeach(plugin) 28 | 29 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 30 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 31 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 32 | endforeach(ffi_plugin) 33 | -------------------------------------------------------------------------------- /yunshu_music/windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 37 | 38 | # Run the Flutter tool portions of the build. This must not be removed. 39 | add_dependencies(${BINARY_NAME} flutter_assemble) 40 | -------------------------------------------------------------------------------- /yunshu_music/windows/runner/Runner.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | #include "resource.h" 5 | 6 | #define APSTUDIO_READONLY_SYMBOLS 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // 9 | // Generated from the TEXTINCLUDE 2 resource. 10 | // 11 | #include "winres.h" 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | #undef APSTUDIO_READONLY_SYMBOLS 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | // English (United States) resources 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Icon 51 | // 52 | 53 | // Icon with lowest ID value placed first to ensure application icon 54 | // remains consistent on all systems. 55 | IDI_APP_ICON ICON "resources\\app_icon.ico" 56 | 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Version 61 | // 62 | 63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) 64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0,0 67 | #endif 68 | 69 | #if defined(FLUTTER_VERSION) 70 | #define VERSION_AS_STRING FLUTTER_VERSION 71 | #else 72 | #define VERSION_AS_STRING "1.0.0" 73 | #endif 74 | 75 | VS_VERSION_INFO VERSIONINFO 76 | FILEVERSION VERSION_AS_NUMBER 77 | PRODUCTVERSION VERSION_AS_NUMBER 78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 79 | #ifdef _DEBUG 80 | FILEFLAGS VS_FF_DEBUG 81 | #else 82 | FILEFLAGS 0x0L 83 | #endif 84 | FILEOS VOS__WINDOWS32 85 | FILETYPE VFT_APP 86 | FILESUBTYPE 0x0L 87 | BEGIN 88 | BLOCK "StringFileInfo" 89 | BEGIN 90 | BLOCK "040904e4" 91 | BEGIN 92 | VALUE "CompanyName", "top.itning" "\0" 93 | VALUE "FileDescription", "yunshu_music" "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "yunshu_music" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2022 top.itning. All rights reserved." "\0" 97 | VALUE "OriginalFilename", "yunshu_music.exe" "\0" 98 | VALUE "ProductName", "yunshu_music" "\0" 99 | VALUE "ProductVersion", VERSION_AS_STRING "\0" 100 | END 101 | END 102 | BLOCK "VarFileInfo" 103 | BEGIN 104 | VALUE "Translation", 0x409, 1252 105 | END 106 | END 107 | 108 | #endif // English (United States) resources 109 | ///////////////////////////////////////////////////////////////////////////// 110 | 111 | 112 | 113 | #ifndef APSTUDIO_INVOKED 114 | ///////////////////////////////////////////////////////////////////////////// 115 | // 116 | // Generated from the TEXTINCLUDE 3 resource. 117 | // 118 | 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | #endif // not APSTUDIO_INVOKED 122 | -------------------------------------------------------------------------------- /yunshu_music/windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | return true; 30 | } 31 | 32 | void FlutterWindow::OnDestroy() { 33 | if (flutter_controller_) { 34 | flutter_controller_ = nullptr; 35 | } 36 | 37 | Win32Window::OnDestroy(); 38 | } 39 | 40 | LRESULT 41 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 42 | WPARAM const wparam, 43 | LPARAM const lparam) noexcept { 44 | // Give Flutter, including plugins, an opportunity to handle window messages. 45 | if (flutter_controller_) { 46 | std::optional result = 47 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 48 | lparam); 49 | if (result) { 50 | return *result; 51 | } 52 | } 53 | 54 | switch (message) { 55 | case WM_FONTCHANGE: 56 | flutter_controller_->engine()->ReloadSystemFonts(); 57 | break; 58 | case WM_CLOSE: 59 | ShowWindow(GetHandle(), SW_HIDE); 60 | return 0; 61 | break; 62 | } 63 | 64 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 65 | } 66 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/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(400, 800); 30 | 31 | UINT windowWidth = 1200, windowHeight = 900; 32 | Win32Window::Size size(windowWidth, windowHeight); 33 | UINT scrWidth, scrHeight, xShaft, yShaft; 34 | scrWidth = GetSystemMetrics(SM_CXFULLSCREEN); 35 | scrHeight = GetSystemMetrics(SM_CYFULLSCREEN); 36 | xShaft = (scrWidth - windowWidth) / 2; 37 | yShaft = (scrHeight - windowHeight) / 2; 38 | Win32Window::Point origin(xShaft, yShaft); 39 | 40 | if (!window.CreateAndShow(L"Loading...", origin, size)) { 41 | return EXIT_FAILURE; 42 | } 43 | window.SetQuitOnClose(true); 44 | 45 | ::MSG msg; 46 | while (::GetMessage(&msg, nullptr, 0, 0)) { 47 | ::TranslateMessage(&msg); 48 | ::DispatchMessage(&msg); 49 | } 50 | 51 | ::CoUninitialize(); 52 | return EXIT_SUCCESS; 53 | } 54 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itning/yunshu_music/0c88294611c32bcb07f55e6ec6fe63ea95eda2f8/yunshu_music/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | if (target_length == 0) { 52 | return std::string(); 53 | } 54 | std::string utf8_string; 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /yunshu_music/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 | -------------------------------------------------------------------------------- /yunshu_music/windows/runner/win32_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_WIN32_WINDOW_H_ 2 | #define RUNNER_WIN32_WINDOW_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be 11 | // inherited from by classes that wish to specialize with custom 12 | // rendering and input handling 13 | class Win32Window { 14 | public: 15 | struct Point { 16 | unsigned int x; 17 | unsigned int y; 18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {} 19 | }; 20 | 21 | struct Size { 22 | unsigned int width; 23 | unsigned int height; 24 | Size(unsigned int width, unsigned int height) 25 | : width(width), height(height) {} 26 | }; 27 | 28 | Win32Window(); 29 | virtual ~Win32Window(); 30 | 31 | // Creates and shows a win32 window with |title| and position and size using 32 | // |origin| and |size|. New windows are created on the default monitor. Window 33 | // sizes are specified to the OS in physical pixels, hence to ensure a 34 | // consistent size to will treat the width height passed in to this function 35 | // as logical pixels and scale to appropriate for the default monitor. Returns 36 | // true if the window was created successfully. 37 | bool CreateAndShow(const std::wstring& title, 38 | const Point& origin, 39 | const Size& size); 40 | 41 | // Release OS resources associated with window. 42 | void Destroy(); 43 | 44 | // Inserts |content| into the window tree. 45 | void SetChildContent(HWND content); 46 | 47 | // Returns the backing Window handle to enable clients to set icon and other 48 | // window properties. Returns nullptr if the window has been destroyed. 49 | HWND GetHandle(); 50 | 51 | // If true, closing this window will quit the application. 52 | void SetQuitOnClose(bool quit_on_close); 53 | 54 | // Return a RECT representing the bounds of the current client area. 55 | RECT GetClientArea(); 56 | 57 | protected: 58 | // Processes and route salient window messages for mouse handling, 59 | // size change and DPI. Delegates handling of these to member overloads that 60 | // inheriting classes can handle. 61 | virtual LRESULT MessageHandler(HWND window, 62 | UINT const message, 63 | WPARAM const wparam, 64 | LPARAM const lparam) noexcept; 65 | 66 | // Called when CreateAndShow is called, allowing subclass window-related 67 | // setup. Subclasses should return false if setup fails. 68 | virtual bool OnCreate(); 69 | 70 | // Called when Destroy is called. 71 | virtual void OnDestroy(); 72 | 73 | private: 74 | friend class WindowClassRegistrar; 75 | 76 | // OS callback called by message pump. Handles the WM_NCCREATE message which 77 | // is passed when the non-client area is being created and enables automatic 78 | // non-client DPI scaling so that the non-client area automatically 79 | // responsponds to changes in DPI. All other messages are handled by 80 | // MessageHandler. 81 | static LRESULT CALLBACK WndProc(HWND const window, 82 | UINT const message, 83 | WPARAM const wparam, 84 | LPARAM const lparam) noexcept; 85 | 86 | // Retrieves a class instance pointer for |window| 87 | static Win32Window* GetThisFromHandle(HWND const window) noexcept; 88 | 89 | bool quit_on_close_ = false; 90 | 91 | // window handle for top level window. 92 | HWND window_handle_ = nullptr; 93 | 94 | // window handle for hosted content. 95 | HWND child_content_ = nullptr; 96 | }; 97 | 98 | #endif // RUNNER_WIN32_WINDOW_H_ 99 | --------------------------------------------------------------------------------