From 2453bbbcee2fcce7241c4b9afb27c81d67831794 Mon Sep 17 00:00:00 2001 From: popdollar Date: Fri, 19 Dec 2025 20:11:02 +0100 Subject: [PATCH 01/13] feat: added basic changes to make tizen launch further testing will be needed --- Fladder-Tizen.sln | 29 ++++++ lib/main.dart | 12 ++- lib/models/settings/arguments_model.dart | 7 +- lib/models/syncing/database_item.dart | 22 +++++ pubspec.lock | 114 ++++++++++++++++++++++- pubspec.yaml | 16 ++++ tizen/.gitignore | 12 +++ tizen/App.cs | 20 ++++ tizen/Runner.csproj | 19 ++++ tizen/shared/res/fladder_icon.png | Bin 0 -> 199313 bytes tizen/tizen-manifest.xml | 13 +++ 11 files changed, 255 insertions(+), 9 deletions(-) create mode 100644 Fladder-Tizen.sln create mode 100644 tizen/.gitignore create mode 100644 tizen/App.cs create mode 100644 tizen/Runner.csproj create mode 100644 tizen/shared/res/fladder_icon.png create mode 100644 tizen/tizen-manifest.xml diff --git a/Fladder-Tizen.sln b/Fladder-Tizen.sln new file mode 100644 index 000000000..fcf439898 --- /dev/null +++ b/Fladder-Tizen.sln @@ -0,0 +1,29 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tizen", "tizen", "{A388AB0E-F47B-31FD-1F3C-3AE867F75632}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Runner", "tizen\Runner.csproj", "{11CBC428-FFDB-ECCF-FBBF-1DB39BFFB147}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {11CBC428-FFDB-ECCF-FBBF-1DB39BFFB147}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11CBC428-FFDB-ECCF-FBBF-1DB39BFFB147}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11CBC428-FFDB-ECCF-FBBF-1DB39BFFB147}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11CBC428-FFDB-ECCF-FBBF-1DB39BFFB147}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {11CBC428-FFDB-ECCF-FBBF-1DB39BFFB147} = {A388AB0E-F47B-31FD-1F3C-3AE867F75632} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {38085DC2-CEE5-4C57-8CBF-1D53D4E7A0F4} + EndGlobalSection +EndGlobal diff --git a/lib/main.dart b/lib/main.dart index 38f698ab9..916629f14 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:ui'; +import 'dart:ffi' as ffi; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -46,8 +47,11 @@ import 'package:fladder/util/themes_data.dart'; import 'package:fladder/util/window_helper.dart'; import 'package:fladder/widgets/media_query_scaler.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; +import 'package:sqlite3/open.dart' as sqlite3_open; + bool get _isDesktop { - if (kIsWeb) return false; + if (kIsWeb || isTizen) return false; return [ TargetPlatform.windows, TargetPlatform.linux, @@ -63,6 +67,12 @@ Future> loadConfig() async { } void main(List args) async { + if (isTizen) { + sqlite3_open.open.overrideFor(sqlite3_open.OperatingSystem.linux, () { + return ffi.DynamicLibrary.open('/usr/share/dotnet.tizen/lib/libsqlite3.so'); + }); + } + WidgetsFlutterBinding.ensureInitialized(); final crashProvider = CrashLogNotifier(); diff --git a/lib/models/settings/arguments_model.dart b/lib/models/settings/arguments_model.dart index 73708db43..bbff29f0b 100644 --- a/lib/models/settings/arguments_model.dart +++ b/lib/models/settings/arguments_model.dart @@ -1,4 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; part 'arguments_model.freezed.dart'; @@ -17,11 +18,11 @@ abstract class ArgumentsModel with _$ArgumentsModel { factory ArgumentsModel.fromArguments(List arguments, String windowArguments, bool leanBackEnabled) { arguments = arguments.map((e) => e.trim()).toList(); - leanBackMode = leanBackEnabled; + leanBackMode = leanBackEnabled || isTizen; final parsedWindowArgs = windowArguments.split(','); return ArgumentsModel( - htpcMode: arguments.contains('--htpc') || leanBackEnabled, - leanBackMode: leanBackEnabled, + htpcMode: arguments.contains('--htpc') || leanBackEnabled || isTizen, + leanBackMode: leanBackEnabled || isTizen, newWindow: parsedWindowArgs.contains('--newWindow'), ); } diff --git a/lib/models/syncing/database_item.dart b/lib/models/syncing/database_item.dart index aa82add2d..1c76e7c21 100644 --- a/lib/models/syncing/database_item.dart +++ b/lib/models/syncing/database_item.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:drift/native.dart'; import 'package:drift/drift.dart'; import 'package:drift_flutter/drift_flutter.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -17,6 +18,8 @@ import 'package:fladder/models/items/trick_play_model.dart'; import 'package:fladder/models/syncing/sync_item.dart'; import 'package:fladder/providers/user_provider.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; +import 'package:sqlite3/sqlite3.dart'; part 'database_item.g.dart'; const _databseName = 'syncedDatabase'; @@ -194,6 +197,14 @@ class AppDatabase extends _$AppDatabase { } static QueryExecutor _openConnection() { + if (isTizen) { + return _openConnectionTizen(); + } else { + return _openConnectionDefault(); + } + } + + static QueryExecutor _openConnectionDefault() { return driftDatabase( name: _databseName, native: const DriftNativeOptions( @@ -205,4 +216,15 @@ class AppDatabase extends _$AppDatabase { ), ); } + + static LazyDatabase _openConnectionTizen() { + return LazyDatabase(() async { + final dir = await getApplicationSupportDirectory(); + final file = File(p.join(dir.path, '$_databseName.sqlite')); + + return NativeDatabase.opened( + sqlite3.open(file.path), + ); + }); + } } diff --git a/pubspec.lock b/pubspec.lock index 34cac7b84..8ba22fa79 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -337,6 +337,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + connectivity_plus_tizen: + dependency: "direct main" + description: + name: connectivity_plus_tizen + sha256: "7f4ede84d702af8b3f56dbfb880e6772f3cf39e0498335753302db93aa562b11" + url: "https://pub.dev" + source: hosted + version: "1.2.2" convert: dependency: transitive description: @@ -505,6 +513,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.7" + drift_sqflite: + dependency: "direct main" + description: + name: drift_sqflite + sha256: dd1afbd72555b7a72ebf053926078d8c302059af4f1eb22040fc27a056429acb + url: "https://pub.dev" + source: hosted + version: "2.0.1" drift_sync: dependency: "direct main" description: @@ -784,6 +800,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_tizen: + dependency: "direct main" + description: + name: flutter_tizen + sha256: "5df51a022828127d8d3bf2af32e67b746b764b1209193148fd33b0d7b7c122a7" + url: "https://pub.dev" + source: hosted + version: "0.2.7" flutter_typeahead: dependency: "direct main" description: @@ -1365,6 +1389,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" + package_info_plus_tizen: + dependency: "direct main" + description: + name: package_info_plus_tizen + sha256: "5e85dd353e08b8a0c4ec52fdda8da6b591344b1440956b720553c52a5cb57b7e" + url: "https://pub.dev" + source: hosted + version: "1.0.5" page_transition: dependency: "direct main" description: @@ -1437,6 +1469,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + path_provider_tizen: + dependency: "direct main" + description: + name: path_provider_tizen + sha256: d896d52410f4b84c5673dadec2ed188104efb39243dd743a470d5d06cebb096f + url: "https://pub.dev" + source: hosted + version: "2.2.1" path_provider_windows: dependency: transitive description: @@ -1805,6 +1845,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.1" + shared_preferences_tizen: + dependency: "direct main" + description: + name: shared_preferences_tizen + sha256: fbf7194c2f6d97c68e254257172bb44a3a34a6ecfaceeedd208b5bf69d836b21 + url: "https://pub.dev" + source: hosted + version: "2.3.2" shared_preferences_web: dependency: transitive description: @@ -1883,7 +1931,7 @@ packages: source: hosted version: "1.10.1" sqflite: - dependency: transitive + dependency: "direct main" description: name: sqflite sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 @@ -1922,8 +1970,16 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + sqflite_tizen: + dependency: "direct main" + description: + name: sqflite_tizen + sha256: fb144054bd7ebccbb4737eea0f948f6b5e6b45a832f797c3fbd3792d08aeefee + url: "https://pub.dev" + source: hosted + version: "0.1.3" sqlite3: - dependency: transitive + dependency: "direct main" description: name: sqlite3 sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2" @@ -1931,13 +1987,13 @@ packages: source: hosted version: "2.9.4" sqlite3_flutter_libs: - dependency: transitive + dependency: "direct main" description: name: sqlite3_flutter_libs - sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df" + sha256: "1e800ebe7f85a80a66adacaa6febe4d5f4d8b75f244e9838a27cb2ffc7aec08d" url: "https://pub.dev" source: hosted - version: "0.5.40" + version: "0.5.41" sqlparser: dependency: transitive description: @@ -2042,6 +2098,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + tizen_app_control: + dependency: transitive + description: + name: tizen_app_control + sha256: "1822a0815434db29b0ac3cf8c37c4d4ad33da08704f68701a926bc99550ccda1" + url: "https://pub.dev" + source: hosted + version: "0.2.3" + tizen_interop: + dependency: transitive + description: + name: tizen_interop + sha256: "46303c36a7e45491ce0149c77a3f54f3d57654938983c482ab0363a8ebe6ee27" + url: "https://pub.dev" + source: hosted + version: "0.3.0" transparent_image: dependency: "direct main" description: @@ -2146,6 +2218,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + url_launcher_tizen: + dependency: "direct main" + description: + name: url_launcher_tizen + sha256: c959c3d77b3bff18258faf36dd1f8f647ddac56549860fcf5b2894c46f3989d8 + url: "https://pub.dev" + source: hosted + version: "2.1.4" url_launcher_web: dependency: transitive description: @@ -2242,6 +2322,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.6.0" + video_player_tizen: + dependency: "direct main" + description: + name: video_player_tizen + sha256: f629713b3a901965e04a4ab3f94988f94f0a6224d412ce416c396e148314b8d0 + url: "https://pub.dev" + source: hosted + version: "2.5.8" video_player_web: dependency: transitive description: @@ -2282,6 +2370,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + wakelock_plus_tizen: + dependency: "direct main" + description: + name: wakelock_plus_tizen + sha256: "12bb99ccc5503bdc98d850b6fb01ac424e05d78c9805dc1c80d01c5d73a70a00" + url: "https://pub.dev" + source: hosted + version: "2.0.0" watcher: dependency: transitive description: @@ -2346,6 +2442,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.14.0" + webview_flutter_tizen: + dependency: "direct main" + description: + name: webview_flutter_tizen + sha256: "174b10f846f613da6327e8f11dea3a69f55d69edea47625e576de6182dfb8320" + url: "https://pub.dev" + source: hosted + version: "0.9.7" webview_flutter_wkwebview: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 61d7e21a9..07aa62127 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -124,6 +124,22 @@ dependencies: drift_sync: ^0.14.0 drift_db_viewer: ^2.1.0 + # Tizen-specific pl + + + Exe + tizen80 + + + + + + + + + + %(RecursiveDir) + + + + diff --git a/tizen/shared/res/fladder_icon.png b/tizen/shared/res/fladder_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d88be009de5fc5aaf07fd4d167b531e495beac GIT binary patch literal 199313 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 v24WcW9z3890JF05AmIO=|4k1R?Gh{1sV= + + + + + fladder_icon.png + + + + + + + From 76e7433e94fb1145faa93d909a953ee3e3211695 Mon Sep 17 00:00:00 2001 From: popdollar Date: Sat, 20 Dec 2025 14:10:12 +0100 Subject: [PATCH 02/13] feat: made videos play controls and colors are still not great. more work needs done --- .../settings/video_player_settings.dart | 13 +- .../settings/player_settings_page.dart | 4 + lib/wrappers/media_control_wrapper.dart | 2 + lib/wrappers/players/tizen_player.dart | 156 ++++++++++++++++++ tizen/tizen-manifest.xml | 15 +- 5 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 lib/wrappers/players/tizen_player.dart diff --git a/lib/models/settings/video_player_settings.dart b/lib/models/settings/video_player_settings.dart index 636f73067..6300a53f5 100644 --- a/lib/models/settings/video_player_settings.dart +++ b/lib/models/settings/video_player_settings.dart @@ -11,6 +11,9 @@ import 'package:fladder/models/settings/key_combinations.dart'; import 'package:fladder/util/bitrate_helper.dart'; import 'package:fladder/util/localization_helper.dart'; + +import 'package:flutter_tizen/flutter_tizen.dart'; + part 'video_player_settings.freezed.dart'; part 'video_player_settings.g.dart'; @@ -90,7 +93,7 @@ abstract class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel { factory VideoPlayerSettingsModel.fromJson(Map json) => _$VideoPlayerSettingsModelFromJson(json); PlayerOptions get wantedPlayer => - leanBackMode ? PlayerOptions.nativePlayer : playerOptions ?? PlayerOptions.platformDefaults; + leanBackMode && !isTizen ? PlayerOptions.nativePlayer : playerOptions ?? PlayerOptions.platformDefaults; Map get currentShortcuts => _defaultVideoHotKeys.map((key, value) => MapEntry(key, hotKeys[key] ?? value)); @@ -139,11 +142,12 @@ abstract class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel { enum PlayerOptions { libMDK, libMPV, - nativePlayer; + nativePlayer, + tizenPlayer; const PlayerOptions(); - static Iterable get available => leanBackMode + static Iterable get available => leanBackMode && !isTizen ? {PlayerOptions.nativePlayer} : kIsWeb ? {PlayerOptions.libMPV} @@ -153,8 +157,10 @@ enum PlayerOptions { }; static PlayerOptions get platformDefaults { + if (isTizen) return PlayerOptions.tizenPlayer; if (leanBackMode) return PlayerOptions.nativePlayer; if (kIsWeb) return PlayerOptions.libMPV; + return switch (defaultTargetPlatform) { _ => PlayerOptions.libMPV, }; @@ -164,6 +170,7 @@ enum PlayerOptions { PlayerOptions.libMDK => "MDK", PlayerOptions.libMPV => "MPV", PlayerOptions.nativePlayer => "Native", + PlayerOptions.tizenPlayer => "Tizen", }; } diff --git a/lib/screens/settings/player_settings_page.dart b/lib/screens/settings/player_settings_page.dart index 1748d1201..398a47805 100644 --- a/lib/screens/settings/player_settings_page.dart +++ b/lib/screens/settings/player_settings_page.dart @@ -389,6 +389,10 @@ class _PlayerSettingsPageState extends ConsumerState { PlayerOptions.libMDK => SettingsMessageBox( messageType: MessageType.info, "${context.localized.noVideoPlayerOptions}\n${context.localized.mdkExperimental}"), + PlayerOptions.tizenPlayer => SettingsMessageBox( + messageType: MessageType.info, + "${context.localized.noVideoPlayerOptions}\n${"Tizen"}", + ), }, ), Column( diff --git a/lib/wrappers/media_control_wrapper.dart b/lib/wrappers/media_control_wrapper.dart index 0796fdfd7..b51a3342f 100644 --- a/lib/wrappers/media_control_wrapper.dart +++ b/lib/wrappers/media_control_wrapper.dart @@ -25,6 +25,7 @@ import 'package:fladder/wrappers/players/lib_mdk.dart' import 'package:fladder/wrappers/players/lib_mpv.dart'; import 'package:fladder/wrappers/players/native_player.dart'; import 'package:fladder/wrappers/players/player_states.dart'; +import 'package:fladder/wrappers/players/tizen_player.dart'; class MediaControlsWrapper extends BaseAudioHandler implements VideoPlayerControlsCallback { MediaControlsWrapper({required this.ref}); @@ -78,6 +79,7 @@ class MediaControlsWrapper extends BaseAudioHandler implements VideoPlayerContro PlayerOptions.libMDK => LibMDK(), PlayerOptions.libMPV => LibMPV(), PlayerOptions.nativePlayer => NativePlayer(), + PlayerOptions.tizenPlayer => TizenPlayer(), }; setup(player); diff --git a/lib/wrappers/players/tizen_player.dart b/lib/wrappers/players/tizen_player.dart new file mode 100644 index 000000000..8df17e8ab --- /dev/null +++ b/lib/wrappers/players/tizen_player.dart @@ -0,0 +1,156 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:video_player/video_player.dart'; + +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/models/settings/video_player_settings.dart'; +import 'package:fladder/screens/video_player/video_player.dart' as video_screen; +import 'package:fladder/wrappers/players/base_player.dart'; +import 'package:fladder/wrappers/players/player_states.dart'; + +class TizenPlayer extends BasePlayer { + VideoPlayerController? _controller; + bool externalSubEnabled = false; + + final StreamController _stateController = StreamController.broadcast(); + + @override + Stream get stateStream => _stateController.stream; + + @override + Future init(VideoPlayerSettingsModel settings) async { + await dispose(); + } + + @override + Future dispose() async { + await _controller?.dispose(); + _controller = null; + } + + @override + Future loadVideo(String url, bool play) async { + await _controller?.dispose(); + + final validUrl = Uri.tryParse(url)?.isAbsolute ?? false; + _controller = validUrl + ? VideoPlayerController.network(url) + : VideoPlayerController.file(File(url)); + + await _controller?.initialize(); + _controller?.addListener(_updateState); + + if (play) { + await _controller?.play(); + } + + _updateState(); + } + + void _updateState() { + if (_controller == null) return; + + final value = _controller!.value; + _stateController.add( + lastState.update( + playing: value.isPlaying, + completed: value.position >= (value.duration ?? Duration.zero), + position: value.position, + duration: value.duration ?? Duration.zero, + volume: (value.volume) * 100, + rate: value.playbackSpeed, + buffering: value.isBuffering, + buffer: _calculateBufferedDuration(value), + ), + ); + } + + Duration _calculateBufferedDuration(VideoPlayerValue value) { + if (value.buffered.isEmpty) return Duration.zero; + return value.buffered.fold(value.position, (total, range) => total + (range.end - range.start)); + } + + @override + Future open(BuildContext context) async { + await Navigator.of(context, rootNavigator: true).push( + MaterialPageRoute( + builder: (_) => const video_screen.VideoPlayer(), + ), + ); + } + + @override + Future pause() => _controller?.pause() ?? Future.value(); + + @override + Future play() => _controller?.play() ?? Future.value(); + + @override + Future playOrPause() async { + if (_controller?.value.isPlaying ?? false) { + await _controller?.pause(); + } else { + await _controller?.play(); + } + } + + @override + Future seek(Duration position) async => _controller?.seekTo(position); + + @override + Future stop() async => await _controller?.pause(); + + @override + Future setVolume(double volume) async => _controller?.setVolume(volume / 100); + + @override + Future loop(bool loop) async => _controller?.setLooping(loop); + + @override + Future setAudioTrack(AudioStreamModel? model, PlaybackModel playbackModel) async { + // Not supported by video_player_tizen + return model?.index ?? 0; + } + + @override + Future setSubtitleTrack(SubStreamModel? model, PlaybackModel playbackModel) async { + // External subtitles not supported by video_player_tizen + return model?.index ?? 0; + } + + @override + Future setSpeed(double speed) async => _controller?.setPlaybackSpeed(speed); + + @override + Future takeScreenshot() async { + // Not supported natively + return null; + } + + @override + Widget? videoWidget(Key key, BoxFit fit) { + if (_controller == null) return null; + + return Container( + key: key, + color: Colors.transparent, + child: ValueListenableBuilder( + valueListenable: _controller!, + builder: (context, value, child) { + final aspectRatio = value.isInitialized ? value.aspectRatio : 16 / 9; + return AspectRatio( + aspectRatio: aspectRatio, + child: VideoPlayer(_controller!), + ); + }, + ), + ); + } + + @override + Widget? subtitles(bool showOverlay, {GlobalKey? controlsKey}) => null; +} diff --git a/tizen/tizen-manifest.xml b/tizen/tizen-manifest.xml index 362eef146..214c06b05 100644 --- a/tizen/tizen-manifest.xml +++ b/tizen/tizen-manifest.xml @@ -8,6 +8,17 @@ - - + + http://developer.samsung.com/privilege/productinfo + http://tizen.org/privilege/internet + http://tizen.org/privilege/mediastorage + http://tizen.org/privilege/externalstorage + http://developer.samsung.com/privilege/drmplay + http://tizen.org/privilege/content.write + http://tizen.org/privilege/content.read + http://tizen.org/privilege/tv.channel + http://tizen.org/privilege/tv.display + http://tizen.org/privilege/tv.window + http://tizen.org/privilege/tv.inputdevice + From 9a11426b4ead69c971ef1a347e034b52275097de Mon Sep 17 00:00:00 2001 From: popdollar Date: Mon, 22 Dec 2025 13:31:08 +0100 Subject: [PATCH 03/13] feat: subtitles and audiotracks in a working state --- lib/wrappers/media_control_wrapper.dart | 29 ++- lib/wrappers/players/tizen_player.dart | 283 +++++++++++++++++++----- pubspec.lock | 24 +- pubspec.yaml | 5 +- 4 files changed, 268 insertions(+), 73 deletions(-) diff --git a/lib/wrappers/media_control_wrapper.dart b/lib/wrappers/media_control_wrapper.dart index b51a3342f..f6c1e020b 100644 --- a/lib/wrappers/media_control_wrapper.dart +++ b/lib/wrappers/media_control_wrapper.dart @@ -30,6 +30,11 @@ import 'package:fladder/wrappers/players/tizen_player.dart'; class MediaControlsWrapper extends BaseAudioHandler implements VideoPlayerControlsCallback { MediaControlsWrapper({required this.ref}); + /// Notifier used to inform UI that subtitle source/mode changed. + /// Incrementing the value will notify any listeners (e.g. subtitle widgets) + /// so they can refresh immediately without waiting for a full controls rebuild. + final ValueNotifier subtitleChangeNotifier = ValueNotifier(0); + BasePlayer? _player; bool get hasPlayer => _player != null; @@ -43,8 +48,18 @@ class MediaControlsWrapper extends BaseAudioHandler implements VideoPlayerContro Stream? get stateStream => _player?.stateStream; PlayerState? get lastState => _player?.lastState; - Widget? subtitleWidget(bool showOverlay, {GlobalKey? controlsKey}) => - _player?.subtitles(showOverlay, controlsKey: controlsKey); + Widget? subtitleWidget(bool showOverlay, {GlobalKey? controlsKey}) { + final inner = _player?.subtitles(showOverlay, controlsKey: controlsKey); + if (inner == null) return null; + + // Wrap the player's subtitle widget in a ValueListenableBuilder so we can + // force a rebuild when the subtitle source/mode changes without needing a + // full controls rebuild. + return ValueListenableBuilder( + valueListenable: subtitleChangeNotifier, + builder: (context, _, __) => _player?.subtitles(showOverlay, controlsKey: controlsKey) ?? const SizedBox.shrink(), + ); + } Widget? videoWidget(Key key, BoxFit fit) => _player?.videoWidget(key, fit); final Ref ref; @@ -310,8 +325,14 @@ class MediaControlsWrapper extends BaseAudioHandler implements VideoPlayerContro Future setAudioTrack(AudioStreamModel? model, PlaybackModel playbackModel) async => await _player?.setAudioTrack(model, playbackModel) ?? -1; - Future setSubtitleTrack(SubStreamModel? model, PlaybackModel playbackModel) async => - await _player?.setSubtitleTrack(model, playbackModel) ?? -1; + Future setSubtitleTrack(SubStreamModel? model, PlaybackModel playbackModel) async { + final result = await _player?.setSubtitleTrack(model, playbackModel) ?? -1; + // Notify UI listeners that subtitle source/mode changed so subtitles can refresh + try { + subtitleChangeNotifier.value = subtitleChangeNotifier.value + 1; + } catch (_) {} + return result; + } Future setVolume(double volume) async => _player?.setVolume(volume); diff --git a/lib/wrappers/players/tizen_player.dart b/lib/wrappers/players/tizen_player.dart index 8df17e8ab..570349daa 100644 --- a/lib/wrappers/players/tizen_player.dart +++ b/lib/wrappers/players/tizen_player.dart @@ -3,7 +3,13 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:video_player_videohole/video_player.dart'; +import 'package:subtitle/subtitle.dart'; + +import 'package:fladder/models/settings/subtitle_settings_model.dart'; +import 'package:fladder/providers/settings/subtitle_settings_provider.dart'; +import 'package:fladder/util/subtitle_position_calculator.dart'; import 'package:fladder/models/items/media_streams_model.dart'; import 'package:fladder/models/playback/playback_model.dart'; @@ -14,17 +20,16 @@ import 'package:fladder/wrappers/players/player_states.dart'; class TizenPlayer extends BasePlayer { VideoPlayerController? _controller; - bool externalSubEnabled = false; - final StreamController _stateController = StreamController.broadcast(); + SubtitleController? _externalSubtitleController; + bool _externalSubEnabled = false; + @override Stream get stateStream => _stateController.stream; @override - Future init(VideoPlayerSettingsModel settings) async { - await dispose(); - } + Future init(VideoPlayerSettingsModel settings) async => await dispose(); @override Future dispose() async { @@ -41,12 +46,10 @@ class TizenPlayer extends BasePlayer { ? VideoPlayerController.network(url) : VideoPlayerController.file(File(url)); - await _controller?.initialize(); - _controller?.addListener(_updateState); + _controller!.addListener(_updateState); + await _controller!.initialize(); - if (play) { - await _controller?.play(); - } + if (play) await _controller!.play(); _updateState(); } @@ -55,102 +58,264 @@ class TizenPlayer extends BasePlayer { if (_controller == null) return; final value = _controller!.value; + _stateController.add( lastState.update( playing: value.isPlaying, - completed: value.position >= (value.duration ?? Duration.zero), + completed: value.position >= value.duration.end, position: value.position, - duration: value.duration ?? Duration.zero, + duration: value.duration.end, volume: (value.volume) * 100, rate: value.playbackSpeed, buffering: value.isBuffering, - buffer: _calculateBufferedDuration(value), + buffer: Duration(milliseconds: value.buffered), ), ); } - Duration _calculateBufferedDuration(VideoPlayerValue value) { - if (value.buffered.isEmpty) return Duration.zero; - return value.buffered.fold(value.position, (total, range) => total + (range.end - range.start)); - } - @override Future open(BuildContext context) async { await Navigator.of(context, rootNavigator: true).push( - MaterialPageRoute( - builder: (_) => const video_screen.VideoPlayer(), - ), + MaterialPageRoute(builder: (_) => const video_screen.VideoPlayer()), ); } @override Future pause() => _controller?.pause() ?? Future.value(); - @override Future play() => _controller?.play() ?? Future.value(); - @override - Future playOrPause() async { - if (_controller?.value.isPlaying ?? false) { - await _controller?.pause(); - } else { - await _controller?.play(); - } - } - + Future playOrPause() async => lastState.playing ? _controller?.pause() : _controller?.play(); @override Future seek(Duration position) async => _controller?.seekTo(position); - @override - Future stop() async => await _controller?.pause(); - + Future stop() async => _controller?.pause(); @override Future setVolume(double volume) async => _controller?.setVolume(volume / 100); - @override Future loop(bool loop) async => _controller?.setLooping(loop); @override Future setAudioTrack(AudioStreamModel? model, PlaybackModel playbackModel) async { - // Not supported by video_player_tizen - return model?.index ?? 0; + final wantedAudioStream = model ?? playbackModel.defaultAudioStream; + if (wantedAudioStream == AudioStreamModel.no() || wantedAudioStream == null) { + return -1; + } else { + final indexOf = playbackModel.audioStreams?.indexOf(wantedAudioStream); + final tracks = await _controller?.audioTracks; + if (tracks != null && tracks.isNotEmpty) { + if (indexOf != null) { + final track = tracks.elementAt((indexOf - 1)); + _controller?.setTrackSelection(track); + _controller?.play(); // refresh captions + } + return wantedAudioStream.index; + } + } + return -1; } @override - Future setSubtitleTrack(SubStreamModel? model, PlaybackModel playbackModel) async { - // External subtitles not supported by video_player_tizen - return model?.index ?? 0; + Future setSubtitleTrack( + SubStreamModel? model, + PlaybackModel playbackModel, + ) async { + final wanted = model ?? playbackModel.defaultSubStream; + + if (wanted == null || wanted == SubStreamModel.no()) { + _externalSubEnabled = true; + _externalSubtitleController = null; + return -1; + } + + if (wanted.isExternal && wanted.url != null) { + loadExternalSubtitle(wanted.url!); + _controller?.play(); // refresh captions + return wanted.index; + } + + // Internal subtitle + _externalSubEnabled = false; + + final tracks = await _controller?.textTracks; + if (tracks != null && tracks.isNotEmpty) { + final indexOf = playbackModel.subStreams?.indexOf(wanted); + if (indexOf != null) { + if (indexOf - 1 >= 0) { + final track = tracks.elementAt(indexOf - 1); + _controller?.setTrackSelection(track); + _controller?.play(); // refresh captions + } else { + //No subtitles + _externalSubEnabled = true; + _externalSubtitleController = null; + _controller!.play(); + + } + } + } +//_updateState(); + return wanted.index; + } + + + Future loadExternalSubtitle( + String data, + ) async { + _externalSubEnabled = true; + _controller!.play(); + final provider = SubtitleProvider.fromNetwork( + Uri.tryParse(data) ?? Uri.parse('') + ); + + final controller = SubtitleController(provider: provider); + controller.initial(); + _externalSubtitleController = controller; } @override Future setSpeed(double speed) async => _controller?.setPlaybackSpeed(speed); @override - Future takeScreenshot() async { - // Not supported natively - return null; - } + Future takeScreenshot() async => null; + @override Widget? videoWidget(Key key, BoxFit fit) { - if (_controller == null) return null; + if (_controller == null || !_controller!.value.isInitialized) return null; - return Container( - key: key, - color: Colors.transparent, - child: ValueListenableBuilder( - valueListenable: _controller!, - builder: (context, value, child) { - final aspectRatio = value.isInitialized ? value.aspectRatio : 16 / 9; - return AspectRatio( - aspectRatio: aspectRatio, - child: VideoPlayer(_controller!), - ); - }, + return Center( + child: AspectRatio( + aspectRatio: _controller!.value.aspectRatio, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(_controller!), + //ClosedCaption(), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + _controller!.value.isPlaying + ? _controller!.pause() + : _controller!.play(); + }, + ), + ], + ), ), ); } @override - Widget? subtitles(bool showOverlay, {GlobalKey? controlsKey}) => null; + Widget? subtitles(bool showOverlay, {GlobalKey? controlsKey}) { + if (_controller == null) return null; + + return _TizenSubtitles( + controller: _controller!, + showOverlay: showOverlay, + controlsKey: controlsKey, + externalSubtitleController: _externalSubtitleController, + useExternal: _externalSubEnabled, + ); + } +} + +class _TizenSubtitles extends ConsumerStatefulWidget { + final VideoPlayerController controller; + final bool showOverlay; + final GlobalKey? controlsKey; + + final SubtitleController? externalSubtitleController; + final bool useExternal; + + const _TizenSubtitles({ + required this.controller, + this.showOverlay = false, + this.controlsKey, + this.externalSubtitleController, + required this.useExternal, + }); + + @override + _TizenSubtitlesState createState() => _TizenSubtitlesState(); +} + +class _TizenSubtitlesState extends ConsumerState<_TizenSubtitles> { + String _cachedSubtitleText = ''; + String? _lastCaption; + double? _cachedMenuHeight; + + @override + void initState() { + super.initState(); + widget.controller.addListener(_onControllerUpdate); + } + + @override + void dispose() { + widget.controller.removeListener(_onControllerUpdate); + super.dispose(); + } + + void _onControllerUpdate() { + final position = widget.controller.value.position; + + String subtitle = ''; + + if (widget.useExternal && widget.externalSubtitleController != null) { + subtitle = widget.externalSubtitleController!.durationSearch(position)?.data.trim() ?? ''; + } else if (!widget.useExternal) { + subtitle = widget.controller.value.caption.text.trim(); + } + + if (subtitle != _lastCaption) { + setState(() { + _lastCaption = subtitle; + _cachedSubtitleText = subtitle; + }); + } + } + + + + @override + Widget build(BuildContext context) { + _measureMenuHeight(); + + final settings = ref.watch(subtitleSettingsProvider); + final padding = MediaQuery.paddingOf(context); + + final text = _cachedSubtitleText; + + if (text.isEmpty) return const SizedBox.shrink(); + + final offset = SubtitlePositionCalculator.calculateOffset( + settings: settings, + showOverlay: widget.showOverlay, + screenHeight: MediaQuery.sizeOf(context).height, + menuHeight: _cachedMenuHeight, + ); + + return SubtitleText( + subModel: settings, + padding: padding, + offset: offset, + text: text, + ); + } + + void _measureMenuHeight() { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted || widget.controlsKey == null) return; + + final RenderBox? renderBox = widget.controlsKey?.currentContext?.findRenderObject() as RenderBox?; + final newHeight = renderBox?.size.height; + + if (newHeight != _cachedMenuHeight && newHeight != null) { + setState(() { + _cachedMenuHeight = newHeight; + }); + } + }); + } } diff --git a/pubspec.lock b/pubspec.lock index 8ba22fa79..d4decfc34 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2058,6 +2058,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + subtitle: + dependency: "direct main" + description: + name: subtitle + sha256: "29115fbaa5d87c5909ffa477cbfdeec2c6ee8ac9a5ef3dce9b2db731afc79f26" + url: "https://pub.dev" + source: hosted + version: "0.1.4" swagger_dart_code_generator: dependency: "direct dev" description: @@ -2142,18 +2150,18 @@ packages: dependency: "direct main" description: name: universal_html - sha256: c0bcae5c733c60f26c7dfc88b10b0fd27cbcc45cb7492311cdaa6067e21c9cd4 + sha256: "0a1795dc516ed9fc48c6fdee8e9a99445cdce6871845d34e31c13184d7a743aa" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.2.5" universal_io: dependency: transitive description: name: universal_io - sha256: f63cbc48103236abf48e345e07a03ce5757ea86285ed313a6a032596ed9301e2 + sha256: ba9dde5f7c6d8ec7ed856bef0eb01c425881acae7748f77dac4d5cc46f2edf04 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.2.3" universal_platform: dependency: transitive description: @@ -2322,14 +2330,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.6.0" - video_player_tizen: + video_player_videohole: dependency: "direct main" description: - name: video_player_tizen - sha256: f629713b3a901965e04a4ab3f94988f94f0a6224d412ce416c396e148314b8d0 + name: video_player_videohole + sha256: "4897cddd805b329c8236057cf554aa979d79aba4d1d85d9779fe572edbb56555" url: "https://pub.dev" source: hosted - version: "2.5.8" + version: "0.5.8" video_player_web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 07aa62127..34c798df5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -128,7 +128,6 @@ dependencies: path_provider_tizen: ^2.1.0 shared_preferences_tizen: ^2.3.2 url_launcher_tizen: ^2.1.4 - video_player_tizen: ^2.5.8 connectivity_plus_tizen: ^1.2.2 wakelock_plus_tizen: ^2.0.0 webview_flutter_tizen: ^0.9.7 @@ -139,7 +138,9 @@ dependencies: sqlite3: ^2.9.4 sqlite3_flutter_libs: ^0.5.41 drift_sqflite: ^2.0.1 - + video_player_videohole: ^0.5.8 + subtitle: ^0.1.4 + # Other async: ^2.13.0 xid: ^1.2.1 From 5f20bdf3b1fb653c77e80638e8cb12f6d5cd1be8 Mon Sep 17 00:00:00 2001 From: popdollar Date: Fri, 26 Dec 2025 16:04:38 +0100 Subject: [PATCH 04/13] feat: video overlay now works with tizen created a specific video_player_controls for the tizen. Can possibly be used for all TVs. It is mostly just a copy of the already existing DesktopOverlay. --- .../tizen_video_player_controls.dart | 960 ++++++++++++++++++ lib/screens/video_player/video_player.dart | 4 +- 2 files changed, 963 insertions(+), 1 deletion(-) create mode 100644 lib/screens/video_player/tizen_video_player_controls.dart diff --git a/lib/screens/video_player/tizen_video_player_controls.dart b/lib/screens/video_player/tizen_video_player_controls.dart new file mode 100644 index 000000000..0795eab87 --- /dev/null +++ b/lib/screens/video_player/tizen_video_player_controls.dart @@ -0,0 +1,960 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'package:async/async.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:iconsax_plus/iconsax_plus.dart'; +import 'package:screen_brightness/screen_brightness.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/media_segments_model.dart'; +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/models/settings/video_player_settings.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/screens/shared/default_title_bar.dart'; +import 'package:fladder/screens/shared/media/components/item_logo.dart'; +import 'package:fladder/screens/video_player/components/video_playback_information.dart'; +import 'package:fladder/screens/video_player/components/video_player_controls_extras.dart'; +import 'package:fladder/screens/video_player/components/video_player_options_sheet.dart'; +import 'package:fladder/screens/video_player/components/video_player_quality_controls.dart'; +// import 'package:fladder/screens/video_player/components/video_player_screenshot_indicator.dart'; +import 'package:fladder/screens/video_player/components/video_player_seek_indicator.dart'; +// import 'package:fladder/screens/video_player/components/video_player_speed_indicator.dart'; +// import 'package:fladder/screens/video_player/components/video_player_volume_indicator.dart'; +import 'package:fladder/screens/video_player/components/video_progress_bar.dart'; +import 'package:fladder/screens/video_player/components/video_volume_slider.dart'; +import 'package:fladder/util/adaptive_layout/adaptive_layout.dart'; +import 'package:fladder/util/duration_extensions.dart'; +import 'package:fladder/util/input_handler.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/full_screen_helpers/full_screen_wrapper.dart'; + +class TVControls extends ConsumerStatefulWidget { + const TVControls({super.key}); + + @override + ConsumerState createState() => _TVControlsState(); +} + +class _TVControlsState extends ConsumerState { + final GlobalKey _bottomControlsKey = GlobalKey(); + + late final initInputDevice = AdaptiveLayout.inputDeviceOf(context); + + late RestartableTimer timer = RestartableTimer( + const Duration(seconds: 5), + () => mounted ? toggleOverlay(value: false) : null, + ); + + double? previousVolume; + + final fadeDuration = const Duration(milliseconds: 350); + bool showOverlay = true; + bool wasPlaying = false; + + SystemUiMode? _currentSystemUiMode; + String? activeIndicator; + RestartableTimer? _activeIndicatorTimer; + final FocusNode _controlsFocusNode = FocusNode(); + // Navigation for remote (D-pad) - list is built dynamically in build() + List _navOrder = []; + int _navIndex = 0; + final Map _navFocusNodes = {}; + + late final double topPadding = MediaQuery.of(context).viewPadding.top; + late final double bottomPadding = MediaQuery.of(context).viewPadding.bottom; + + @override + void initState() { + super.initState(); + timer.reset(); + // Register a small hardware handler to catch remote media keys that may not be + // present in the configured hotkey map (some remotes send LogicalKeyboardKey.mediaPlayPause, + // etc.). This ensures Play/Pause on Samsung remotes is handled. + HardwareKeyboard.instance.addHandler(_tizenHardwareHandler); + } + + void _setActiveIndicator(String value) { + _activeIndicatorTimer?.cancel(); + setState(() { + activeIndicator = value; + }); + _activeIndicatorTimer = RestartableTimer(const Duration(seconds: 1), () { + setState(() { + activeIndicator = null; + }); + }); + } + + Widget _wrapNav(String id, Widget child) { + // Make this control focusable and handle activation via D-pad/select. + final node = _navFocusNodes.putIfAbsent(id, () => FocusNode()); + return FocusableActionDetector( + focusNode: node, + enabled: showOverlay, + shortcuts: { + // Map remote 'select' to activation. Avoid mapping Enter/Space here + // to prevent double-activation (Enter/Space are handled by + // individual buttons which would otherwise be invoked twice). + //LogicalKeySet(LogicalKeyboardKey.select): ActivateIntent(), + }, + actions: >{ + ActivateIntent: CallbackAction(onInvoke: (intent) { + _activateSelection(); + return null; + }), + }, + onFocusChange: (hasFocus) { + if (hasFocus) { + final idx = _navOrder.indexOf(id); + if (idx >= 0) { + setState(() { + _navIndex = idx; + _setActiveIndicator(id); + }); + } + } + }, + child: Builder(builder: (context) { + final focused = Focus.of(context).hasFocus; + if (!showOverlay) return child; + return Container( + decoration: focused + ? BoxDecoration( + border: Border.all(color: Colors.white.withOpacity(0.9), width: 2), + borderRadius: BorderRadius.circular(8), + ) + : null, + padding: focused ? const EdgeInsets.all(2) : EdgeInsets.zero, + child: child, + ); + }), + ); + } + + void _ensureNavOrder() { + // Build nav order based on currently visible controls. + // This is a best-effort list; presence of items depends on layout and input device. + final List order = []; + // Bottom control row (most important controls) + // Options / extra + order.add('options'); + // Subtitle / audio (may be present or not; we'll keep keys even if widgets not shown) + order.add('subtitle'); + order.add('audio'); + order.add('previous'); + order.add('seekBack'); + order.add('playPause'); + order.add('seekForward'); + order.add('next'); + order.add('quality'); + + _navOrder = order; + if (_navIndex >= _navOrder.length) _navIndex = 0; + + // Ensure focus nodes exist for each nav id and clean up removed ones + final existing = Set.from(_navFocusNodes.keys); + for (final id in _navOrder) { + existing.remove(id); + _navFocusNodes.putIfAbsent(id, () => FocusNode()); + } + // Dispose any nodes that are no longer used + for (final id in existing) { + _navFocusNodes[id]?.dispose(); + _navFocusNodes.remove(id); + } + } + + void _moveSelection(int delta) { + if (_navOrder.isEmpty) return; + setState(() { + _navIndex = (_navIndex + delta) % _navOrder.length; + if (_navIndex < 0) _navIndex += _navOrder.length; + _setActiveIndicator(_navOrder[_navIndex]); + }); + // Ensure the focused node follows our selection index + final id = _navOrder[_navIndex]; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) _navFocusNodes[id]?.requestFocus(); + }); + } + + void _activateSelection() { + if (_navOrder.isEmpty) return; + final id = _navOrder[_navIndex]; + // Map ids to actions + switch (id) { + case 'options': + showVideoPlayerOptions(context, () => minimizePlayer(context)); + break; + case 'subtitle': + showSubSelection(context); + break; + case 'audio': + showAudioSelection(context); + break; + case 'previous': + loadPreviousVideo(ref)?.call(); + break; + case 'seekBack': + final backwardSpeed = + ref.read(userProvider.select((value) => value?.userSettings?.skipBackDuration.inSeconds ?? 10)); + seekBack(ref, seconds: backwardSpeed); + break; + case 'playPause': + doPlayPause(); + break; + case 'seekForward': + + final forwardSpeed = + ref.read(userProvider.select((value) => value?.userSettings?.skipForwardDuration.inSeconds ?? 30)); + seekForward(ref, seconds: forwardSpeed); + break; + case 'next': + loadNextVideo(ref)?.call(); + break; + case 'quality': + openQualityOptions(context); + break; + default: + break; + } + } + + void doPlayPause() { + ref.read(videoPlayerProvider).playOrPause(); + _setActiveIndicator('Play/Pause'); + resetTimer(); + } + + @override + void dispose() { + HardwareKeyboard.instance.removeHandler(_tizenHardwareHandler); + _controlsFocusNode.dispose(); + for (final node in _navFocusNodes.values) { + node.dispose(); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + // Build nav order for remote navigation each build so it reflects visible controls + _ensureNavOrder(); + final mediaSegments = ref.watch(playBackModel.select((value) => value?.mediaSegments)); + final player = ref.watch(videoPlayerProvider); + final subtitleWidget = player.subtitleWidget(showOverlay, controlsKey: _bottomControlsKey); + final currentShortcuts = ref.watch(videoPlayerSettingsProvider.select((value) => value.currentShortcuts)); + // When the overlay (controls) is visible we want arrow left/right to navigate UI elements + // instead of seeking. Filter out seek hotkeys while overlay is visible so framework focus + // navigation can handle them. When overlay is hidden, keep seek hotkeys so remote arrows + // control seeking. + final effectiveKeyMap = showOverlay ? Map.of(currentShortcuts) : currentShortcuts; + if (showOverlay) { + effectiveKeyMap.remove(VideoHotKeys.seekForward); + effectiveKeyMap.remove(VideoHotKeys.seekBack); + + + } + effectiveKeyMap.remove(VideoHotKeys.playPause); + effectiveKeyMap.remove(VideoHotKeys.exit); + + return Listener( + onPointerSignal: setVolume, + child: InputHandler( + autoFocus: true, + listenRawKeyboard: true, + keyMap: effectiveKeyMap, + //keyMapResult: _onKey, + child: PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) { + if (!didPop) { + closePlayer(); + } + }, + child: Stack( + children: [ + if (subtitleWidget != null) subtitleWidget, + Positioned.fill( + child: AnimatedOpacity( + duration: fadeDuration, + opacity: showOverlay ? 1 : 0, + child: Column( + children: [ + topButtons(context), + const Spacer(), + ExcludeFocus( + excluding: !showOverlay, + child: FocusTraversalGroup( + policy: OrderedTraversalPolicy(), + child: Focus( + focusNode: _controlsFocusNode, + child: bottomButtons(context), + ), + ), + ), + ], + ), + ), + ), + if (!showOverlay) const VideoPlayerSeekIndicator(), + + Consumer( + builder: (context, ref, child) { + final position = ref.watch(mediaPlaybackProvider.select((value) => value.position)); + MediaSegment? segment = mediaSegments?.atPosition(position); + SegmentVisibility forceShow = + segment?.visibility(position, force: showOverlay) ?? SegmentVisibility.hidden; + final segmentSkipType = ref + .watch(videoPlayerSettingsProvider.select((value) => value.segmentSkipSettings[segment?.type])); + final autoSkip = forceShow != SegmentVisibility.hidden && + segmentSkipType == SegmentSkip.skip && + player.lastState?.buffering == false; + if (autoSkip) { + skipToSegmentEnd(segment); + } + return Stack( + children: [ + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(32), + child: SkipSegmentButton( + segment: segment, + skipType: segmentSkipType, + visibility: forceShow, + pressedSkip: () => skipToSegmentEnd(segment), + ), + ), + ), + ], + ); + }, + ), + ], + ), + ), + ), + ); + } + + Widget playButton(bool playing, bool buffering) { + return Align( + alignment: Alignment.center, + child: AnimatedScale( + curve: Curves.easeInOutCubicEmphasized, + scale: playing + ? 0 + : buffering + ? 0 + : 1, + duration: const Duration(milliseconds: 250), + child: IconButton.outlined( + onPressed: () => ref.read(videoPlayerProvider).play(), + isSelected: true, + iconSize: 65, + tooltip: "Resume video", + icon: const Icon(IconsaxPlusBold.play), + ), + ), + ); + } + + Widget topButtons(BuildContext context) { + final currentItem = ref.watch(playBackModel.select((value) => value?.item)); + final maxHeight = 150.clamp(50, (MediaQuery.sizeOf(context).height * 0.25).clamp(51, double.maxFinite)).toDouble(); + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withValues(alpha: 0.8), + Colors.black.withValues(alpha: 0), + ], + )), + child: Padding( + padding: MediaQuery.paddingOf(context).copyWith(bottom: 0, top: 0), + child: Container( + alignment: Alignment.topCenter, + child: Column( + children: [ + const Align( + alignment: Alignment.topRight, + child: DefaultTitleBar(), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + spacing: 16, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (currentItem != null) + Expanded( + child: Row( + children: [ + Flexible( + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: maxHeight, + ), + child: ItemLogo( + item: currentItem, + imageAlignment: Alignment.topLeft, + textStyle: Theme.of(context).textTheme.headlineLarge, + ), + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } + + Widget bottomButtons(BuildContext context) { + return Consumer(builder: (context, ref, child) { + final mediaPlayback = ref.watch(mediaPlaybackProvider); + final bitRateOptions = ref.watch(playBackModel.select((value) => value?.bitRateOptions)); + return Container( + key: _bottomControlsKey, // Add key to measure height + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [ + Colors.black.withValues(alpha: 0.8), + Colors.black.withValues(alpha: 0), + ], + )), + child: Padding( + padding: MediaQuery.paddingOf(context).add( + const EdgeInsets.symmetric(horizontal: 16).copyWith(bottom: 12), + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: progressBar(mediaPlayback), + ), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + flex: 2, + child: Row( + children: [ + _wrapNav( + 'options', + IconButton( + onPressed: () => showVideoPlayerOptions(context, () => minimizePlayer(context)), + icon: const Icon(IconsaxPlusLinear.more)), + ), + if (AdaptiveLayout.layoutOf(context) == ViewSize.tablet) ...[ + _wrapNav( + 'subtitle', + IconButton( + onPressed: () => showSubSelection(context), + icon: const Icon(IconsaxPlusLinear.subtitle), + ), + ), + _wrapNav( + 'audio', + IconButton( + onPressed: () => showAudioSelection(context), + icon: const Icon(IconsaxPlusLinear.audio_square), + ), + ), + ], + if (AdaptiveLayout.layoutOf(context) == ViewSize.television) ...[ + Flexible( + child: _wrapNav( + 'subtitle', + ElevatedButton.icon( + onPressed: () => showSubSelection(context), + icon: const Icon(IconsaxPlusLinear.subtitle), + label: Text( + ref.watch(playBackModel.select((value) { + final language = value?.mediaStreams?.currentSubStream?.language; + return language?.isEmpty == true ? context.localized.off : language; + }))?.capitalize() ?? + "", + maxLines: 1, + ), + ), + ), + ), + Flexible( + child: _wrapNav( + 'audio', + ElevatedButton.icon( + onPressed: () => showAudioSelection(context), + icon: const Icon(IconsaxPlusLinear.audio_square), + label: Text( + ref.watch(playBackModel.select((value) { + final language = value?.mediaStreams?.currentAudioStream?.language; + return language?.isEmpty == true ? context.localized.off : language; + }))?.capitalize() ?? + "", + maxLines: 1, + ), + ), + ), + ) + ], + ].addInBetween(const SizedBox( + width: 4, + )), + ), + ), + previousButton, + seekBackwardButton(ref), + _wrapNav( + 'playPause', + // Wrap the IconButton in a Consumer so the Icon rebuilds + // specifically when the playing state changes. + Consumer(builder: (context, ref, child) { + final playing = ref.watch(mediaPlaybackProvider.select((m) => m.playing)); + return IconButton.filledTonal( + iconSize: 38, + onPressed: doPlayPause, + icon: Icon( + playing ? IconsaxPlusBold.pause : IconsaxPlusBold.play, + ), + ); + }), + ), + seekForwardButton(ref), + nextVideoButton, + Flexible( + flex: 2, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + // Removed the pointer close button to avoid showing a cross in the corner. + const Spacer(), + if (AdaptiveLayout.viewSizeOf(context) >= ViewSize.tablet && + ref.read(videoPlayerProvider).hasPlayer) ...{ + if (bitRateOptions?.isNotEmpty == true) + Tooltip( + message: context.localized.qualityOptionsTitle, + child: _wrapNav( + 'quality', + IconButton( + onPressed: () =>openQualityOptions(context), + icon: const Icon(IconsaxPlusLinear.speedometer), + ), + ), + ), + }, + if (initInputDevice == InputDevice.pointer && + AdaptiveLayout.viewSizeOf(context) > ViewSize.phone) ...[ + VideoVolumeSlider( + onChanged: () => resetTimer(), + ), + const FullScreenButton(), + ] + ].addInBetween(const SizedBox(width: 8)), + ), + ), + ].addInBetween(const SizedBox(width: 6)), + ), + ], + ), + ), + ); + }); + } + + Widget progressBar(MediaPlaybackModel mediaPlayback) { + return Consumer( + builder: (context, ref, child) { + final playbackModel = ref.watch(playBackModel); + final item = playbackModel?.item; + final List details = [ null + ]; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + children: [ + Expanded( + child: Text( + details.nonNulls.join(' - '), + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + maxLines: 2, + ), + ), + const Spacer(), + if (playbackModel != null) + InkWell( + onTap: () => showVideoPlaybackInformation(context), + child: Card( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: Text( + playbackModel.label(context) ?? "", + ), + ), + ), + ), + if (item != null) ...{ + Card( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: Text( + item.streamModel?.mediaInfoTag ?? "", + ), + ), + ), + }, + ].addPadding(const EdgeInsets.symmetric(horizontal: 4)), + ), + const SizedBox(height: 4), + SizedBox( + height: 25, + child: VideoProgressBar( + wasPlayingChanged: (value) => wasPlaying = value, + wasPlaying: wasPlaying, + duration: mediaPlayback.duration, + position: mediaPlayback.position, + buffer: mediaPlayback.buffer, + buffering: mediaPlayback.buffering, + timerReset: () => timer.reset(), + onPositionChanged: (position) => ref.read(videoPlayerProvider).seek(position), + ), + ), + const SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + mediaPlayback.position.readAbleDuration, + style: Theme.of(context).textTheme.bodyMedium, + ), + Text( + "-${(mediaPlayback.duration - mediaPlayback.position).readAbleDuration}", + style: Theme.of(context).textTheme.bodyMedium, + ), + ], + ), + ], + ); + }, + ); + } + + Widget get previousButton { + return Consumer( + builder: (context, ref, child) { + final previousVideo = ref.watch(playBackModel.select((value) => value?.previousVideo)); + return Tooltip( + message: previousVideo?.detailedName(context) ?? "", + textAlign: TextAlign.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surface.withValues(alpha: 0.95), + ), + textStyle: Theme.of(context).textTheme.labelLarge, + child: _wrapNav( + 'previous', + IconButton( + onPressed: loadPreviousVideo(ref, video: previousVideo), + iconSize: 30, + icon: const Icon( + IconsaxPlusLinear.backward, + ), + ), + ), + ); + }, + ); + } + + Function()? loadPreviousVideo(WidgetRef ref, {ItemBaseModel? video}) { + final previousVideo = video ?? ref.read(playBackModel.select((value) => value?.previousVideo)); + final buffering = ref.read(mediaPlaybackProvider.select((value) => value.buffering)); + return previousVideo != null && !buffering ? () => ref.read(playbackModelHelper).loadNewVideo(previousVideo) : null; + } + + Widget get nextVideoButton { + return Consumer( + builder: (context, ref, child) { + final nextVideo = ref.watch(playBackModel.select((value) => value?.nextVideo)); + return Tooltip( + message: nextVideo?.detailedName(context) ?? "", + textAlign: TextAlign.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surface.withValues(alpha: 0.95), + ), + textStyle: Theme.of(context).textTheme.labelLarge, + child: _wrapNav( + 'next', + IconButton( + onPressed: loadNextVideo(ref, video: nextVideo), + iconSize: 30, + icon: const Icon( + IconsaxPlusLinear.forward, + ), + ), + ), + ); + }, + ); + } + + Function()? loadNextVideo(WidgetRef ref, {ItemBaseModel? video}) { + final nextVideo = video ?? ref.read(playBackModel.select((value) => value?.nextVideo)); + final buffering = ref.read(mediaPlaybackProvider.select((value) => value.buffering)); + return nextVideo != null && !buffering ? () => ref.read(playbackModelHelper).loadNewVideo(nextVideo) : null; + } + + Widget seekBackwardButton(WidgetRef ref) { + final backwardSpeed = 10; + //ref.read(userProvider.select((value) => value?.userSettings?.skipBackDuration.inSeconds ?? 30)); + return _wrapNav( + 'seekBack', + IconButton( + onPressed: () => seekBack(ref, seconds: backwardSpeed), + tooltip: "-$backwardSpeed", + iconSize: 40, + icon: Stack( + alignment: Alignment.center, + children: [ + const Icon( + IconsaxPlusBroken.refresh, + size: 45, + ), + Transform.translate( + offset: const Offset(0, 1), + child: Text( + "-$backwardSpeed", + style: Theme.of(context).textTheme.bodySmall, + ), + ), + ], + ), + ), + ); + } + + Widget seekForwardButton(WidgetRef ref) { + final forwardSpeed = + ref.read(userProvider.select((value) => value?.userSettings?.skipForwardDuration.inSeconds ?? 30)); + return _wrapNav( + 'seekForward', + IconButton( + onPressed: () => seekForward(ref, seconds: forwardSpeed), + tooltip: forwardSpeed.toString(), + iconSize: 40, + icon: Stack( + alignment: Alignment.center, + children: [ + Transform.flip( + flipX: true, + child: const Icon( + IconsaxPlusBroken.refresh, + size: 45, + ), + ), + Transform.translate( + offset: const Offset(0, 1), + child: Text( + forwardSpeed.toString(), + style: Theme.of(context).textTheme.bodySmall, + ), + ), + ], + ), + ), + ); + } + + void skipToSegmentEnd(MediaSegment? mediaSegments) { + final end = mediaSegments?.end; + if (end != null) { + resetTimer(); + ref.read(videoPlayerProvider).seek(end); + } + } + + void seekBack(WidgetRef ref, {int seconds = 15}) { + final mediaPlayback = ref.read(mediaPlaybackProvider); + resetTimer(); + final newPosition = (mediaPlayback.position.inSeconds - seconds).clamp(0, mediaPlayback.duration.inSeconds); + ref.read(videoPlayerProvider).seek(Duration(seconds: newPosition)); + } + + void seekForward(WidgetRef ref, {int seconds = 15}) { + final mediaPlayback = ref.read(mediaPlaybackProvider); + resetTimer(); + final newPosition = (mediaPlayback.position.inSeconds + seconds).clamp(0, mediaPlayback.duration.inSeconds); + ref.read(videoPlayerProvider).seek(Duration(seconds: newPosition)); + } + + void toggleOverlay({bool? value}) { + if (showOverlay == (value ?? !showOverlay)) return; + setState(() => showOverlay = (value ?? !showOverlay)); + resetTimer(); + + // When overlay becomes visible, set focus to the controls so arrow keys + // navigate the control buttons. + if (showOverlay) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) _controlsFocusNode.requestFocus(); + }); + } + if (showOverlay) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted && _navOrder.isNotEmpty) { + final id = _navOrder[_navIndex]; + _navFocusNodes[id]?.requestFocus(); + } + }); + } + + final desiredMode = showOverlay ? SystemUiMode.edgeToEdge : SystemUiMode.immersiveSticky; + + if (_currentSystemUiMode != desiredMode) { + _currentSystemUiMode = desiredMode; + SystemChrome.setEnabledSystemUIMode(desiredMode, overlays: []); + } + + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarColor: Colors.transparent, + statusBarIconBrightness: Brightness.light, + systemNavigationBarDividerColor: Colors.transparent, + )); + } + + void minimizePlayer(BuildContext context) { + clearOverlaySettings(); + ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(state: VideoPlayerState.minimized)); + Navigator.of(context).pop(); + } + + void resetTimer() => timer.reset(); + + Future closePlayer() async { + clearOverlaySettings(); + ref.read(videoPlayerProvider).stop(); + Navigator.of(context).pop(); + } + + Future clearOverlaySettings() async { + toggleOverlay(value: true); + if (initInputDevice != InputDevice.pointer) { + ScreenBrightness().resetApplicationScreenBrightness(); + } else { + disableFullScreen(); + } + + SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( + statusBarIconBrightness: ref.read(clientSettingsProvider.select((value) => value.statusBarBrightness(context))), + )); + + timer.cancel(); + } + + Future disableFullScreen() async { + resetTimer(); + fullScreenHelper.closeFullScreen(ref); + } + + void setVolume(PointerEvent event) { + if (event is PointerScrollEvent) { + if (event.scrollDelta.dy > 0) { + ref.read(videoPlayerSettingsProvider.notifier).steppedVolume(-5); + } else { + ref.read(videoPlayerSettingsProvider.notifier).steppedVolume(5); + } + } + } + + bool _tizenHardwareHandler(KeyEvent event) { + // Only handle on key down to avoid double triggers + if (event is! KeyDownEvent) return false; + final key = event.logicalKey; + + // Common media keys + if (key == LogicalKeyboardKey.mediaPlayPause || key == LogicalKeyboardKey.mediaPlay || key == LogicalKeyboardKey.mediaPause) { + // toggle play/pause + ref.read(videoPlayerProvider).playOrPause(); + _setActiveIndicator('Play/Pause'); + resetTimer(); + return true; + } + + // If overlay is visible, use D-pad to navigate controls + if (showOverlay) { + if (key == LogicalKeyboardKey.arrowLeft) { + _moveSelection(-1); + resetTimer(); + return true; + } + if (key == LogicalKeyboardKey.arrowRight) { + _moveSelection(1); + resetTimer(); + return true; + } + // if (key == LogicalKeyboardKey.arrowUp) { + // // Move up a few steps (best-effort grid movement) + // _moveSelection(-3); + // return true; + // } + // if (key == LogicalKeyboardKey.arrowDown) { + // _moveSelection(3); + // return true; + // } + // Activation keys + + if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter || key == LogicalKeyboardKey.space) { + //_activateSelection(); + //_setActiveIndicator('Activate'); + resetTimer(); + return true; + } + } + + // // Arrow keys -> seek indicator (when overlay not visible) + // if (key == LogicalKeyboardKey.arrowLeft || key == LogicalKeyboardKey.arrowRight) { + // _setActiveIndicator('Seek'); + // // do not swallow here; other handlers (seek indicator) will process the key + // return false; + // } + + // Up/Down -> volume (when overlay not visible) + if (key == LogicalKeyboardKey.arrowUp || key == LogicalKeyboardKey.arrowDown) { + // _setActiveIndicator('Volume'); + // do not swallow here; allow normal processing + toggleOverlay(value: true); + return false; + } + + return false; + } +} diff --git a/lib/screens/video_player/video_player.dart b/lib/screens/video_player/video_player.dart index c73f9586b..76ec15195 100644 --- a/lib/screens/video_player/video_player.dart +++ b/lib/screens/video_player/video_player.dart @@ -11,6 +11,8 @@ import 'package:fladder/providers/settings/video_player_settings_provider.dart'; import 'package:fladder/providers/video_player_provider.dart'; import 'package:fladder/screens/video_player/components/video_player_next_wrapper.dart'; import 'package:fladder/screens/video_player/video_player_controls.dart'; +import 'package:fladder/screens/video_player/tizen_video_player_controls.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; import 'package:fladder/util/adaptive_layout/adaptive_layout.dart'; import 'package:fladder/util/themes_data.dart'; import 'package:fladder/widgets/shared/back_intent_dpad.dart'; @@ -113,7 +115,7 @@ class _VideoPlayerState extends ConsumerState with WidgetsBindingOb : videoFit, ), ), - controls: const DesktopControls(), + controls: isTizen ? const TVControls() : const DesktopControls(), overlays: [ if (errorPlaying) const _VideoErrorWidget(), ], From 09a448064b4c0425666f57c9ab51902bc86e5152 Mon Sep 17 00:00:00 2001 From: popdollar Date: Fri, 26 Dec 2025 18:07:26 +0100 Subject: [PATCH 05/13] feat: created tizen transcode profile there was an issue where there was added an extra / in the transcode url. not sure why. I've removed it in a imo not so great way, but is, for now, fixes the issue --- lib/profiles/default_profile.dart | 77 ++++++++++++++++++------------- lib/profiles/tizen_profile.dart | 42 +++++++++++++++++ pubspec.yaml | 2 +- tizen/tizen-manifest.xml | 2 + 4 files changed, 90 insertions(+), 33 deletions(-) create mode 100644 lib/profiles/tizen_profile.dart diff --git a/lib/profiles/default_profile.dart b/lib/profiles/default_profile.dart index f33505d68..139e2baa9 100644 --- a/lib/profiles/default_profile.dart +++ b/lib/profiles/default_profile.dart @@ -1,44 +1,57 @@ +import 'dart:developer'; + import 'package:flutter/foundation.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; import 'package:fladder/models/settings/video_player_settings.dart'; +import 'package:fladder/profiles/tizen_profile.dart'; import 'package:fladder/profiles/web_profile.dart'; import 'package:fladder/providers/video_player_provider.dart'; final videoProfileProvider = StateProvider.autoDispose((ref) => defaultProfile(ref.read(videoPlayerProvider.select((value) => value.backend)) ?? PlayerOptions.platformDefaults)); -DeviceProfile defaultProfile(PlayerOptions player) => kIsWeb - ? webProfile - : const DeviceProfile( - maxStreamingBitrate: 120000000, - maxStaticBitrate: 120000000, - musicStreamingTranscodingBitrate: 384000, - directPlayProfiles: [ - DirectPlayProfile( - type: DlnaProfileType.video, - ), - DirectPlayProfile( - type: DlnaProfileType.audio, - ) - ], - transcodingProfiles: [ - TranscodingProfile( - audioCodec: 'aac,mp3,mp2', - container: 'ts', - maxAudioChannels: '2', - protocol: MediaStreamProtocol.hls, - type: DlnaProfileType.video, - videoCodec: 'h264', - ), - ], - containerProfiles: [], - subtitleProfiles: [ - SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.$external), - SubtitleProfile(format: 'ass', method: SubtitleDeliveryMethod.$external), - SubtitleProfile(format: 'ssa', method: SubtitleDeliveryMethod.$external), - SubtitleProfile(format: 'pgssub', method: SubtitleDeliveryMethod.$external), - ], - ); +DeviceProfile defaultProfile(PlayerOptions player) { + if (kIsWeb) { + return webProfile; + } + + // Use Tizen-specific profile for Tizen devices + if (isTizen) { + return tizenProfile; + } + + return const DeviceProfile( + maxStreamingBitrate: 120000000, + maxStaticBitrate: 120000000, + musicStreamingTranscodingBitrate: 384000, + directPlayProfiles: [ + DirectPlayProfile( + type: DlnaProfileType.video, + ), + DirectPlayProfile( + type: DlnaProfileType.audio, + ) + ], + transcodingProfiles: [ + TranscodingProfile( + audioCodec: 'aac,mp3,mp2', + container: 'ts', + maxAudioChannels: '2', + protocol: MediaStreamProtocol.hls, + type: DlnaProfileType.video, + videoCodec: 'h264', + ), + ], + containerProfiles: [], + subtitleProfiles: [ + SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'ass', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'ssa', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'pgssub', method: SubtitleDeliveryMethod.$external), + ], + ); +} diff --git a/lib/profiles/tizen_profile.dart b/lib/profiles/tizen_profile.dart new file mode 100644 index 000000000..deb46f03d --- /dev/null +++ b/lib/profiles/tizen_profile.dart @@ -0,0 +1,42 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; + +/// Device profile for Tizen TV devices +/// +/// Based on the default profile but with DTS audio codec excluded +/// to force transcoding of DTS audio to AAC +const DeviceProfile tizenProfile = DeviceProfile( + maxStreamingBitrate: 120000000, + maxStaticBitrate: 120000000, + musicStreamingTranscodingBitrate: 384000, + directPlayProfiles: [ + // Video: Allow any container with H.264 and supported audio (excluding DTS) + // Supports multiple audio channels including Dolby 5.1 and Atmos + DirectPlayProfile( + type: DlnaProfileType.video, + videoCodec: 'h264,hevc,vp8,vp9,av1', + audioCodec: 'aac,mp3,flac,wav,vorbis,opus,eac3,ac3,truehd', + ), + // Audio only + DirectPlayProfile(container: 'mp3', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'aac', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'm4a', audioCodec: 'aac', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'm4b', audioCodec: 'aac', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'flac', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'wav', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'ogg', type: DlnaProfileType.audio), + ], + transcodingProfiles: [ + TranscodingProfile( + audioCodec: 'aac,mp3,mp2', + container: 'ts', + protocol: MediaStreamProtocol.hls, + type: DlnaProfileType.video, + videoCodec: 'h264', + ), + ], + containerProfiles: [], + subtitleProfiles: [ + SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.embed), + SubtitleProfile(format: 'srt', method: SubtitleDeliveryMethod.embed), + ], +); diff --git a/pubspec.yaml b/pubspec.yaml index 34c798df5..c39094d5c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -125,7 +125,7 @@ dependencies: drift_db_viewer: ^2.1.0 # Tizen-specific plhttp://tizen.org/privilege/tv.display http://tizen.org/privilege/tv.window http://tizen.org/privilege/tv.inputdevice + http://tizen.org/privilege/network.get + http://tizen.org/privilege/appmanager.launch From ef0f09cc01267ce185797fbd55e1961ed9d329a6 Mon Sep 17 00:00:00 2001 From: popdollar Date: Sat, 27 Dec 2025 16:40:25 +0100 Subject: [PATCH 06/13] fix: small fixes to ui not behaving correctly with tizen small other fixes and clean up of code --- lib/main.dart | 26 +++- lib/profiles/default_profile.dart | 1 - lib/profiles/tizen_profile.dart | 12 +- .../tizen_video_player_controls.dart | 122 +++++++----------- lib/util/resolution_checker.dart | 14 +- lib/widgets/shared/pull_to_refresh.dart | 1 + lib/wrappers/players/tizen_player.dart | 15 ++- pubspec.lock | 8 ++ pubspec.yaml | 1 + 9 files changed, 111 insertions(+), 89 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 916629f14..60afe0fab 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -307,12 +307,32 @@ class _MainState extends ConsumerState
with WindowListener, WidgetsBinding final scrollBehaviour = const MaterialScrollBehavior(); return DynamicColorBuilder( builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) { - final lightTheme = themeColor == null + final rawLightTheme = themeColor == null ? FladderTheme.theme(lightDynamic ?? FladderTheme.defaultScheme(Brightness.light), schemeVariant) : FladderTheme.theme(themeColor.schemeLight, schemeVariant); - final darkTheme = (themeColor == null + final rawDarkTheme = (themeColor == null ? FladderTheme.theme(darkDynamic ?? FladderTheme.defaultScheme(Brightness.dark), schemeVariant) : FladderTheme.theme(themeColor.schemeDark, schemeVariant)); + final lightTheme = !isTizen + ? rawLightTheme + : rawLightTheme.copyWith( + pageTransitionsTheme: PageTransitionsTheme( + builders: { + ...rawLightTheme.pageTransitionsTheme.builders, + TargetPlatform.linux: const FadeUpwardsPageTransitionsBuilder(), + }, + ), + ); + final darkTheme = !isTizen + ? rawDarkTheme + : rawDarkTheme.copyWith( + pageTransitionsTheme: PageTransitionsTheme( + builders: { + ...rawDarkTheme.pageTransitionsTheme.builders, + TargetPlatform.linux: const FadeUpwardsPageTransitionsBuilder(), + }, + ), + ); final amoledOverwrite = amoledBlack ? Colors.black : null; return ThemesData( light: lightTheme, @@ -369,4 +389,4 @@ class _MainState extends ConsumerState
with WindowListener, WidgetsBinding } } -final currentTitleProvider = StateProvider((ref) => "Fladder"); +final currentTitleProvider = StateProvider((ref) => "Fladder"); \ No newline at end of file diff --git a/lib/profiles/default_profile.dart b/lib/profiles/default_profile.dart index 139e2baa9..ab3e9de89 100644 --- a/lib/profiles/default_profile.dart +++ b/lib/profiles/default_profile.dart @@ -19,7 +19,6 @@ DeviceProfile defaultProfile(PlayerOptions player) { return webProfile; } - // Use Tizen-specific profile for Tizen devices if (isTizen) { return tizenProfile; } diff --git a/lib/profiles/tizen_profile.dart b/lib/profiles/tizen_profile.dart index deb46f03d..94b938751 100644 --- a/lib/profiles/tizen_profile.dart +++ b/lib/profiles/tizen_profile.dart @@ -14,7 +14,7 @@ const DeviceProfile tizenProfile = DeviceProfile( DirectPlayProfile( type: DlnaProfileType.video, videoCodec: 'h264,hevc,vp8,vp9,av1', - audioCodec: 'aac,mp3,flac,wav,vorbis,opus,eac3,ac3,truehd', + audioCodec: 'aac,mp3,flac,wav,vorbis,opus,eac3,ac3,truehd', ), // Audio only DirectPlayProfile(container: 'mp3', type: DlnaProfileType.audio), @@ -35,8 +35,10 @@ const DeviceProfile tizenProfile = DeviceProfile( ), ], containerProfiles: [], - subtitleProfiles: [ - SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.embed), - SubtitleProfile(format: 'srt', method: SubtitleDeliveryMethod.embed), - ], + subtitleProfiles: [ + SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'ass', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'ssa', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'pgssub', method: SubtitleDeliveryMethod.$external), + ], ); diff --git a/lib/screens/video_player/tizen_video_player_controls.dart b/lib/screens/video_player/tizen_video_player_controls.dart index 0795eab87..93428850c 100644 --- a/lib/screens/video_player/tizen_video_player_controls.dart +++ b/lib/screens/video_player/tizen_video_player_controls.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -14,7 +13,6 @@ import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/models/items/media_segments_model.dart'; import 'package:fladder/models/media_playback_model.dart'; import 'package:fladder/models/playback/playback_model.dart'; -import 'package:fladder/models/settings/video_player_settings.dart'; import 'package:fladder/providers/settings/client_settings_provider.dart'; import 'package:fladder/providers/settings/video_player_settings_provider.dart'; import 'package:fladder/providers/user_provider.dart'; @@ -25,10 +23,7 @@ import 'package:fladder/screens/video_player/components/video_playback_informati import 'package:fladder/screens/video_player/components/video_player_controls_extras.dart'; import 'package:fladder/screens/video_player/components/video_player_options_sheet.dart'; import 'package:fladder/screens/video_player/components/video_player_quality_controls.dart'; -// import 'package:fladder/screens/video_player/components/video_player_screenshot_indicator.dart'; import 'package:fladder/screens/video_player/components/video_player_seek_indicator.dart'; -// import 'package:fladder/screens/video_player/components/video_player_speed_indicator.dart'; -// import 'package:fladder/screens/video_player/components/video_player_volume_indicator.dart'; import 'package:fladder/screens/video_player/components/video_progress_bar.dart'; import 'package:fladder/screens/video_player/components/video_volume_slider.dart'; import 'package:fladder/util/adaptive_layout/adaptive_layout.dart'; @@ -65,11 +60,10 @@ class _TVControlsState extends ConsumerState { SystemUiMode? _currentSystemUiMode; String? activeIndicator; RestartableTimer? _activeIndicatorTimer; - final FocusNode _controlsFocusNode = FocusNode(); - // Navigation for remote (D-pad) - list is built dynamically in build() - List _navOrder = []; - int _navIndex = 0; - final Map _navFocusNodes = {}; + final FocusNode controlsFocusNode = FocusNode(); + List navOrder = []; + int navIndex = 0; + final Map navFocusNodes = {}; late final double topPadding = MediaQuery.of(context).viewPadding.top; late final double bottomPadding = MediaQuery.of(context).viewPadding.bottom; @@ -78,9 +72,6 @@ class _TVControlsState extends ConsumerState { void initState() { super.initState(); timer.reset(); - // Register a small hardware handler to catch remote media keys that may not be - // present in the configured hotkey map (some remotes send LogicalKeyboardKey.mediaPlayPause, - // etc.). This ensures Play/Pause on Samsung remotes is handled. HardwareKeyboard.instance.addHandler(_tizenHardwareHandler); } @@ -97,29 +88,24 @@ class _TVControlsState extends ConsumerState { } Widget _wrapNav(String id, Widget child) { - // Make this control focusable and handle activation via D-pad/select. - final node = _navFocusNodes.putIfAbsent(id, () => FocusNode()); + final node = navFocusNodes.putIfAbsent(id, () => FocusNode()); return FocusableActionDetector( focusNode: node, enabled: showOverlay, shortcuts: { - // Map remote 'select' to activation. Avoid mapping Enter/Space here - // to prevent double-activation (Enter/Space are handled by - // individual buttons which would otherwise be invoked twice). - //LogicalKeySet(LogicalKeyboardKey.select): ActivateIntent(), }, actions: >{ ActivateIntent: CallbackAction(onInvoke: (intent) { - _activateSelection(); + activateSelection(); return null; }), }, onFocusChange: (hasFocus) { if (hasFocus) { - final idx = _navOrder.indexOf(id); + final idx = navOrder.indexOf(id); if (idx >= 0) { setState(() { - _navIndex = idx; + navIndex = idx; _setActiveIndicator(id); }); } @@ -131,7 +117,7 @@ class _TVControlsState extends ConsumerState { return Container( decoration: focused ? BoxDecoration( - border: Border.all(color: Colors.white.withOpacity(0.9), width: 2), + border: Border.all(color: Colors.white.withValues(alpha: 0.9), width: 2), borderRadius: BorderRadius.circular(8), ) : null, @@ -142,14 +128,9 @@ class _TVControlsState extends ConsumerState { ); } - void _ensureNavOrder() { - // Build nav order based on currently visible controls. - // This is a best-effort list; presence of items depends on layout and input device. + void ensureNavOrder() { final List order = []; - // Bottom control row (most important controls) - // Options / extra order.add('options'); - // Subtitle / audio (may be present or not; we'll keep keys even if widgets not shown) order.add('subtitle'); order.add('audio'); order.add('previous'); @@ -159,40 +140,38 @@ class _TVControlsState extends ConsumerState { order.add('next'); order.add('quality'); - _navOrder = order; - if (_navIndex >= _navOrder.length) _navIndex = 0; + navOrder = order; + if (navIndex >= navOrder.length) navIndex = 0; - // Ensure focus nodes exist for each nav id and clean up removed ones - final existing = Set.from(_navFocusNodes.keys); - for (final id in _navOrder) { + final existing = Set.from(navFocusNodes.keys); + for (final id in navOrder) { existing.remove(id); - _navFocusNodes.putIfAbsent(id, () => FocusNode()); + navFocusNodes.putIfAbsent(id, () => FocusNode()); } - // Dispose any nodes that are no longer used + for (final id in existing) { - _navFocusNodes[id]?.dispose(); - _navFocusNodes.remove(id); + navFocusNodes[id]?.dispose(); + navFocusNodes.remove(id); } } void _moveSelection(int delta) { - if (_navOrder.isEmpty) return; + if (navOrder.isEmpty) return; setState(() { - _navIndex = (_navIndex + delta) % _navOrder.length; - if (_navIndex < 0) _navIndex += _navOrder.length; - _setActiveIndicator(_navOrder[_navIndex]); + navIndex = (navIndex + delta) % navOrder.length; + if (navIndex < 0) navIndex += navOrder.length; + _setActiveIndicator(navOrder[navIndex]); }); - // Ensure the focused node follows our selection index - final id = _navOrder[_navIndex]; + + final id = navOrder[navIndex]; WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted) _navFocusNodes[id]?.requestFocus(); + if (mounted) navFocusNodes[id]?.requestFocus(); }); } - void _activateSelection() { - if (_navOrder.isEmpty) return; - final id = _navOrder[_navIndex]; - // Map ids to actions + void activateSelection() { + if (navOrder.isEmpty) return; + final id = navOrder[navIndex]; switch (id) { case 'options': showVideoPlayerOptions(context, () => minimizePlayer(context)); @@ -240,8 +219,8 @@ class _TVControlsState extends ConsumerState { @override void dispose() { HardwareKeyboard.instance.removeHandler(_tizenHardwareHandler); - _controlsFocusNode.dispose(); - for (final node in _navFocusNodes.values) { + controlsFocusNode.dispose(); + for (final node in navFocusNodes.values) { node.dispose(); } super.dispose(); @@ -250,32 +229,27 @@ class _TVControlsState extends ConsumerState { @override Widget build(BuildContext context) { // Build nav order for remote navigation each build so it reflects visible controls - _ensureNavOrder(); + ensureNavOrder(); final mediaSegments = ref.watch(playBackModel.select((value) => value?.mediaSegments)); final player = ref.watch(videoPlayerProvider); final subtitleWidget = player.subtitleWidget(showOverlay, controlsKey: _bottomControlsKey); - final currentShortcuts = ref.watch(videoPlayerSettingsProvider.select((value) => value.currentShortcuts)); - // When the overlay (controls) is visible we want arrow left/right to navigate UI elements - // instead of seeking. Filter out seek hotkeys while overlay is visible so framework focus - // navigation can handle them. When overlay is hidden, keep seek hotkeys so remote arrows - // control seeking. - final effectiveKeyMap = showOverlay ? Map.of(currentShortcuts) : currentShortcuts; - if (showOverlay) { - effectiveKeyMap.remove(VideoHotKeys.seekForward); - effectiveKeyMap.remove(VideoHotKeys.seekBack); - - - } - effectiveKeyMap.remove(VideoHotKeys.playPause); - effectiveKeyMap.remove(VideoHotKeys.exit); + // final currentShortcuts = ref.watch(videoPlayerSettingsProvider.select((value) => value.currentShortcuts)); + // final effectiveKeyMap = showOverlay ? Map.of(currentShortcuts) : currentShortcuts; + + // if (showOverlay) { + // effectiveKeyMap.remove(VideoHotKeys.seekForward); + // effectiveKeyMap.remove(VideoHotKeys.seekBack); + // } + + //effectiveKeyMap.remove(VideoHotKeys.playPause); + //effectiveKeyMap.remove(VideoHotKeys.exit); return Listener( onPointerSignal: setVolume, child: InputHandler( autoFocus: true, listenRawKeyboard: true, - keyMap: effectiveKeyMap, - //keyMapResult: _onKey, + //keyMap: effectiveKeyMap, child: PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { @@ -299,7 +273,7 @@ class _TVControlsState extends ConsumerState { child: FocusTraversalGroup( policy: OrderedTraversalPolicy(), child: Focus( - focusNode: _controlsFocusNode, + focusNode: controlsFocusNode, child: bottomButtons(context), ), ), @@ -824,14 +798,14 @@ class _TVControlsState extends ConsumerState { // navigate the control buttons. if (showOverlay) { WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted) _controlsFocusNode.requestFocus(); + if (mounted) controlsFocusNode.requestFocus(); }); } if (showOverlay) { WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted && _navOrder.isNotEmpty) { - final id = _navOrder[_navIndex]; - _navFocusNodes[id]?.requestFocus(); + if (mounted && navOrder.isNotEmpty) { + final id = navOrder[navIndex]; + navFocusNodes[id]?.requestFocus(); } }); } @@ -933,7 +907,7 @@ class _TVControlsState extends ConsumerState { // Activation keys if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter || key == LogicalKeyboardKey.space) { - //_activateSelection(); + //activateSelection(); //_setActiveIndicator('Activate'); resetTimer(); return true; diff --git a/lib/util/resolution_checker.dart b/lib/util/resolution_checker.dart index a13c11080..b7d88dfed 100644 --- a/lib/util/resolution_checker.dart +++ b/lib/util/resolution_checker.dart @@ -1,6 +1,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:device_info_plus_tizen/device_info_plus_tizen.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:screen_retriever/screen_retriever.dart'; @@ -20,12 +22,14 @@ class _ResolutionCheckerState extends ConsumerState { Size? lastResolution; Timer? _timer; + + @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((value) async { if (ref.read(argumentsStateProvider).htpcMode) { - lastResolution = (await screenRetriever.getPrimaryDisplay()).size; + lastResolution = isTizen ? await getTizenResolution() : (await screenRetriever.getPrimaryDisplay()).size; _timer = Timer.periodic(const Duration(seconds: 2), (timer) => checkResolution()); } }); @@ -33,7 +37,7 @@ class _ResolutionCheckerState extends ConsumerState { Future checkResolution() async { if (!mounted) return; - final newResolution = (await screenRetriever.getPrimaryDisplay()).size; + final newResolution = isTizen ? await getTizenResolution() : (await screenRetriever.getPrimaryDisplay()).size; if (lastResolution != newResolution) { lastResolution = newResolution; shouldSetResolution(); @@ -50,6 +54,12 @@ class _ResolutionCheckerState extends ConsumerState { } } + Future getTizenResolution() async { + final DeviceInfoPluginTizen deviceInfoPlugin = DeviceInfoPluginTizen(); + final tizenInfo = await deviceInfoPlugin.tizenInfo; + return Size(tizenInfo.screenWidth.toDouble(), tizenInfo.screenHeight.toDouble()); + } + @override void dispose() { _timer?.cancel(); diff --git a/lib/widgets/shared/pull_to_refresh.dart b/lib/widgets/shared/pull_to_refresh.dart index 2cf919d12..8b5f35b95 100644 --- a/lib/widgets/shared/pull_to_refresh.dart +++ b/lib/widgets/shared/pull_to_refresh.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/util/refresh_state.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; class PullToRefresh extends ConsumerStatefulWidget { final GlobalKey? refreshKey; diff --git a/lib/wrappers/players/tizen_player.dart b/lib/wrappers/players/tizen_player.dart index 570349daa..8d91bfd0b 100644 --- a/lib/wrappers/players/tizen_player.dart +++ b/lib/wrappers/players/tizen_player.dart @@ -133,7 +133,7 @@ class TizenPlayer extends BasePlayer { _controller?.play(); // refresh captions return wanted.index; } - + // Internal subtitle _externalSubEnabled = false; @@ -154,7 +154,6 @@ class TizenPlayer extends BasePlayer { } } } -//_updateState(); return wanted.index; } @@ -191,7 +190,6 @@ class TizenPlayer extends BasePlayer { alignment: Alignment.bottomCenter, children: [ VideoPlayer(_controller!), - //ClosedCaption(), GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { @@ -263,11 +261,13 @@ class _TizenSubtitlesState extends ConsumerState<_TizenSubtitles> { String subtitle = ''; if (widget.useExternal && widget.externalSubtitleController != null) { - subtitle = widget.externalSubtitleController!.durationSearch(position)?.data.trim() ?? ''; + subtitle = widget.externalSubtitleController?.durationSearch(position)?.data.trim() ?? ''; } else if (!widget.useExternal) { subtitle = widget.controller.value.caption.text.trim(); } + subtitle = _sanitizeSubtitle(subtitle); + if (subtitle != _lastCaption) { setState(() { _lastCaption = subtitle; @@ -276,7 +276,14 @@ class _TizenSubtitlesState extends ConsumerState<_TizenSubtitles> { } } + String _sanitizeSubtitle(String subtitle) { + if (subtitle.isEmpty) return subtitle; + final fontTagRegex = RegExp(r']*>', caseSensitive: false); + final sanitized = subtitle.replaceAll(fontTagRegex, ''); + + return sanitized.trim(); + } @override Widget build(BuildContext context) { diff --git a/pubspec.lock b/pubspec.lock index d4decfc34..0ec2ae9db 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -473,6 +473,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" + device_info_plus_tizen: + dependency: "direct main" + description: + name: device_info_plus_tizen + sha256: "54cea0bb09f772e35cfabcf5f2920a8e615f98e6eecba9f102ea4a8762adad44" + url: "https://pub.dev" + source: hosted + version: "1.3.0" diffutil_dart: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c39094d5c..ef68dcd0d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -132,6 +132,7 @@ dependencies: wakelock_plus_tizen: ^2.0.0 webview_flutter_tizen: ^0.9.7 package_info_plus_tizen: ^1.0.5 + device_info_plus_tizen: ^1.3.0 flutter_tizen: ^0.2.7 sqflite: ^2.4.2 sqflite_tizen: ^0.1.3 From e35d4f0e5ddca5cb0971850d3cdf2270011b0831 Mon Sep 17 00:00:00 2001 From: popdollar Date: Sun, 28 Dec 2025 14:15:04 +0100 Subject: [PATCH 07/13] fix: fixed bug where videoplayer would crash when loading next video reused the videoWidget from lib_mkd, which is correctly setup and thereby fixed the issue. corrected other small things --- lib/profiles/default_profile.dart | 2 - .../tizen_video_player_controls.dart | 36 ++++++----- lib/wrappers/players/tizen_player.dart | 62 ++++++++++++------- 3 files changed, 59 insertions(+), 41 deletions(-) diff --git a/lib/profiles/default_profile.dart b/lib/profiles/default_profile.dart index ab3e9de89..93926a82e 100644 --- a/lib/profiles/default_profile.dart +++ b/lib/profiles/default_profile.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:flutter/foundation.dart'; import 'package:flutter_tizen/flutter_tizen.dart'; diff --git a/lib/screens/video_player/tizen_video_player_controls.dart b/lib/screens/video_player/tizen_video_player_controls.dart index 93428850c..7f0f98648 100644 --- a/lib/screens/video_player/tizen_video_player_controls.dart +++ b/lib/screens/video_player/tizen_video_player_controls.dart @@ -77,10 +77,12 @@ class _TVControlsState extends ConsumerState { void _setActiveIndicator(String value) { _activeIndicatorTimer?.cancel(); + if (!mounted) return; setState(() { activeIndicator = value; }); _activeIndicatorTimer = RestartableTimer(const Duration(seconds: 1), () { + if (!mounted) return; setState(() { activeIndicator = null; }); @@ -194,7 +196,6 @@ class _TVControlsState extends ConsumerState { doPlayPause(); break; case 'seekForward': - final forwardSpeed = ref.read(userProvider.select((value) => value?.userSettings?.skipForwardDuration.inSeconds ?? 30)); seekForward(ref, seconds: forwardSpeed); @@ -219,6 +220,7 @@ class _TVControlsState extends ConsumerState { @override void dispose() { HardwareKeyboard.instance.removeHandler(_tizenHardwareHandler); + _activeIndicatorTimer?.cancel(); controlsFocusNode.dispose(); for (final node in navFocusNodes.values) { node.dispose(); @@ -233,23 +235,12 @@ class _TVControlsState extends ConsumerState { final mediaSegments = ref.watch(playBackModel.select((value) => value?.mediaSegments)); final player = ref.watch(videoPlayerProvider); final subtitleWidget = player.subtitleWidget(showOverlay, controlsKey: _bottomControlsKey); - // final currentShortcuts = ref.watch(videoPlayerSettingsProvider.select((value) => value.currentShortcuts)); - // final effectiveKeyMap = showOverlay ? Map.of(currentShortcuts) : currentShortcuts; - - // if (showOverlay) { - // effectiveKeyMap.remove(VideoHotKeys.seekForward); - // effectiveKeyMap.remove(VideoHotKeys.seekBack); - // } - - //effectiveKeyMap.remove(VideoHotKeys.playPause); - //effectiveKeyMap.remove(VideoHotKeys.exit); return Listener( onPointerSignal: setVolume, child: InputHandler( autoFocus: true, listenRawKeyboard: true, - //keyMap: effectiveKeyMap, child: PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { @@ -790,8 +781,23 @@ class _TVControlsState extends ConsumerState { } void toggleOverlay({bool? value}) { - if (showOverlay == (value ?? !showOverlay)) return; - setState(() => showOverlay = (value ?? !showOverlay)); + final desiredState = value ?? !showOverlay; + if (showOverlay == desiredState) return; + + String? indicatorToActivate; + setState(() { + showOverlay = desiredState; + if (showOverlay) { + final playPauseIndex = navOrder.indexOf('playPause'); + if (playPauseIndex != -1) { + navIndex = playPauseIndex; + indicatorToActivate = 'playPause'; + } + } + }); + if (indicatorToActivate != null) { + _setActiveIndicator(indicatorToActivate!); + } resetTimer(); // When overlay becomes visible, set focus to the controls so arrow keys @@ -922,7 +928,7 @@ class _TVControlsState extends ConsumerState { // } // Up/Down -> volume (when overlay not visible) - if (key == LogicalKeyboardKey.arrowUp || key == LogicalKeyboardKey.arrowDown) { + if (key == LogicalKeyboardKey.arrowUp || key == LogicalKeyboardKey.arrowDown || key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter || key == LogicalKeyboardKey.space) { // _setActiveIndicator('Volume'); // do not swallow here; allow normal processing toggleOverlay(value: true); diff --git a/lib/wrappers/players/tizen_player.dart b/lib/wrappers/players/tizen_player.dart index 8d91bfd0b..701b0a026 100644 --- a/lib/wrappers/players/tizen_player.dart +++ b/lib/wrappers/players/tizen_player.dart @@ -180,29 +180,40 @@ class TizenPlayer extends BasePlayer { @override - Widget? videoWidget(Key key, BoxFit fit) { - if (_controller == null || !_controller!.value.isInitialized) return null; - - return Center( - child: AspectRatio( - aspectRatio: _controller!.value.aspectRatio, - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - VideoPlayer(_controller!), - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - _controller!.value.isPlaying - ? _controller!.pause() - : _controller!.play(); - }, - ), - ], - ), - ), - ); - } + Widget? videoWidget( + Key key, + BoxFit fit, + ) => + _controller == null + ? null + : Container( + key: key, + color: Colors.transparent, + child: LayoutBuilder( + builder: (context, constraints) => Stack( + fit: StackFit.expand, + children: [ + FittedBox( + fit: fit, + alignment: Alignment.center, + child: ValueListenableBuilder( + valueListenable: _controller!, + builder: (context, value, child) { + final aspectRatio = value.isInitialized ? value.aspectRatio : 1.77; + return SizedBox( + width: constraints.maxWidth, + child: AspectRatio( + aspectRatio: aspectRatio, + child: VideoPlayer(_controller!), + ), + ); + }, + ), + ), + ], + ), + ), + ); @override Widget? subtitles(bool showOverlay, {GlobalKey? controlsKey}) { @@ -256,11 +267,14 @@ class _TizenSubtitlesState extends ConsumerState<_TizenSubtitles> { } void _onControllerUpdate() { + if (!mounted) return; + if (widget.controller.value.isInitialized == false) return; + final position = widget.controller.value.position; String subtitle = ''; - if (widget.useExternal && widget.externalSubtitleController != null) { + if (widget.useExternal && widget.externalSubtitleController != null && widget.externalSubtitleController!.initialized) { subtitle = widget.externalSubtitleController?.durationSearch(position)?.data.trim() ?? ''; } else if (!widget.useExternal) { subtitle = widget.controller.value.caption.text.trim(); From 398d73927083fd7da970adc657435b202d9f5338 Mon Sep 17 00:00:00 2001 From: popdollar Date: Tue, 30 Dec 2025 13:58:59 +0100 Subject: [PATCH 08/13] fix: added a fix to scaling of tizen video_widget Added tizen_video_hole to be able to scale the video player independant of the UI scaling of the app. Also removed TrueHD from tizen_profile because only some TrueHD seem to be working --- lib/profiles/tizen_profile.dart | 22 +++- lib/util/resolution_checker.dart | 1 + lib/util/tizen_video_hole.dart | 176 +++++++++++++++++++++++++ lib/wrappers/players/tizen_player.dart | 4 +- 4 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 lib/util/tizen_video_hole.dart diff --git a/lib/profiles/tizen_profile.dart b/lib/profiles/tizen_profile.dart index 94b938751..69477af24 100644 --- a/lib/profiles/tizen_profile.dart +++ b/lib/profiles/tizen_profile.dart @@ -2,19 +2,18 @@ import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; /// Device profile for Tizen TV devices /// -/// Based on the default profile but with DTS audio codec excluded -/// to force transcoding of DTS audio to AAC +/// TV does not support DTS and only most TrueHD const DeviceProfile tizenProfile = DeviceProfile( maxStreamingBitrate: 120000000, maxStaticBitrate: 120000000, musicStreamingTranscodingBitrate: 384000, directPlayProfiles: [ - // Video: Allow any container with H.264 and supported audio (excluding DTS) + // Video: Allow any container with H.264 and supported audio (excluding DTS and most TrueHD (maybe need some system to try and then fall back)) // Supports multiple audio channels including Dolby 5.1 and Atmos DirectPlayProfile( type: DlnaProfileType.video, videoCodec: 'h264,hevc,vp8,vp9,av1', - audioCodec: 'aac,mp3,flac,wav,vorbis,opus,eac3,ac3,truehd', + audioCodec: 'aac,mp3,flac,wav,vorbis,opus,eac3,ac3', ), // Audio only DirectPlayProfile(container: 'mp3', type: DlnaProfileType.audio), @@ -25,13 +24,22 @@ const DeviceProfile tizenProfile = DeviceProfile( DirectPlayProfile(container: 'wav', type: DlnaProfileType.audio), DirectPlayProfile(container: 'ogg', type: DlnaProfileType.audio), ], + /// Transcoding Profiles transcodingProfiles: [ + // Video transcoding with E-AC-3 audio TranscodingProfile( - audioCodec: 'aac,mp3,mp2', - container: 'ts', - protocol: MediaStreamProtocol.hls, type: DlnaProfileType.video, + protocol: MediaStreamProtocol.hls, + container: 'ts', videoCodec: 'h264', + audioCodec: 'eac3,ac3,aac', // Transcode TrueHD/DTS to E-AC-3 + ), + // Optional: Audio-only transcoding + TranscodingProfile( + type: DlnaProfileType.audio, + protocol: MediaStreamProtocol.http, + container: 'mp4', + audioCodec: 'aac,eac3,ac3', ), ], containerProfiles: [], diff --git a/lib/util/resolution_checker.dart b/lib/util/resolution_checker.dart index b7d88dfed..dc2228c0e 100644 --- a/lib/util/resolution_checker.dart +++ b/lib/util/resolution_checker.dart @@ -57,6 +57,7 @@ class _ResolutionCheckerState extends ConsumerState { Future getTizenResolution() async { final DeviceInfoPluginTizen deviceInfoPlugin = DeviceInfoPluginTizen(); final tizenInfo = await deviceInfoPlugin.tizenInfo; + // this seem to return 1920x1080 even on 4K TVs :( return Size(tizenInfo.screenWidth.toDouble(), tizenInfo.screenHeight.toDouble()); } diff --git a/lib/util/tizen_video_hole.dart b/lib/util/tizen_video_hole.dart new file mode 100644 index 000000000..67562518a --- /dev/null +++ b/lib/util/tizen_video_hole.dart @@ -0,0 +1,176 @@ +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:video_player_videohole/video_player.dart'; +import 'package:video_player_videohole/video_player_platform_interface.dart'; + +/// This is a modified version of the VideoHole widget from the video_player package +/// It is used to create a hole in the video player to display the video on the Tizen TV +/// This is only used to have scaling of UI be independent of the Tizen Video Player +class TizenVideoHole extends StatefulWidget { + const TizenVideoHole(this.controller, {super.key}); + + final VideoPlayerController controller; + + @override + State createState() => _TizenVideoHoleState(); +} + +class _TizenVideoHoleState extends State { + final GlobalKey _videoBoxKey = GlobalKey(); + Rect _playerRect = Rect.zero; + late final VoidCallback _listener; + int _playerId = -1; + int? _lastGeometryPlayerId; + + @override + void initState() { + super.initState(); + + // Keep track of the platform player id. It becomes available after + // asynchronous initialization. + _playerId = widget.controller.playerId; + _listener = () { + _playerId = widget.controller.playerId; + }; + widget.controller.addListener(_listener); + + WidgetsBinding.instance.addPostFrameCallback(_afterFrameLayout); + } + + @override + void didUpdateWidget(TizenVideoHole oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.controller == widget.controller) { + return; + } + + oldWidget.controller.removeListener(_listener); + _playerId = widget.controller.playerId; + widget.controller.addListener(_listener); + _lastGeometryPlayerId = null; + _playerRect = Rect.zero; + } + + @override + void dispose() { + widget.controller.removeListener(_listener); + super.dispose(); + } + + void _afterFrameLayout(_) { + if (!mounted) { + return; + } + + if (widget.controller.value.isInitialized) { + final int playerId = _playerId; + final Rect currentRect = _getCurrentRect(); + final bool playerChanged = _lastGeometryPlayerId != playerId; + final bool rectChanged = _playerRect != currentRect; + + if (currentRect != Rect.zero && (playerChanged || rectChanged)) { + VideoPlayerPlatform.instance.setDisplayGeometry( + playerId, + _safeInt(currentRect.left), + _safeInt(currentRect.top), + _safeInt(currentRect.width), + _safeInt(currentRect.height), + ); + _playerRect = currentRect; + _lastGeometryPlayerId = playerId; + } + } + + WidgetsBinding.instance.addPostFrameCallback(_afterFrameLayout); + } + + int _safeInt(double value) { + if (!value.isFinite || value.isNaN) { + return 0; + } + return value.toInt(); + } + + Rect _getCurrentRect() { + final RenderObject? renderObject = _videoBoxKey.currentContext?.findRenderObject(); + if (renderObject == null) { + return Rect.zero; + } + + final RenderBox renderBox = renderObject as RenderBox; + + final double pixelRatio = View.of(context).devicePixelRatio; + + final Matrix4 transform = renderBox.getTransformTo(null); + final Rect logicalRect = MatrixUtils.transformRect( + transform, + Offset.zero & renderBox.size, + ); + + return Rect.fromLTWH( + logicalRect.left * pixelRatio, + logicalRect.top * pixelRatio, + logicalRect.width * pixelRatio, + logicalRect.height * pixelRatio, + ); + } + + @override + Widget build(BuildContext context) { + return Container(key: _videoBoxKey, child: const _Hole()); + } +} + +class _Hole extends LeafRenderObjectWidget { + const _Hole(); + + @override + RenderBox createRenderObject(BuildContext context) => _HoleBox(); +} + +class _HoleBox extends RenderBox { + @override + bool get sizedByParent => true; + + @override + bool get alwaysNeedsCompositing => true; + + @override + bool get isRepaintBoundary => true; + + @override + void performResize() { + size = constraints.biggest; + } + + @override + bool hitTestSelf(Offset position) => true; + + @override + void paint(PaintingContext context, Offset offset) { + context.addLayer(_HoleLayer(rect: offset & size)); + } +} + +class _HoleLayer extends Layer { + _HoleLayer({required this.rect}); + + final Rect rect; + + @override + void addToScene(ui.SceneBuilder builder, [Offset layerOffset = Offset.zero]) { + builder.addPicture(layerOffset, _createHolePicture(rect)); + } + + ui.Picture _createHolePicture(Rect holeRect) { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final Canvas canvas = Canvas(recorder); + final Paint paint = Paint() + ..color = Colors.transparent + ..blendMode = BlendMode.src; + canvas.drawRect(holeRect, paint); + return recorder.endRecording(); + } +} diff --git a/lib/wrappers/players/tizen_player.dart b/lib/wrappers/players/tizen_player.dart index 701b0a026..2f5b21f9f 100644 --- a/lib/wrappers/players/tizen_player.dart +++ b/lib/wrappers/players/tizen_player.dart @@ -10,6 +10,7 @@ import 'package:subtitle/subtitle.dart'; import 'package:fladder/models/settings/subtitle_settings_model.dart'; import 'package:fladder/providers/settings/subtitle_settings_provider.dart'; import 'package:fladder/util/subtitle_position_calculator.dart'; +import 'package:fladder/util/tizen_video_hole.dart'; import 'package:fladder/models/items/media_streams_model.dart'; import 'package:fladder/models/playback/playback_model.dart'; @@ -40,6 +41,7 @@ class TizenPlayer extends BasePlayer { @override Future loadVideo(String url, bool play) async { await _controller?.dispose(); + _controller = null; final validUrl = Uri.tryParse(url)?.isAbsolute ?? false; _controller = validUrl @@ -204,7 +206,7 @@ class TizenPlayer extends BasePlayer { width: constraints.maxWidth, child: AspectRatio( aspectRatio: aspectRatio, - child: VideoPlayer(_controller!), + child: TizenVideoHole(_controller!), ), ); }, From 48416aedf14057f50a2cad358af7ab703eea42b2 Mon Sep 17 00:00:00 2001 From: popdollar Date: Tue, 30 Dec 2025 20:35:34 +0100 Subject: [PATCH 09/13] chore: made a readme for tizen also updated version number --- tizen/README.md | 13 +++++++++++++ tizen/tizen-manifest.xml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tizen/README.md diff --git a/tizen/README.md b/tizen/README.md new file mode 100644 index 000000000..db6cbecd4 --- /dev/null +++ b/tizen/README.md @@ -0,0 +1,13 @@ +## Install + +Download the tpk file. + +Download the newest version of this awesome tool: https://github.com/PatrickSt1991/Samsung-Jellyfin-Installer + +Run Samsung-Jellyfin-Installer as per the instructions in the above link. + +Then click the little settings icon (cogwheel). Now under custom WGT choose the downloaded tpk file. +Check the "Force Samsung Login" check box. + +Close the settings. Select the target TV. Click download and install. A prompt for samsung login will popup. Login with a samsung account. +When finished you can now use the fladder application. \ No newline at end of file diff --git a/tizen/tizen-manifest.xml b/tizen/tizen-manifest.xml index 6f9bdc2c0..8b0a2bfe7 100644 --- a/tizen/tizen-manifest.xml +++ b/tizen/tizen-manifest.xml @@ -1,5 +1,5 @@ - + From c62932ba3466fc7b2ddb5b5ab6db0b6b6e9f2a65 Mon Sep 17 00:00:00 2001 From: popdollar Date: Fri, 2 Jan 2026 15:35:02 +0100 Subject: [PATCH 10/13] fix: have tizen sync use correct folder structure --- lib/providers/sync_provider.dart | 4 +++- lib/util/adaptive_layout/adaptive_layout.dart | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/providers/sync_provider.dart b/lib/providers/sync_provider.dart index 9f20cfaa9..0eb48f895 100644 --- a/lib/providers/sync_provider.dart +++ b/lib/providers/sync_provider.dart @@ -43,6 +43,8 @@ import 'package:fladder/util/duration_extensions.dart'; import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; + final syncProvider = StateNotifierProvider((ref) => throw UnimplementedError()); final downloadTasksProvider = StateProvider.family((ref, id) => DownloadStream.empty()); @@ -169,7 +171,7 @@ class SyncNotifier extends StateNotifier { late final JellyService api = ref.read(jellyApiProvider); - String? get _savePath => !kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS) + String? get _savePath => !kIsWeb && !isTizen && (Platform.isWindows || Platform.isLinux || Platform.isMacOS) ? ref.read(clientSettingsProvider.select((value) => value.syncPath)) : mobileDirectory.path; diff --git a/lib/util/adaptive_layout/adaptive_layout.dart b/lib/util/adaptive_layout/adaptive_layout.dart index 5ef52b35c..599bae5eb 100644 --- a/lib/util/adaptive_layout/adaptive_layout.dart +++ b/lib/util/adaptive_layout/adaptive_layout.dart @@ -15,6 +15,8 @@ import 'package:fladder/util/poster_defaults.dart'; import 'package:fladder/util/resolution_checker.dart'; import 'package:fladder/widgets/keyboard/slide_in_keyboard.dart'; +import 'package:flutter_tizen/flutter_tizen.dart'; + enum InputDevice { touch, pointer, @@ -155,7 +157,7 @@ class _AdaptiveLayoutBuilderState extends ConsumerState { } bool get isDesktop { - if (kIsWeb) return false; + if (kIsWeb || isTizen) return false; return [ TargetPlatform.macOS, TargetPlatform.windows, From 5e4a07f648a27e2be81cbd50213a0b69c3541024 Mon Sep 17 00:00:00 2001 From: popdollar Date: Tue, 6 Jan 2026 21:04:05 +0100 Subject: [PATCH 11/13] fix: simpler scaling of tizen video player fixed some linting/formatting errors --- lib/util/tizen_video_hole.dart | 176 ------------------------ lib/widgets/shared/pull_to_refresh.dart | 1 - lib/wrappers/players/tizen_player.dart | 6 +- 3 files changed, 3 insertions(+), 180 deletions(-) delete mode 100644 lib/util/tizen_video_hole.dart diff --git a/lib/util/tizen_video_hole.dart b/lib/util/tizen_video_hole.dart deleted file mode 100644 index 67562518a..000000000 --- a/lib/util/tizen_video_hole.dart +++ /dev/null @@ -1,176 +0,0 @@ -import 'dart:ui' as ui; - -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:video_player_videohole/video_player.dart'; -import 'package:video_player_videohole/video_player_platform_interface.dart'; - -/// This is a modified version of the VideoHole widget from the video_player package -/// It is used to create a hole in the video player to display the video on the Tizen TV -/// This is only used to have scaling of UI be independent of the Tizen Video Player -class TizenVideoHole extends StatefulWidget { - const TizenVideoHole(this.controller, {super.key}); - - final VideoPlayerController controller; - - @override - State createState() => _TizenVideoHoleState(); -} - -class _TizenVideoHoleState extends State { - final GlobalKey _videoBoxKey = GlobalKey(); - Rect _playerRect = Rect.zero; - late final VoidCallback _listener; - int _playerId = -1; - int? _lastGeometryPlayerId; - - @override - void initState() { - super.initState(); - - // Keep track of the platform player id. It becomes available after - // asynchronous initialization. - _playerId = widget.controller.playerId; - _listener = () { - _playerId = widget.controller.playerId; - }; - widget.controller.addListener(_listener); - - WidgetsBinding.instance.addPostFrameCallback(_afterFrameLayout); - } - - @override - void didUpdateWidget(TizenVideoHole oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.controller == widget.controller) { - return; - } - - oldWidget.controller.removeListener(_listener); - _playerId = widget.controller.playerId; - widget.controller.addListener(_listener); - _lastGeometryPlayerId = null; - _playerRect = Rect.zero; - } - - @override - void dispose() { - widget.controller.removeListener(_listener); - super.dispose(); - } - - void _afterFrameLayout(_) { - if (!mounted) { - return; - } - - if (widget.controller.value.isInitialized) { - final int playerId = _playerId; - final Rect currentRect = _getCurrentRect(); - final bool playerChanged = _lastGeometryPlayerId != playerId; - final bool rectChanged = _playerRect != currentRect; - - if (currentRect != Rect.zero && (playerChanged || rectChanged)) { - VideoPlayerPlatform.instance.setDisplayGeometry( - playerId, - _safeInt(currentRect.left), - _safeInt(currentRect.top), - _safeInt(currentRect.width), - _safeInt(currentRect.height), - ); - _playerRect = currentRect; - _lastGeometryPlayerId = playerId; - } - } - - WidgetsBinding.instance.addPostFrameCallback(_afterFrameLayout); - } - - int _safeInt(double value) { - if (!value.isFinite || value.isNaN) { - return 0; - } - return value.toInt(); - } - - Rect _getCurrentRect() { - final RenderObject? renderObject = _videoBoxKey.currentContext?.findRenderObject(); - if (renderObject == null) { - return Rect.zero; - } - - final RenderBox renderBox = renderObject as RenderBox; - - final double pixelRatio = View.of(context).devicePixelRatio; - - final Matrix4 transform = renderBox.getTransformTo(null); - final Rect logicalRect = MatrixUtils.transformRect( - transform, - Offset.zero & renderBox.size, - ); - - return Rect.fromLTWH( - logicalRect.left * pixelRatio, - logicalRect.top * pixelRatio, - logicalRect.width * pixelRatio, - logicalRect.height * pixelRatio, - ); - } - - @override - Widget build(BuildContext context) { - return Container(key: _videoBoxKey, child: const _Hole()); - } -} - -class _Hole extends LeafRenderObjectWidget { - const _Hole(); - - @override - RenderBox createRenderObject(BuildContext context) => _HoleBox(); -} - -class _HoleBox extends RenderBox { - @override - bool get sizedByParent => true; - - @override - bool get alwaysNeedsCompositing => true; - - @override - bool get isRepaintBoundary => true; - - @override - void performResize() { - size = constraints.biggest; - } - - @override - bool hitTestSelf(Offset position) => true; - - @override - void paint(PaintingContext context, Offset offset) { - context.addLayer(_HoleLayer(rect: offset & size)); - } -} - -class _HoleLayer extends Layer { - _HoleLayer({required this.rect}); - - final Rect rect; - - @override - void addToScene(ui.SceneBuilder builder, [Offset layerOffset = Offset.zero]) { - builder.addPicture(layerOffset, _createHolePicture(rect)); - } - - ui.Picture _createHolePicture(Rect holeRect) { - final ui.PictureRecorder recorder = ui.PictureRecorder(); - final Canvas canvas = Canvas(recorder); - final Paint paint = Paint() - ..color = Colors.transparent - ..blendMode = BlendMode.src; - canvas.drawRect(holeRect, paint); - return recorder.endRecording(); - } -} diff --git a/lib/widgets/shared/pull_to_refresh.dart b/lib/widgets/shared/pull_to_refresh.dart index 8b5f35b95..2cf919d12 100644 --- a/lib/widgets/shared/pull_to_refresh.dart +++ b/lib/widgets/shared/pull_to_refresh.dart @@ -4,7 +4,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/util/refresh_state.dart'; -import 'package:flutter_tizen/flutter_tizen.dart'; class PullToRefresh extends ConsumerStatefulWidget { final GlobalKey? refreshKey; diff --git a/lib/wrappers/players/tizen_player.dart b/lib/wrappers/players/tizen_player.dart index 2f5b21f9f..09341e018 100644 --- a/lib/wrappers/players/tizen_player.dart +++ b/lib/wrappers/players/tizen_player.dart @@ -10,7 +10,6 @@ import 'package:subtitle/subtitle.dart'; import 'package:fladder/models/settings/subtitle_settings_model.dart'; import 'package:fladder/providers/settings/subtitle_settings_provider.dart'; import 'package:fladder/util/subtitle_position_calculator.dart'; -import 'package:fladder/util/tizen_video_hole.dart'; import 'package:fladder/models/items/media_streams_model.dart'; import 'package:fladder/models/playback/playback_model.dart'; @@ -202,11 +201,12 @@ class TizenPlayer extends BasePlayer { valueListenable: _controller!, builder: (context, value, child) { final aspectRatio = value.isInitialized ? value.aspectRatio : 1.77; + final scale = View.of(context).devicePixelRatio / MediaQuery.devicePixelRatioOf(context); return SizedBox( - width: constraints.maxWidth, + width: constraints.maxWidth * scale, child: AspectRatio( aspectRatio: aspectRatio, - child: TizenVideoHole(_controller!), + child: VideoPlayer(_controller!), ), ); }, From fa2bc19d33de72c50269dbc96745e9a33da22101 Mon Sep 17 00:00:00 2001 From: popdollar Date: Tue, 6 Jan 2026 22:00:05 +0100 Subject: [PATCH 12/13] fix: more specific device profile for Tizen to better handle transcoding --- lib/profiles/tizen_profile.dart | 183 ++++++++++++++++++++++++++++---- 1 file changed, 165 insertions(+), 18 deletions(-) diff --git a/lib/profiles/tizen_profile.dart b/lib/profiles/tizen_profile.dart index 69477af24..635dae71a 100644 --- a/lib/profiles/tizen_profile.dart +++ b/lib/profiles/tizen_profile.dart @@ -1,21 +1,26 @@ import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; -/// Device profile for Tizen TV devices -/// -/// TV does not support DTS and only most TrueHD +/// Tizen TV device profile +/// - TV supports H.264, HEVC, VP9, AV1 video +/// - TV supports AAC, MP3, FLAC, WAV, Vorbis, Opus, E-AC-3, AC-3 audio +/// - TV does NOT support DTS or most TrueHD +/// - Audio-only transcoding will handle unsupported audio const DeviceProfile tizenProfile = DeviceProfile( maxStreamingBitrate: 120000000, maxStaticBitrate: 120000000, musicStreamingTranscodingBitrate: 384000, + + // ------------------------ + // Direct Play Profiles + // ------------------------ directPlayProfiles: [ - // Video: Allow any container with H.264 and supported audio (excluding DTS and most TrueHD (maybe need some system to try and then fall back)) - // Supports multiple audio channels including Dolby 5.1 and Atmos + // Video: allow only codecs Tizen supports DirectPlayProfile( type: DlnaProfileType.video, videoCodec: 'h264,hevc,vp8,vp9,av1', - audioCodec: 'aac,mp3,flac,wav,vorbis,opus,eac3,ac3', + audioCodec: 'aac,mp3,flac,wav,vorbis,opus,eac3,ac3', // exclude dts/truehd ), - // Audio only + // Audio-only DirectPlayProfile(container: 'mp3', type: DlnaProfileType.audio), DirectPlayProfile(container: 'aac', type: DlnaProfileType.audio), DirectPlayProfile(container: 'm4a', audioCodec: 'aac', type: DlnaProfileType.audio), @@ -24,29 +29,171 @@ const DeviceProfile tizenProfile = DeviceProfile( DirectPlayProfile(container: 'wav', type: DlnaProfileType.audio), DirectPlayProfile(container: 'ogg', type: DlnaProfileType.audio), ], - /// Transcoding Profiles + + // ------------------------ + // Transcoding Profiles + // ------------------------ transcodingProfiles: [ - // Video transcoding with E-AC-3 audio + // Video copy + audio transcode for unsupported audio (e.g., DTS/TrueHD) TranscodingProfile( type: DlnaProfileType.video, protocol: MediaStreamProtocol.hls, container: 'ts', - videoCodec: 'h264', - audioCodec: 'eac3,ac3,aac', // Transcode TrueHD/DTS to E-AC-3 + videoCodec: 'copy', // copy video, no transcode + audioCodec: 'eac3,ac3,aac', // transcode unsupported audio + context: EncodingContext.streaming, + maxAudioChannels: '6', // support up to 5.1 ), - // Optional: Audio-only transcoding + // Audio-only transcoding for playback TranscodingProfile( type: DlnaProfileType.audio, protocol: MediaStreamProtocol.http, container: 'mp4', audioCodec: 'aac,eac3,ac3', + context: EncodingContext.streaming, + maxAudioChannels: '6', ), ], + containerProfiles: [], - subtitleProfiles: [ - SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.$external), - SubtitleProfile(format: 'ass', method: SubtitleDeliveryMethod.$external), - SubtitleProfile(format: 'ssa', method: SubtitleDeliveryMethod.$external), - SubtitleProfile(format: 'pgssub', method: SubtitleDeliveryMethod.$external), - ], + + // ------------------------ + // Codec Profiles + // ------------------------ + codecProfiles: [ + // Video codec profiles: allow direct play if Tizen supports it + CodecProfile( + type: CodecType.video, + codec: 'h264', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isanamorphic, + $Value: 'true', + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videorangetype, + $Value: 'SDR', + ), + ProfileCondition( + condition: ProfileConditionType.lessthanequal, + property: ProfileConditionValue.videolevel, + $Value: '52', + ), + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isinterlaced, + $Value: 'true', + ), + ], + ), + CodecProfile( + type: CodecType.video, + codec: 'hevc', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isanamorphic, + $Value: 'true', + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videoprofile, + $Value: 'main', + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videorangetype, + $Value: 'SDR|HDR10|HLG', + ), + ProfileCondition( + condition: ProfileConditionType.lessthanequal, + property: ProfileConditionValue.videolevel, + $Value: '120', + ), + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isinterlaced, + $Value: 'true', + ), + ], + ), + CodecProfile( + type: CodecType.video, + codec: 'vp9', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videorangetype, + $Value: 'SDR|HDR10|HLG', + ), + ], + ), + CodecProfile( + type: CodecType.video, + codec: 'av1', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isanamorphic, + $Value: 'true', + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videoprofile, + $Value: 'main', + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videorangetype, + $Value: 'SDR|HDR10|HLG', + ), + ProfileCondition( + condition: ProfileConditionType.lessthanequal, + property: ProfileConditionValue.videolevel, + $Value: '19', + ), + ], + ), + + // Audio codec profiles: allow direct play for supported audio + CodecProfile( + type: CodecType.videoaudio, + codec: 'aac', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.equals, + property: ProfileConditionValue.issecondaryaudio, + $Value: 'false', + ), + ], + ), + CodecProfile( + type: CodecType.videoaudio, + codec: 'ac3', + ), + CodecProfile( + type: CodecType.videoaudio, + codec: 'eac3', + ), + CodecProfile( + type: CodecType.videoaudio, + codec: 'flac', + ), + CodecProfile( + type: CodecType.videoaudio, + codec: 'mp3', + ), + ], + + // ------------------------ + // Subtitles + // ------------------------ + subtitleProfiles: [ + SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'ass', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'ssa', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'pgssub', method: SubtitleDeliveryMethod.$external), + ], ); From 8f3cb9a1e5813efc6c97a0efadfc1bf20bb3db81 Mon Sep 17 00:00:00 2001 From: popdollar Date: Thu, 22 Jan 2026 11:18:03 +0100 Subject: [PATCH 13/13] fix: small fixes to tizen_player and tizen_video_player_controls fixed it so pause and play in TizenPlayer does not return an empty future cleaned up tizen_video_player_controls - removed commented out code. --- .../tizen_video_player_controls.dart | 27 +++---------------- lib/wrappers/players/tizen_player.dart | 4 +-- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/lib/screens/video_player/tizen_video_player_controls.dart b/lib/screens/video_player/tizen_video_player_controls.dart index 7f0f98648..93be22316 100644 --- a/lib/screens/video_player/tizen_video_player_controls.dart +++ b/lib/screens/video_player/tizen_video_player_controls.dart @@ -189,7 +189,7 @@ class _TVControlsState extends ConsumerState { break; case 'seekBack': final backwardSpeed = - ref.read(userProvider.select((value) => value?.userSettings?.skipBackDuration.inSeconds ?? 10)); + ref.read(userProvider.select((value) => value?.userSettings?.skipBackDuration.inSeconds ?? 30)); seekBack(ref, seconds: backwardSpeed); break; case 'playPause': @@ -698,8 +698,8 @@ class _TVControlsState extends ConsumerState { } Widget seekBackwardButton(WidgetRef ref) { - final backwardSpeed = 10; - //ref.read(userProvider.select((value) => value?.userSettings?.skipBackDuration.inSeconds ?? 30)); + final backwardSpeed = + ref.read(userProvider.select((value) => value?.userSettings?.skipBackDuration.inSeconds ?? 30)); return _wrapNav( 'seekBack', IconButton( @@ -901,36 +901,15 @@ class _TVControlsState extends ConsumerState { resetTimer(); return true; } - // if (key == LogicalKeyboardKey.arrowUp) { - // // Move up a few steps (best-effort grid movement) - // _moveSelection(-3); - // return true; - // } - // if (key == LogicalKeyboardKey.arrowDown) { - // _moveSelection(3); - // return true; - // } - // Activation keys if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter || key == LogicalKeyboardKey.space) { - //activateSelection(); - //_setActiveIndicator('Activate'); resetTimer(); return true; } } - // // Arrow keys -> seek indicator (when overlay not visible) - // if (key == LogicalKeyboardKey.arrowLeft || key == LogicalKeyboardKey.arrowRight) { - // _setActiveIndicator('Seek'); - // // do not swallow here; other handlers (seek indicator) will process the key - // return false; - // } - // Up/Down -> volume (when overlay not visible) if (key == LogicalKeyboardKey.arrowUp || key == LogicalKeyboardKey.arrowDown || key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter || key == LogicalKeyboardKey.space) { - // _setActiveIndicator('Volume'); - // do not swallow here; allow normal processing toggleOverlay(value: true); return false; } diff --git a/lib/wrappers/players/tizen_player.dart b/lib/wrappers/players/tizen_player.dart index 09341e018..379c461f7 100644 --- a/lib/wrappers/players/tizen_player.dart +++ b/lib/wrappers/players/tizen_player.dart @@ -82,9 +82,9 @@ class TizenPlayer extends BasePlayer { } @override - Future pause() => _controller?.pause() ?? Future.value(); + Future pause() async => _controller?.pause(); @override - Future play() => _controller?.play() ?? Future.value(); + Future play() async => _controller?.play(); @override Future playOrPause() async => lastState.playing ? _controller?.pause() : _controller?.play(); @override