Compare commits

...
1 Commits
Author SHA1 Message Date
RarDog 9a0fd282b7 feat(video): optimize video player aspect ratio sizing and seekbar positioning v3.1.4
Build and Release / Build Windows x64 (push) Has been cancelled
2026-09-04 21:50:17 +03:00
6 changed files with 166 additions and 64 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
</p> </p>
<p align="center"> <p align="center">
<a href="https://github.com/RarDog/Lunaris/releases"><img src="https://img.shields.io/badge/Version-3.1.3-8A2BE2?style=for-the-badge&logo=semver&logoColor=white" alt="Version 3.1.3" /></a> <a href="https://github.com/RarDog/Lunaris/releases"><img src="https://img.shields.io/badge/Version-3.1.4-8A2BE2?style=for-the-badge&logo=semver&logoColor=white" alt="Version 3.1.4" /></a>
<img src="https://img.shields.io/badge/Flutter-3.47+-02569B?style=for-the-badge&logo=flutter&logoColor=white" alt="Flutter" /> <img src="https://img.shields.io/badge/Flutter-3.47+-02569B?style=for-the-badge&logo=flutter&logoColor=white" alt="Flutter" />
<img src="https://img.shields.io/badge/Platform-Android%20%7C%20Linux%20%7C%20Windows-00C853?style=for-the-badge" alt="Platforms" /> <img src="https://img.shields.io/badge/Platform-Android%20%7C%20Linux%20%7C%20Windows-00C853?style=for-the-badge" alt="Platforms" />
<a href="https://github.com/RarDog/Lunaris/wiki"><img src="https://img.shields.io/badge/Wiki-Documentation-FF6F00?style=for-the-badge&logo=gitbook&logoColor=white" alt="Wiki" /></a> <a href="https://github.com/RarDog/Lunaris/wiki"><img src="https://img.shields.io/badge/Wiki-Documentation-FF6F00?style=for-the-badge&logo=gitbook&logoColor=white" alt="Wiki" /></a>
+2 -2
View File
@@ -1,3 +1,3 @@
const appDisplayVersion = '3.1.3'; const appDisplayVersion = '3.1.4';
const appBuildNumber = 64; const appBuildNumber = 65;
const appReleaseChannel = 'Stable'; const appReleaseChannel = 'Stable';
+9
View File
@@ -1,4 +1,13 @@
const lunarisChangelog = [ const lunarisChangelog = [
LunarisChange(
version: '3.1.4',
title: 'Оптимизация видеоплеера — адаптивная высота и идеальное прилегание полосы воспроизведения',
bullets: [
'Устранение зазора под видео: контейнер плеера на мобильных устройствах и ПК теперь динамически подстраивается под пропорции видео (aspect ratio) вместо жестко фиксированной высоты 62% экрана, устраняя огромные пустые черные полосы сверху и снизу.',
'Точное позиционирование полосы воспроизведения: исправлен отступ снизу и ложное наложение системных insets на неполноэкранный плеер в карточке поста — ползунок воспроизведения, таймкоды и кнопка фуллскрина теперь аккуратно прилегают к нижнему краю видео без зависания в воздухе.',
'Компактные элементы управления: выровнены буферный трек и слайдер прокрутки, оптимизирован градиент затенения для максимальной видимости и удобства управления.',
],
),
LunarisChange( LunarisChange(
version: '3.1.3', version: '3.1.3',
title: 'iPhone Liquid Glass — Источники, Проверка сети и Навигация назад по вкладкам', title: 'iPhone Liquid Glass — Источники, Проверка сети и Навигация назад по вкладкам',
@@ -219,7 +219,44 @@ class PostDetailsScreen extends ConsumerWidget {
), ),
Expanded( Expanded(
child: Center( child: Center(
child: SizedBox( child: MediaUrlSelector.isVideo(post)
? ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 760,
),
child: AspectRatio(
aspectRatio:
(post.width > 0 && post.height > 0)
? (post.width / post.height)
.clamp(0.45, 2.4)
: (16 / 9),
child: PostMediaViewer(
key: ValueKey(post.cacheKey),
post: post,
localFilePath: localMedia?.savedPath,
qualityMode: qualityMode,
mediaHeaders: ref
.watch(postMediaHeadersProvider(post))
.value ??
const {},
initialPosition: Duration(
milliseconds: settings.videoPlaybackPositions[
post.cacheKey] ??
0,
),
initialLoop: settings.videoPlayerLoop,
initialMuted: settings.videoPlayerMuted,
initialCoverVideo: settings.videoPlayerCover,
initialHalfVolume:
settings.videoPlayerHalfVolume,
onPlaybackSnapshot: (snapshot) =>
_saveVideoSnapshot(ref, post, snapshot),
onPlaybackPreferencesChanged: (snapshot) =>
_saveVideoPreferences(ref, snapshot),
),
),
)
: SizedBox(
width: double.infinity, width: double.infinity,
height: 760, height: 760,
child: PostMediaViewer( child: PostMediaViewer(
@@ -409,7 +446,45 @@ class PostDetailsScreen extends ConsumerWidget {
? null ? null
: () => : () =>
_showMobileQuickActions(context, ref, post, favoriteKeys), _showMobileQuickActions(context, ref, post, favoriteKeys),
child: SizedBox( child: isVideo
? Center(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context).height * 0.70,
),
child: AspectRatio(
aspectRatio: (post.width > 0 && post.height > 0)
? (post.width / post.height).clamp(0.45, 2.4)
: (16 / 9),
child: PostMediaViewer(
key: ValueKey(post.cacheKey),
post: post,
localFilePath: localMedia?.savedPath,
qualityMode: qualityMode,
mediaHeaders:
ref.watch(postMediaHeadersProvider(post)).value ??
const {},
initialPosition: Duration(
milliseconds:
settings.videoPlaybackPositions[post.cacheKey] ??
0,
),
initialLoop: settings.videoPlayerLoop,
initialMuted: settings.videoPlayerMuted,
initialCoverVideo: settings.videoPlayerCover,
initialHalfVolume: settings.videoPlayerHalfVolume,
onPlaybackSnapshot: (snapshot) =>
_saveVideoSnapshot(ref, post, snapshot),
onPlaybackPreferencesChanged: (snapshot) =>
_saveVideoPreferences(ref, snapshot),
onMediaGestureLockChanged: (locked) {
onMediaGestureLockChanged?.call(locked);
},
),
),
),
)
: SizedBox(
width: double.infinity, width: double.infinity,
height: MediaQuery.sizeOf(context).height * 0.62, height: MediaQuery.sizeOf(context).height * 0.62,
child: PostMediaViewer( child: PostMediaViewer(
@@ -418,7 +493,8 @@ class PostDetailsScreen extends ConsumerWidget {
localFilePath: localMedia?.savedPath, localFilePath: localMedia?.savedPath,
qualityMode: qualityMode, qualityMode: qualityMode,
mediaHeaders: mediaHeaders:
ref.watch(postMediaHeadersProvider(post)).value ?? const {}, ref.watch(postMediaHeadersProvider(post)).value ??
const {},
initialPosition: Duration( initialPosition: Duration(
milliseconds: milliseconds:
settings.videoPlaybackPositions[post.cacheKey] ?? 0, settings.videoPlaybackPositions[post.cacheKey] ?? 0,
@@ -1792,7 +1792,10 @@ class _VideoControls extends StatelessWidget {
), ),
), ),
child: SafeArea( child: SafeArea(
top: fullscreen,
bottom: false, bottom: false,
left: fullscreen,
right: fullscreen,
child: Row( child: Row(
children: [ children: [
if (fullscreen) ...[ if (fullscreen) ...[
@@ -1910,7 +1913,12 @@ class _VideoControls extends StatelessWidget {
left: 0, left: 0,
right: 0, right: 0,
child: Container( child: Container(
padding: const EdgeInsets.fromLTRB(14, 12, 14, 10), padding: EdgeInsets.fromLTRB(
14,
8,
14,
fullscreen ? 10 : 4,
),
decoration: const BoxDecoration( decoration: const BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
begin: Alignment.bottomCenter, begin: Alignment.bottomCenter,
@@ -1920,6 +1928,9 @@ class _VideoControls extends StatelessWidget {
), ),
child: SafeArea( child: SafeArea(
top: false, top: false,
bottom: fullscreen,
left: fullscreen,
right: fullscreen,
child: StreamBuilder<Duration>( child: StreamBuilder<Duration>(
stream: player.stream.duration, stream: player.stream.duration,
initialData: player.state.duration, initialData: player.state.duration,
@@ -1967,8 +1978,8 @@ class _VideoControls extends StatelessWidget {
// Buffer progress track // Buffer progress track
if (maxMs > 0 && bufferMs > 0) if (maxMs > 0 && bufferMs > 0)
Positioned( Positioned(
left: 20, left: 14,
right: 20, right: 14,
child: ClipRRect( child: ClipRRect(
borderRadius: borderRadius:
BorderRadius.circular(2), BorderRadius.circular(2),
@@ -1976,10 +1987,12 @@ class _VideoControls extends StatelessWidget {
value: (bufferMs / maxMs) value: (bufferMs / maxMs)
.clamp(0.0, 1.0), .clamp(0.0, 1.0),
minHeight: 3.5, minHeight: 3.5,
backgroundColor: Colors.transparent, backgroundColor:
Colors.transparent,
valueColor: valueColor:
AlwaysStoppedAnimation( AlwaysStoppedAnimation(
Colors.white.withValues(alpha: 0.28), Colors.white
.withValues(alpha: 0.28),
), ),
), ),
), ),
@@ -1997,6 +2010,10 @@ class _VideoControls extends StatelessWidget {
const RoundSliderThumbShape( const RoundSliderThumbShape(
enabledThumbRadius: 6, enabledThumbRadius: 6,
), ),
overlayShape:
const RoundSliderOverlayShape(
overlayRadius: 14,
),
), ),
child: Slider( child: Slider(
value: valueMs, value: valueMs,
+1 -1
View File
@@ -1,7 +1,7 @@
name: gel_rule_app name: gel_rule_app
description: Local backend/core layer for a Flutter booru browser app. description: Local backend/core layer for a Flutter booru browser app.
publish_to: "none" publish_to: "none"
version: 3.1.3+64 version: 3.1.4+65
environment: environment:
sdk: ">=3.3.0 <4.0.0" sdk: ">=3.3.0 <4.0.0"