rip out media_kit, use better_player and audioplayers
This also let us rip out cocoapods stuff. Needs testing on Windows, MacOS, and ideally, iOS.
This commit is contained in:
parent
161d39322c
commit
37a2c150f3
28 changed files with 375 additions and 604 deletions
11
.github/workflows/windows.yml
vendored
11
.github/workflows/windows.yml
vendored
|
|
@ -45,6 +45,17 @@ jobs:
|
||||||
flutter pub run build_runner build
|
flutter pub run build_runner build
|
||||||
flutter build windows --dart-define=GIT_COMMIT=${{ github.sha }}
|
flutter build windows --dart-define=GIT_COMMIT=${{ github.sha }}
|
||||||
|
|
||||||
|
# better_player plays videos with libmpv, but doesn't bundle it
|
||||||
|
- name: Download libmpv
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
$archive = "$env:RUNNER_TEMP\mpv.7z"
|
||||||
|
Invoke-WebRequest "https://github.com/shinchiro/mpv-winbuild-cmake/releases/download/20261021/mpv-dev-x86_64-20261021-git-e471496c56.7z" -OutFile $archive
|
||||||
|
if ((Get-FileHash $archive -Algorithm SHA256).Hash -ne "efc719eff3dc5954b4a5efc800632808bcec01cc9034940dd14e5eb7fe9ea633") {
|
||||||
|
throw "libmpv checksum mismatch"
|
||||||
|
}
|
||||||
|
7z e $archive libmpv-2.dll -obuild/windows/x64/runner/Release
|
||||||
|
|
||||||
- name: Copy MinGW runtime DLLs
|
- name: Copy MinGW runtime DLLs
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ This installs Nexus system-wide. With `enableNotifications`, it also installs KU
|
||||||
#### Linux
|
#### Linux
|
||||||
|
|
||||||
- On NixOS: Either use direnv and `direnv allow`, or `nix develop`
|
- On NixOS: Either use direnv and `direnv allow`, or `nix develop`
|
||||||
- On other distros: Install Flutter, Go, Git, Libclang, Libass, MPV, and Glibc. Do not use any Snap packages, they cause various compilation issues.
|
- On other distros: Install Flutter, Go, Git, Libclang, MPV, GStreamer (with its base, good and libav plugins), and Glibc. Do not use any Snap packages, they cause various compilation issues.
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
|
|
@ -83,12 +83,11 @@ You will need:
|
||||||
|
|
||||||
- Flutter
|
- Flutter
|
||||||
- Git
|
- Git
|
||||||
- Libass
|
|
||||||
- MPV
|
|
||||||
- Go
|
- Go
|
||||||
- Visual Studio 2022 (Desktop development with C++)
|
- Visual Studio 2022 (Desktop development with C++)
|
||||||
- [MSYS2/MinGW-w64 GCC](https://www.msys2.org/) (for CGO)
|
- [MSYS2/MinGW-w64 GCC](https://www.msys2.org/) (for CGO)
|
||||||
- [LLVM/Clang + libclang](https://clang.llvm.org/get_started.html) (for `ffigen`)
|
- [LLVM/Clang + libclang](https://clang.llvm.org/get_started.html) (for `ffigen`)
|
||||||
|
- `libmpv-2.dll`, for playing videos, next to `nexus.exe` (CI uses a build from [mpv-winbuild-cmake](https://github.com/shinchiro/mpv-winbuild-cmake/releases))
|
||||||
|
|
||||||
On Windows, make sure these are available in your shell `PATH`:
|
On Windows, make sure these are available in your shell `PATH`:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|
|
||||||
43
ios/Podfile
43
ios/Podfile
|
|
@ -1,43 +0,0 @@
|
||||||
# Uncomment this line to define a global platform for your project
|
|
||||||
# platform :ios, '13.0'
|
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
|
||||||
|
|
||||||
project 'Runner', {
|
|
||||||
'Debug' => :debug,
|
|
||||||
'Profile' => :release,
|
|
||||||
'Release' => :release,
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutter_root
|
|
||||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
|
||||||
unless File.exist?(generated_xcode_build_settings_path)
|
|
||||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
|
||||||
end
|
|
||||||
|
|
||||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
|
||||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
|
||||||
return matches[1].strip if matches
|
|
||||||
end
|
|
||||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
|
||||||
end
|
|
||||||
|
|
||||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
|
||||||
|
|
||||||
flutter_ios_podfile_setup
|
|
||||||
|
|
||||||
target 'Runner' do
|
|
||||||
use_frameworks!
|
|
||||||
|
|
||||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
|
||||||
target 'RunnerTests' do
|
|
||||||
inherit! :search_paths
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
post_install do |installer|
|
|
||||||
installer.pods_project.targets.each do |target|
|
|
||||||
flutter_additional_ios_build_settings(target)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
PODS:
|
|
||||||
- Flutter (1.0.0)
|
|
||||||
- media_kit_libs_ios_video (1.0.4):
|
|
||||||
- Flutter
|
|
||||||
- media_kit_video (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
|
||||||
- Flutter (from `Flutter`)
|
|
||||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
|
||||||
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
|
||||||
Flutter:
|
|
||||||
:path: Flutter
|
|
||||||
media_kit_libs_ios_video:
|
|
||||||
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
|
|
||||||
media_kit_video:
|
|
||||||
:path: ".symlinks/plugins/media_kit_video/ios"
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
|
||||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
|
||||||
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
|
||||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
|
|
||||||
|
|
||||||
COCOAPODS: 1.17.0
|
|
||||||
|
|
@ -8,13 +8,11 @@
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
2ADFEE6C745FFB2100CC9AFD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8156A45F510382D558AED93A /* Pods_RunnerTests.framework */; };
|
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
||||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||||
88D55A5F1C7625122EBEE29D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82F9A3759658343C81A0EA4C /* Pods_Runner.framework */; };
|
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
|
@ -46,19 +44,14 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
22DE4310DAFBE211CDF700B1 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
363A89F6FA09BCCBDED440CE /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
63516CF65A79A5DDDE64B0D1 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
8156A45F510382D558AED93A /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
82F9A3759658343C81A0EA4C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
|
@ -66,9 +59,6 @@
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
AEB96D8976BD46D6860C7041 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
B8B599FDB72E4713FB7B5A44 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
FE5E4162842555A83F8A7FD7 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
|
@ -76,7 +66,6 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
2ADFEE6C745FFB2100CC9AFD /* Pods_RunnerTests.framework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -85,27 +74,12 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
||||||
88D55A5F1C7625122EBEE29D /* Pods_Runner.framework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
1CFFAE23B502BCCEB2B191A3 /* Pods */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
AEB96D8976BD46D6860C7041 /* Pods-Runner.debug.xcconfig */,
|
|
||||||
363A89F6FA09BCCBDED440CE /* Pods-Runner.release.xcconfig */,
|
|
||||||
22DE4310DAFBE211CDF700B1 /* Pods-Runner.profile.xcconfig */,
|
|
||||||
B8B599FDB72E4713FB7B5A44 /* Pods-RunnerTests.debug.xcconfig */,
|
|
||||||
FE5E4162842555A83F8A7FD7 /* Pods-RunnerTests.release.xcconfig */,
|
|
||||||
63516CF65A79A5DDDE64B0D1 /* Pods-RunnerTests.profile.xcconfig */,
|
|
||||||
);
|
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -114,15 +88,6 @@
|
||||||
path = RunnerTests;
|
path = RunnerTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
594EB1F65336CF9C7958F6FA /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
82F9A3759658343C81A0EA4C /* Pods_Runner.framework */,
|
|
||||||
8156A45F510382D558AED93A /* Pods_RunnerTests.framework */,
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -142,8 +107,6 @@
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
1CFFAE23B502BCCEB2B191A3 /* Pods */,
|
|
||||||
594EB1F65336CF9C7958F6FA /* Frameworks */,
|
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
|
@ -179,7 +142,6 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
EE82EC529EB6C0F1FA480659 /* [CP] Check Pods Manifest.lock */,
|
|
||||||
331C807D294A63A400263BE5 /* Sources */,
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
331C807F294A63A400263BE5 /* Resources */,
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
8C0A36760DA8B873D8F6DDCE /* Frameworks */,
|
8C0A36760DA8B873D8F6DDCE /* Frameworks */,
|
||||||
|
|
@ -198,14 +160,12 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
0830C6758DA3ECA81FB12386 /* [CP] Check Pods Manifest.lock */,
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
1D165FDFB9D0D939B041966D /* [CP] Embed Pods Frameworks */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
|
@ -283,45 +243,6 @@
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
0830C6758DA3ECA81FB12386 /* [CP] Check Pods Manifest.lock */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
|
||||||
"${PODS_ROOT}/Manifest.lock",
|
|
||||||
);
|
|
||||||
name = "[CP] Check Pods Manifest.lock";
|
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
1D165FDFB9D0D939B041966D /* [CP] Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
|
||||||
outputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
|
|
@ -353,28 +274,6 @@
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
EE82EC529EB6C0F1FA480659 /* [CP] Check Pods Manifest.lock */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
|
||||||
"${PODS_ROOT}/Manifest.lock",
|
|
||||||
);
|
|
||||||
name = "[CP] Check Pods Manifest.lock";
|
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
|
@ -502,7 +401,6 @@
|
||||||
};
|
};
|
||||||
331C8088294A63A400263BE5 /* Debug */ = {
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = B8B599FDB72E4713FB7B5A44 /* Pods-RunnerTests.debug.xcconfig */;
|
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
|
@ -520,7 +418,6 @@
|
||||||
};
|
};
|
||||||
331C8089294A63A400263BE5 /* Release */ = {
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = FE5E4162842555A83F8A7FD7 /* Pods-RunnerTests.release.xcconfig */;
|
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
|
@ -536,7 +433,6 @@
|
||||||
};
|
};
|
||||||
331C808A294A63A400263BE5 /* Profile */ = {
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 63516CF65A79A5DDDE64B0D1 /* Pods-RunnerTests.profile.xcconfig */;
|
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
|
|
||||||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
|
|
@ -4,7 +4,4 @@
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
|
||||||
location = "group:Pods/Pods.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import "package:dynamic_color/dynamic_color.dart";
|
||||||
import "package:flutter/foundation.dart";
|
import "package:flutter/foundation.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:material_emoji_picker/material_emoji_picker.dart";
|
import "package:material_emoji_picker/material_emoji_picker.dart";
|
||||||
import "package:media_kit/media_kit.dart";
|
|
||||||
import "package:nexus/controllers/active_account.dart";
|
import "package:nexus/controllers/active_account.dart";
|
||||||
import "package:nexus/controllers/client.dart";
|
import "package:nexus/controllers/client.dart";
|
||||||
import "package:nexus/controllers/client_state.dart";
|
import "package:nexus/controllers/client_state.dart";
|
||||||
|
|
@ -65,7 +64,6 @@ void showError(Object error, [StackTrace? stackTrace]) {
|
||||||
|
|
||||||
void main(List<String> args) async {
|
void main(List<String> args) async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
MediaKit.ensureInitialized();
|
|
||||||
|
|
||||||
LicenseRegistry.addLicense(() => .fromIterable(fontLicenses));
|
LicenseRegistry.addLicense(() => .fromIterable(fontLicenses));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
|
|
||||||
|
import "package:audioplayers/audioplayers.dart" as audioplayers;
|
||||||
import "package:material_ui/material_ui.dart";
|
import "package:material_ui/material_ui.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:media_kit/media_kit.dart";
|
|
||||||
import "package:nexus/controllers/client.dart";
|
import "package:nexus/controllers/client.dart";
|
||||||
import "package:nexus/helpers/extensions/save_attachment.dart";
|
import "package:nexus/helpers/extensions/save_attachment.dart";
|
||||||
import "package:nexus/models/info/audio.dart";
|
import "package:nexus/models/info/audio.dart";
|
||||||
|
|
@ -18,9 +18,7 @@ class const AudioPlayer(
|
||||||
}) extends HookConsumerWidget {
|
}) extends HookConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final player = useMemoized(
|
final player = useMemoized(audioplayers.AudioPlayer.new);
|
||||||
() => Player(configuration: .new(bufferSize: 128 * 1024 * 1024)),
|
|
||||||
);
|
|
||||||
final loaded = useState(false);
|
final loaded = useState(false);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
|
|
@ -29,19 +27,39 @@ class const AudioPlayer(
|
||||||
.read(ClientController.provider.notifier)
|
.read(ClientController.provider.notifier)
|
||||||
.downloadMedia(.new(mxc: uri, encrypted: encrypted));
|
.downloadMedia(.new(mxc: uri, encrypted: encrypted));
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
await player.open(Media(audio.path), play: false);
|
// Keeps the audio loaded after it finishes, so it can be replayed
|
||||||
|
await player.setReleaseMode(.stop);
|
||||||
|
await player.setSource(audioplayers.DeviceFileSource(audio.path));
|
||||||
if (context.mounted) loaded.value = true;
|
if (context.mounted) loaded.value = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
return player.dispose;
|
return player.dispose;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
final state = useStream(
|
||||||
|
player.onPlayerStateChanged,
|
||||||
|
initialData: player.state,
|
||||||
|
).requireData;
|
||||||
|
final position = useStream(
|
||||||
|
player.onPositionChanged,
|
||||||
|
initialData: Duration.zero,
|
||||||
|
).requireData;
|
||||||
|
final duration = useStream(
|
||||||
|
player.onDurationChanged,
|
||||||
|
initialData: Duration.zero,
|
||||||
|
).requireData;
|
||||||
|
final playing = state == .playing;
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: .symmetric(horizontal: 8),
|
padding: .symmetric(horizontal: 8),
|
||||||
child: PlayerControls(
|
child: PlayerControls(
|
||||||
player,
|
playing: playing,
|
||||||
|
position: position,
|
||||||
|
duration: duration,
|
||||||
|
onPlayPause: playing ? player.pause : player.resume,
|
||||||
|
onSeek: player.seek,
|
||||||
loading: !loaded.value,
|
loading: !loaded.value,
|
||||||
size: info?.size,
|
size: info?.size,
|
||||||
actions: .new([
|
actions: .new([
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,25 @@
|
||||||
import "dart:math";
|
import "dart:math";
|
||||||
|
|
||||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
|
||||||
import "package:material_ui/material_ui.dart";
|
import "package:material_ui/material_ui.dart";
|
||||||
import "package:media_kit/media_kit.dart";
|
|
||||||
import "package:nexus/helpers/extensions/size_to_string.dart";
|
import "package:nexus/helpers/extensions/size_to_string.dart";
|
||||||
|
|
||||||
/// Play/pause, position and seeking controls for a media_kit [Player].
|
/// Play/pause, position and seeking controls, for any player.
|
||||||
class const PlayerControls(
|
class const PlayerControls({
|
||||||
final Player player, {
|
required final bool playing,
|
||||||
|
required final Duration position,
|
||||||
|
required final Duration duration,
|
||||||
|
required final VoidCallback onPlayPause,
|
||||||
|
required final ValueChanged<Duration> onSeek,
|
||||||
final bool loading = false,
|
final bool loading = false,
|
||||||
|
final bool buffering = false,
|
||||||
final Color? color,
|
final Color? color,
|
||||||
final int? size,
|
final int? size,
|
||||||
final IList<Widget> actions = const .empty(),
|
final IList<Widget> actions = const .empty(),
|
||||||
super.key,
|
super.key,
|
||||||
}) extends HookWidget {
|
}) extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final playing = useStream(
|
|
||||||
player.stream.playing,
|
|
||||||
initialData: player.state.playing,
|
|
||||||
).requireData;
|
|
||||||
final buffering = useStream(
|
|
||||||
player.stream.buffering,
|
|
||||||
initialData: player.state.buffering,
|
|
||||||
).requireData;
|
|
||||||
final position = useStream(
|
|
||||||
player.stream.position,
|
|
||||||
initialData: player.state.position,
|
|
||||||
).requireData;
|
|
||||||
final duration = useStream(
|
|
||||||
player.stream.duration,
|
|
||||||
initialData: player.state.duration,
|
|
||||||
).requireData;
|
|
||||||
|
|
||||||
String format(Duration duration) {
|
String format(Duration duration) {
|
||||||
final minutes = duration.inMinutes
|
final minutes = duration.inMinutes
|
||||||
.remainder(60)
|
.remainder(60)
|
||||||
|
|
@ -61,7 +47,7 @@ class const PlayerControls(
|
||||||
child: CircularProgressIndicator(padding: .all(12), color: color),
|
child: CircularProgressIndicator(padding: .all(12), color: color),
|
||||||
)
|
)
|
||||||
: IconButton(
|
: IconButton(
|
||||||
onPressed: player.playOrPause,
|
onPressed: onPlayPause,
|
||||||
color: color,
|
color: color,
|
||||||
tooltip: playing ? "Pause" : "Play",
|
tooltip: playing ? "Pause" : "Play",
|
||||||
icon: Icon(playing ? Icons.pause_circle : Icons.play_circle),
|
icon: Icon(playing ? Icons.pause_circle : Icons.play_circle),
|
||||||
|
|
@ -73,7 +59,7 @@ class const PlayerControls(
|
||||||
value: min(position.inMilliseconds.toDouble(), max),
|
value: min(position.inMilliseconds.toDouble(), max),
|
||||||
onChanged: loading
|
onChanged: loading
|
||||||
? null
|
? null
|
||||||
: (value) => player.seek(.new(milliseconds: value.toInt())),
|
: (value) => onSeek(.new(milliseconds: value.toInt())),
|
||||||
);
|
);
|
||||||
|
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
|
|
||||||
|
import "package:better_player/better_player.dart";
|
||||||
import "package:material_ui/material_ui.dart";
|
import "package:material_ui/material_ui.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/client.dart";
|
import "package:nexus/controllers/client.dart";
|
||||||
import "package:nexus/helpers/extensions/save_attachment.dart";
|
import "package:nexus/helpers/extensions/save_attachment.dart";
|
||||||
import "package:nexus/models/info/video.dart";
|
import "package:nexus/models/info/video.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:media_kit/media_kit.dart";
|
|
||||||
import "package:media_kit_video/media_kit_video.dart";
|
|
||||||
import "package:nexus/widgets/players/player_controls.dart";
|
import "package:nexus/widgets/players/player_controls.dart";
|
||||||
|
|
||||||
class const VideoPlayer(
|
class const VideoPlayer(
|
||||||
|
|
@ -19,11 +18,118 @@ class const VideoPlayer(
|
||||||
}) extends HookConsumerWidget {
|
}) extends HookConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final player = useMemoized(
|
final aspectRatio = switch (info) {
|
||||||
() => Player(configuration: .new(bufferSize: 128 * 1024 * 1024)),
|
VideoInfo(:final width?, :final height?) when width > 0 && height > 0 =>
|
||||||
);
|
width / height,
|
||||||
final controller = useMemoized(() => VideoController(player));
|
_ => 16 / 9,
|
||||||
|
};
|
||||||
|
|
||||||
final loaded = useState(false);
|
final loaded = useState(false);
|
||||||
|
final controller = useMemoized(
|
||||||
|
() => BetterPlayerController(
|
||||||
|
PlayerConfiguration(
|
||||||
|
aspectRatio: aspectRatio,
|
||||||
|
fit: .contain,
|
||||||
|
controlsConfiguration: PlayerControlsConfiguration(
|
||||||
|
playerTheme: .custom,
|
||||||
|
customControlsBuilder: (controller, _) => HookBuilder(
|
||||||
|
builder: (context) {
|
||||||
|
final isLoaded = useValueListenable(loaded);
|
||||||
|
final value = useState(controller.videoPlayerValue);
|
||||||
|
useEffect(() {
|
||||||
|
void listener() => value.value = controller.videoPlayerValue;
|
||||||
|
controller.addVideoListener(listener);
|
||||||
|
return () => controller.removeVideoListener(listener);
|
||||||
|
}, [controller]);
|
||||||
|
|
||||||
|
final playing = value.value?.isPlaying ?? false;
|
||||||
|
|
||||||
|
// better_player doesn't use material_ui, so this Material is needed.
|
||||||
|
return Material(
|
||||||
|
type: .transparency,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: GestureDetector(
|
||||||
|
behavior: .opaque,
|
||||||
|
onTap: isLoaded
|
||||||
|
? playing
|
||||||
|
? controller.pause
|
||||||
|
: controller.play
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: 4,
|
||||||
|
right: 4,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () => context.saveAttachment(
|
||||||
|
ref,
|
||||||
|
uri,
|
||||||
|
encrypted: encrypted,
|
||||||
|
filename: filename,
|
||||||
|
),
|
||||||
|
color: Colors.white,
|
||||||
|
style: IconButton.styleFrom(
|
||||||
|
backgroundColor: Colors.black38,
|
||||||
|
),
|
||||||
|
tooltip: "Download",
|
||||||
|
icon: Icon(Icons.download),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: .bottomCenter,
|
||||||
|
end: .topCenter,
|
||||||
|
colors: [Colors.black54, Colors.transparent],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const .only(left: 4, right: 4, top: 16),
|
||||||
|
child: PlayerControls(
|
||||||
|
playing: playing,
|
||||||
|
buffering: value.value?.isBuffering ?? false,
|
||||||
|
position: value.value?.position ?? .zero,
|
||||||
|
duration: value.value?.duration ?? .zero,
|
||||||
|
onPlayPause: playing
|
||||||
|
? controller.pause
|
||||||
|
: controller.play,
|
||||||
|
onSeek: controller.seekTo,
|
||||||
|
loading: !isLoaded,
|
||||||
|
size: info?.size,
|
||||||
|
color: Colors.white,
|
||||||
|
actions: .new([
|
||||||
|
IconButton(
|
||||||
|
onPressed: controller.toggleFullScreen,
|
||||||
|
color: Colors.white,
|
||||||
|
tooltip: controller.isFullScreen
|
||||||
|
? "Exit fullscreen"
|
||||||
|
: "Fullscreen",
|
||||||
|
icon: Icon(
|
||||||
|
controller.isFullScreen
|
||||||
|
? Icons.fullscreen_exit
|
||||||
|
: Icons.fullscreen,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
scheduleMicrotask(() async {
|
scheduleMicrotask(() async {
|
||||||
|
|
@ -31,109 +137,20 @@ class const VideoPlayer(
|
||||||
.read(ClientController.provider.notifier)
|
.read(ClientController.provider.notifier)
|
||||||
.downloadMedia(.new(mxc: uri, encrypted: encrypted));
|
.downloadMedia(.new(mxc: uri, encrypted: encrypted));
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
await player.open(Media(video.path), play: false);
|
await controller.setupDataSource(.file(video.path));
|
||||||
if (context.mounted) loaded.value = true;
|
if (context.mounted) loaded.value = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
return player.dispose;
|
return null;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
final controls = useCallback(
|
|
||||||
(VideoState _) =>
|
|
||||||
// Until media_kit moves to material_ui, this Material is needed.
|
|
||||||
Material(
|
|
||||||
type: .transparency,
|
|
||||||
child: ValueListenableBuilder(
|
|
||||||
valueListenable: loaded,
|
|
||||||
builder: (_, loaded, _) => Stack(
|
|
||||||
children: [
|
|
||||||
Positioned.fill(
|
|
||||||
child: GestureDetector(
|
|
||||||
behavior: .opaque,
|
|
||||||
onTap: loaded ? player.playOrPause : null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
top: 4,
|
|
||||||
right: 4,
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () => context.saveAttachment(
|
|
||||||
ref,
|
|
||||||
uri,
|
|
||||||
encrypted: encrypted,
|
|
||||||
filename: filename,
|
|
||||||
),
|
|
||||||
color: Colors.white,
|
|
||||||
style: IconButton.styleFrom(
|
|
||||||
backgroundColor: Colors.black38,
|
|
||||||
),
|
|
||||||
tooltip: "Download",
|
|
||||||
icon: Icon(Icons.download),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
child: DecoratedBox(
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: .bottomCenter,
|
|
||||||
end: .topCenter,
|
|
||||||
colors: [Colors.black54, Colors.transparent],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const .only(left: 4, right: 4, top: 16),
|
|
||||||
child: PlayerControls(
|
|
||||||
player,
|
|
||||||
loading: !loaded,
|
|
||||||
size: info?.size,
|
|
||||||
color: Colors.white,
|
|
||||||
actions: .new([
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
final fullscreen = isFullscreen(context);
|
|
||||||
|
|
||||||
return IconButton(
|
|
||||||
onPressed: () => toggleFullscreen(context),
|
|
||||||
color: Colors.white,
|
|
||||||
tooltip: fullscreen
|
|
||||||
? "Exit fullscreen"
|
|
||||||
: "Fullscreen",
|
|
||||||
icon: Icon(
|
|
||||||
fullscreen
|
|
||||||
? Icons.fullscreen_exit
|
|
||||||
: Icons.fullscreen,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
[uri, encrypted, filename, info],
|
|
||||||
);
|
|
||||||
|
|
||||||
final aspectRatio = switch (info) {
|
|
||||||
VideoInfo(:final width?, :final height?) when width > 0 && height > 0 =>
|
|
||||||
width / height,
|
|
||||||
_ => 16 / 9,
|
|
||||||
};
|
|
||||||
|
|
||||||
return ConstrainedBox(
|
return ConstrainedBox(
|
||||||
constraints: const .new(maxHeight: 300),
|
constraints: const .new(maxHeight: 300),
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: aspectRatio,
|
aspectRatio: aspectRatio,
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: .circular(12),
|
borderRadius: .circular(12),
|
||||||
child: Video(controller: controller, controls: controls),
|
child: BetterPlayer(controller: controller),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <app_links_linux/app_links_plugin_linux.h>
|
#include <app_links_linux/app_links_plugin_linux.h>
|
||||||
|
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
||||||
|
#include <better_player_linux/better_player_linux_plugin.h>
|
||||||
#include <dynamic_color/dynamic_color_plugin.h>
|
#include <dynamic_color/dynamic_color_plugin.h>
|
||||||
#include <file_selector_linux/file_selector_plugin.h>
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
#include <location/location_plugin.h>
|
#include <location/location_plugin.h>
|
||||||
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
|
||||||
#include <media_kit_video/media_kit_video_plugin.h>
|
|
||||||
#include <pasteboard/pasteboard_plugin.h>
|
#include <pasteboard/pasteboard_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
|
|
@ -19,6 +19,12 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) app_links_linux_registrar =
|
g_autoptr(FlPluginRegistrar) app_links_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "AppLinksPluginLinux");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "AppLinksPluginLinux");
|
||||||
app_links_plugin_linux_register_with_registrar(app_links_linux_registrar);
|
app_links_plugin_linux_register_with_registrar(app_links_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin");
|
||||||
|
audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) better_player_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "BetterPlayerLinuxPlugin");
|
||||||
|
better_player_linux_plugin_register_with_registrar(better_player_linux_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
|
g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin");
|
||||||
dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);
|
dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);
|
||||||
|
|
@ -28,12 +34,6 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) location_registrar =
|
g_autoptr(FlPluginRegistrar) location_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "LocationPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "LocationPlugin");
|
||||||
location_plugin_register_with_registrar(location_registrar);
|
location_plugin_register_with_registrar(location_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar =
|
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin");
|
|
||||||
media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar);
|
|
||||||
g_autoptr(FlPluginRegistrar) media_kit_video_registrar =
|
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin");
|
|
||||||
media_kit_video_plugin_register_with_registrar(media_kit_video_registrar);
|
|
||||||
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
||||||
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
app_links_linux
|
app_links_linux
|
||||||
|
audioplayers_linux
|
||||||
|
better_player_linux
|
||||||
dynamic_color
|
dynamic_color
|
||||||
file_selector_linux
|
file_selector_linux
|
||||||
location
|
location
|
||||||
media_kit_libs_linux
|
|
||||||
media_kit_video
|
|
||||||
pasteboard
|
pasteboard
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@
|
||||||
stdenv.cc
|
stdenv.cc
|
||||||
go
|
go
|
||||||
git
|
git
|
||||||
|
ffmpeg-headless
|
||||||
|
|
||||||
libGL
|
libGL
|
||||||
(flutter.override {
|
(flutter.override {
|
||||||
|
# audioplayers plays audio through GStreamer
|
||||||
extraPkgConfigPackages = [
|
extraPkgConfigPackages = [
|
||||||
mpv-unwrapped
|
gst_all_1.gstreamer
|
||||||
libass
|
gst_all_1.gst-plugins-base
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|
@ -25,6 +27,27 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
env = lib.optionalAttrs pkgs.stdenv.isLinux {
|
env = lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||||
LD_LIBRARY_PATH = "./build/native_assets/linux:${lib.makeLibraryPath [ pkgs.zlib ]}";
|
# better_player loads libmpv at runtime to play videos
|
||||||
|
LD_LIBRARY_PATH = "./build/native_assets/linux:${
|
||||||
|
lib.makeLibraryPath [
|
||||||
|
pkgs.zlib
|
||||||
|
pkgs.mpv-unwrapped
|
||||||
|
]
|
||||||
|
}";
|
||||||
|
# audioplayers links GStreamer by name only, without its library directory
|
||||||
|
LIBRARY_PATH = lib.makeLibraryPath [
|
||||||
|
pkgs.gst_all_1.gstreamer
|
||||||
|
pkgs.gst_all_1.gst-plugins-base
|
||||||
|
pkgs.glib
|
||||||
|
];
|
||||||
|
GST_PLUGIN_SYSTEM_PATH_1_0 = lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" (
|
||||||
|
with pkgs.gst_all_1;
|
||||||
|
[
|
||||||
|
gstreamer
|
||||||
|
gst-plugins-base
|
||||||
|
gst-plugins-good
|
||||||
|
gst-libav
|
||||||
|
]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
lib,
|
lib,
|
||||||
callPackage,
|
callPackage,
|
||||||
mpv-unwrapped,
|
mpv-unwrapped,
|
||||||
libass,
|
gst_all_1,
|
||||||
|
ffmpeg-headless,
|
||||||
libxext,
|
libxext,
|
||||||
libxfixes,
|
libxfixes,
|
||||||
libclang,
|
libclang,
|
||||||
|
|
@ -39,8 +40,9 @@ flutter.buildFlutterApplication {
|
||||||
nativeBuildInputs = [ (callPackage ./hook_pkg_config.nix { }) ];
|
nativeBuildInputs = [ (callPackage ./hook_pkg_config.nix { }) ];
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
mpv-unwrapped
|
# audioplayers plays audio through GStreamer
|
||||||
libass
|
gst_all_1.gstreamer
|
||||||
|
gst_all_1.gst-plugins-base
|
||||||
# nativeapi includes XInput2.h, which needs these, but xi.pc only lists them privately
|
# nativeapi includes XInput2.h, which needs these, but xi.pc only lists them privately
|
||||||
libxext
|
libxext
|
||||||
libxfixes
|
libxfixes
|
||||||
|
|
@ -54,6 +56,7 @@ flutter.buildFlutterApplication {
|
||||||
|
|
||||||
gitHashes = {
|
gitHashes = {
|
||||||
linkify = "sha256-TpMD6+0zyY6i9l+6d8ErnVufmepCv362rCtnbOht/z4=";
|
linkify = "sha256-TpMD6+0zyY6i9l+6d8ErnVufmepCv362rCtnbOht/z4=";
|
||||||
|
location = "sha256-zWnffXiK1LD4Ln23coPozBjYfTlhZmBhC5Z8mCdAgwQ=";
|
||||||
fab_m3e = "sha256-5V9m6yY0jimx2gh7lQHYg4HDKQ4Wrl0ATmBhw5DkQMI=";
|
fab_m3e = "sha256-5V9m6yY0jimx2gh7lQHYg4HDKQ4Wrl0ATmBhw5DkQMI=";
|
||||||
fluttertagger = "sha256-tHUNU2+fBPkq5UK5YRi3SWs1zF2PIPz6RgSbwignU/I=";
|
fluttertagger = "sha256-tHUNU2+fBPkq5UK5YRi3SWs1zF2PIPz6RgSbwignU/I=";
|
||||||
m3e_design = "sha256-5V9m6yY0jimx2gh7lQHYg4HDKQ4Wrl0ATmBhw5DkQMI=";
|
m3e_design = "sha256-5V9m6yY0jimx2gh7lQHYg4HDKQ4Wrl0ATmBhw5DkQMI=";
|
||||||
|
|
@ -69,8 +72,24 @@ flutter.buildFlutterApplication {
|
||||||
install -D assets/bundled/icon.svg $out/share/icons/hicolor/scalable/apps/nexus.svg
|
install -D assets/bundled/icon.svg $out/share/icons/hicolor/scalable/apps/nexus.svg
|
||||||
install -Dm755 linux/*.desktop -t $out/share/applications
|
install -Dm755 linux/*.desktop -t $out/share/applications
|
||||||
install -Dm644 linux/*.service -t $out/share/dbus-1/services
|
install -Dm644 linux/*.service -t $out/share/dbus-1/services
|
||||||
|
# better_player loads libmpv at runtime to play videos, and audioplayers
|
||||||
|
# needs GStreamer's plugins to decode audio
|
||||||
|
# gomuks uses ffmpeg and ffprobe for video thumbnails and metadata
|
||||||
wrapProgram $out/bin/nexus \
|
wrapProgram $out/bin/nexus \
|
||||||
--suffix LD_LIBRARY_PATH : $out/app/nexus/lib
|
--suffix LD_LIBRARY_PATH : $out/app/nexus/lib \
|
||||||
|
--prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ mpv-unwrapped ]} \
|
||||||
|
--prefix PATH : ${lib.makeBinPath [ ffmpeg-headless ]} \
|
||||||
|
--prefix GST_PLUGIN_SYSTEM_PATH_1_0 : ${
|
||||||
|
lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" (
|
||||||
|
with gst_all_1;
|
||||||
|
[
|
||||||
|
gstreamer
|
||||||
|
gst-plugins-base
|
||||||
|
gst-plugins-good
|
||||||
|
gst-libav
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "my_application.h"
|
#include "my_application.h"
|
||||||
|
|
||||||
|
#include <clocale>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <flutter_linux/flutter_linux.h>
|
#include <flutter_linux/flutter_linux.h>
|
||||||
|
|
@ -301,6 +302,9 @@ static void my_application_startup(
|
||||||
G_APPLICATION_CLASS(
|
G_APPLICATION_CLASS(
|
||||||
my_application_parent_class)
|
my_application_parent_class)
|
||||||
->startup(application);
|
->startup(application);
|
||||||
|
|
||||||
|
// mpv hates normal locales
|
||||||
|
setlocale(LC_NUMERIC, "C");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void my_application_shutdown(
|
static void my_application_shutdown(
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
|
||||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
|
||||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@ import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import app_links
|
import app_links
|
||||||
|
import audioplayers_darwin
|
||||||
|
import better_player_macos
|
||||||
import dynamic_color
|
import dynamic_color
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
import flutter_local_notifications
|
import flutter_local_notifications
|
||||||
import location
|
import location
|
||||||
import media_kit_libs_macos_video
|
|
||||||
import media_kit_video
|
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import pasteboard
|
import pasteboard
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
|
|
@ -20,12 +20,12 @@ import wakelock_plus
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
|
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
|
||||||
|
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
|
||||||
|
BetterPlayerPlugin.register(with: registry.registrar(forPlugin: "BetterPlayerPlugin"))
|
||||||
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||||
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
|
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
|
||||||
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
|
|
||||||
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
|
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue