#380 subtitle vertical position option

This commit is contained in:
Thibault Deckers 2022-11-23 11:25:10 +01:00
parent f3bee6ec7e
commit cbfbc436ed
10 changed files with 163 additions and 28 deletions

View file

@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
### Added
- Viewer: Info page editing actions available as quick actions
- Video: subtitle vertical position option
- Info: export metadata to text file
- Accessibility: apply bold font system setting
- `libre` app flavor (no mobile service maps, no Crashlytics)

View file

@ -198,6 +198,9 @@
"displayRefreshRatePreferHighest": "Highest rate",
"displayRefreshRatePreferLowest": "Lowest rate",
"subtitlePositionTop": "Top",
"subtitlePositionBottom": "Bottom",
"videoPlaybackSkip": "Skip",
"videoPlaybackMuted": "Play muted",
"videoPlaybackWithSound": "Play with sound",
@ -738,6 +741,8 @@
"settingsSubtitleThemeSample": "This is a sample.",
"settingsSubtitleThemeTextAlignmentTile": "Text alignment",
"settingsSubtitleThemeTextAlignmentDialogTitle": "Text Alignment",
"settingsSubtitleThemeTextPositionTile": "Text position",
"settingsSubtitleThemeTextPositionDialogTitle": "Text Position",
"settingsSubtitleThemeTextSize": "Text size",
"settingsSubtitleThemeShowOutline": "Show outline and shadow",
"settingsSubtitleThemeTextColor": "Text color",

View file

@ -98,6 +98,7 @@ class SettingsDefaults {
// subtitles
static const subtitleFontSize = 20.0;
static const subtitleTextAlignment = TextAlign.center;
static const subtitleTextPosition = SubtitlePosition.bottom;
static const subtitleShowOutline = true;
static const subtitleTextColor = Colors.white;
static const subtitleBackgroundColor = Colors.transparent;

View file

@ -20,6 +20,8 @@ enum KeepScreenOn { never, viewerOnly, always }
enum SlideshowVideoPlayback { skip, playMuted, playWithSound }
enum SubtitlePosition { top, bottom }
enum UnitSystem { metric, imperial }
enum VideoControls { play, playSeek, playOutside, none }

View file

@ -0,0 +1,24 @@
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:flutter/widgets.dart';
import 'enums.dart';
extension ExtraSubtitlePosition on SubtitlePosition {
String getName(BuildContext context) {
switch (this) {
case SubtitlePosition.top:
return context.l10n.subtitlePositionTop;
case SubtitlePosition.bottom:
return context.l10n.subtitlePositionBottom;
}
}
TextAlignVertical toTextAlignVertical() {
switch (this) {
case SubtitlePosition.top:
return TextAlignVertical.top;
case SubtitlePosition.bottom:
return TextAlignVertical.bottom;
}
}
}

View file

@ -123,6 +123,7 @@ class Settings extends ChangeNotifier {
// subtitles
static const subtitleFontSizeKey = 'subtitle_font_size';
static const subtitleTextAlignmentKey = 'subtitle_text_alignment';
static const subtitleTextPositionKey = 'subtitle_text_position';
static const subtitleShowOutlineKey = 'subtitle_show_outline';
static const subtitleTextColorKey = 'subtitle_text_color';
static const subtitleBackgroundColorKey = 'subtitle_background_color';
@ -573,6 +574,10 @@ class Settings extends ChangeNotifier {
set subtitleTextAlignment(TextAlign newValue) => setAndNotify(subtitleTextAlignmentKey, newValue.toString());
SubtitlePosition get subtitleTextPosition => getEnumOrDefault(subtitleTextPositionKey, SettingsDefaults.subtitleTextPosition, SubtitlePosition.values);
set subtitleTextPosition(SubtitlePosition newValue) => setAndNotify(subtitleTextPositionKey, newValue.toString());
bool get subtitleShowOutline => getBool(subtitleShowOutlineKey) ?? SettingsDefaults.subtitleShowOutline;
set subtitleShowOutline(bool newValue) => setAndNotify(subtitleShowOutlineKey, newValue);
@ -963,6 +968,7 @@ class Settings extends ChangeNotifier {
case videoLoopModeKey:
case videoControlsKey:
case subtitleTextAlignmentKey:
case subtitleTextPositionKey:
case mapStyleKey:
case mapDefaultCenterKey:
case coordinateFormatKey:

View file

@ -1,3 +1,4 @@
import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/utils/constants.dart';
import 'package:aves/widgets/common/basic/outlined_text.dart';
@ -20,6 +21,7 @@ class SubtitleSample extends StatelessWidget {
return Consumer<Settings>(
builder: (context, settings, child) {
final textAlign = settings.subtitleTextAlignment;
final textPosition = settings.subtitleTextPosition;
final outlineColor = Colors.black.withOpacity(settings.subtitleTextColor.opacity);
final shadows = [
Shadow(
@ -40,7 +42,7 @@ class SubtitleSample extends StatelessWidget {
),
height: 128,
child: AnimatedAlign(
alignment: _getAlignment(textAlign),
alignment: _getAlignment(textAlign, textPosition),
curve: Curves.easeInOutCubic,
duration: const Duration(milliseconds: 400),
child: Padding(
@ -75,7 +77,19 @@ class SubtitleSample extends StatelessWidget {
);
}
Alignment _getAlignment(TextAlign textAlign) {
Alignment _getAlignment(TextAlign textAlign, SubtitlePosition textPosition) {
switch (textPosition) {
case SubtitlePosition.top:
switch (textAlign) {
case TextAlign.left:
return Alignment.topLeft;
case TextAlign.right:
return Alignment.topRight;
case TextAlign.center:
default:
return Alignment.topCenter;
}
case SubtitlePosition.bottom:
switch (textAlign) {
case TextAlign.left:
return Alignment.bottomLeft;
@ -86,4 +100,5 @@ class SubtitleSample extends StatelessWidget {
return Alignment.bottomCenter;
}
}
}
}

View file

@ -1,3 +1,5 @@
import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/enums/subtitle_position.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/widgets/common/basic/color_list_tile.dart';
import 'package:aves/widgets/common/basic/slider_list_tile.dart';
@ -40,6 +42,14 @@ class SubtitleThemePage extends StatelessWidget {
tileTitle: context.l10n.settingsSubtitleThemeTextAlignmentTile,
dialogTitle: context.l10n.settingsSubtitleThemeTextAlignmentDialogTitle,
),
SettingsSelectionListTile<SubtitlePosition>(
values: const [SubtitlePosition.top, SubtitlePosition.bottom],
getName: (context, v) => v.getName(context),
selector: (context, s) => s.subtitleTextPosition,
onSelection: (v) => settings.subtitleTextPosition = v,
tileTitle: context.l10n.settingsSubtitleThemeTextPositionTile,
dialogTitle: context.l10n.settingsSubtitleThemeTextPositionDialogTitle,
),
SliderListTile(
title: context.l10n.settingsSubtitleThemeTextSize,
value: settings.subtitleFontSize,

View file

@ -1,3 +1,4 @@
import 'package:aves/model/settings/enums/subtitle_position.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/widgets/common/basic/outlined_text.dart';
import 'package:aves/widgets/common/basic/text_background_painter.dart';
@ -33,6 +34,7 @@ class VideoSubtitles extends StatelessWidget {
child: Consumer<Settings>(
builder: (context, settings, child) {
final baseTextAlign = settings.subtitleTextAlignment;
final baseTextAlignY = settings.subtitleTextPosition.toTextAlignVertical();
final baseOutlineWidth = settings.subtitleShowOutline ? 1 : 0;
final baseOutlineColor = Colors.black.withOpacity(settings.subtitleTextColor.opacity);
final baseShadows = [
@ -119,7 +121,8 @@ class VideoSubtitles extends StatelessWidget {
);
}).toList();
final drawingPaths = extraStyle.drawingPaths;
final textAlign = extraStyle.hAlign ?? (position != null ? TextAlign.center : baseTextAlign);
final textHAlign = extraStyle.hAlign ?? (position != null ? TextAlign.center : baseTextAlign);
final textVAlign = extraStyle.vAlign ?? (position != null ? TextAlignVertical.bottom : baseTextAlignY);
Widget child;
if (drawingPaths != null) {
@ -138,7 +141,7 @@ class VideoSubtitles extends StatelessWidget {
outlineWidth: outlineWidth * (position != null ? viewScale : baseOutlineWidth),
outlineColor: extraStyle.borderColor ?? baseOutlineColor,
outlineBlurSigma: extraStyle.edgeBlur ?? 0,
textAlign: textAlign,
textAlign: textHAlign,
);
}
@ -154,7 +157,7 @@ class VideoSubtitles extends StatelessWidget {
final textHeight = para.getMaxIntrinsicHeight(double.infinity);
late double anchorOffsetX, anchorOffsetY;
switch (textAlign) {
switch (textHAlign) {
case TextAlign.left:
anchorOffsetX = 0;
break;
@ -166,7 +169,7 @@ class VideoSubtitles extends StatelessWidget {
anchorOffsetX = -textWidth / 2;
break;
}
switch (extraStyle.vAlign ?? TextAlignVertical.bottom) {
switch (textVAlign) {
case TextAlignVertical.top:
anchorOffsetY = 0;
break;
@ -214,7 +217,7 @@ class VideoSubtitles extends StatelessWidget {
if (position == null) {
late double alignX;
switch (textAlign) {
switch (textHAlign) {
case TextAlign.left:
alignX = -1;
break;
@ -227,7 +230,7 @@ class VideoSubtitles extends StatelessWidget {
break;
}
late double alignY;
switch (extraStyle.vAlign) {
switch (textVAlign) {
case TextAlignVertical.top:
alignY = -bottom;
break;
@ -248,7 +251,7 @@ class VideoSubtitles extends StatelessWidget {
style: DefaultTextStyle.of(context).style.merge(spans.first.style!.copyWith(
backgroundColor: settings.subtitleBackgroundColor,
)),
textAlign: textAlign,
textAlign: textHAlign,
child: child,
),
),

View file

@ -1,15 +1,27 @@
{
"de": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"el": [
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle",
"tagEditorSectionPlaceholders"
],
"es": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"fa": [
@ -151,6 +163,8 @@
"accessibilityAnimationsKeep",
"displayRefreshRatePreferHighest",
"displayRefreshRatePreferLowest",
"subtitlePositionTop",
"subtitlePositionBottom",
"videoPlaybackSkip",
"videoPlaybackMuted",
"videoPlaybackWithSound",
@ -476,6 +490,8 @@
"settingsSubtitleThemeSample",
"settingsSubtitleThemeTextAlignmentTile",
"settingsSubtitleThemeTextAlignmentDialogTitle",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle",
"settingsSubtitleThemeTextSize",
"settingsSubtitleThemeShowOutline",
"settingsSubtitleThemeTextColor",
@ -596,7 +612,11 @@
],
"fr": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"gl": [
@ -605,6 +625,8 @@
"accessibilityAnimationsKeep",
"displayRefreshRatePreferHighest",
"displayRefreshRatePreferLowest",
"subtitlePositionTop",
"subtitlePositionBottom",
"videoPlaybackSkip",
"videoPlaybackMuted",
"videoPlaybackWithSound",
@ -930,6 +952,8 @@
"settingsSubtitleThemeSample",
"settingsSubtitleThemeTextAlignmentTile",
"settingsSubtitleThemeTextAlignmentDialogTitle",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle",
"settingsSubtitleThemeTextSize",
"settingsSubtitleThemeShowOutline",
"settingsSubtitleThemeTextColor",
@ -1050,20 +1074,36 @@
],
"id": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"it": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"ja": [
"chipActionFilterIn",
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"ko": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"nb": [
@ -1077,6 +1117,8 @@
"mapStyleStamenToner",
"mapStyleStamenWatercolor",
"keepScreenOnViewerOnly",
"subtitlePositionTop",
"subtitlePositionBottom",
"viewerTransitionFade",
"albumTierSpecial",
"storageAccessDialogMessage",
@ -1154,6 +1196,8 @@
"settingsViewerEnableOverlayBlurEffect",
"settingsSlideshowShuffle",
"settingsSubtitleThemeSample",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle",
"settingsAllowInstalledAppAccess",
"settingsAllowMediaManagement",
"settingsHiddenFiltersBanner",
@ -1181,7 +1225,11 @@
],
"nl": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"pl": [
@ -1230,6 +1278,8 @@
"accessibilityAnimationsKeep",
"displayRefreshRatePreferHighest",
"displayRefreshRatePreferLowest",
"subtitlePositionTop",
"subtitlePositionBottom",
"videoPlaybackSkip",
"videoPlaybackMuted",
"videoPlaybackWithSound",
@ -1555,6 +1605,8 @@
"settingsSubtitleThemeSample",
"settingsSubtitleThemeTextAlignmentTile",
"settingsSubtitleThemeTextAlignmentDialogTitle",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle",
"settingsSubtitleThemeTextSize",
"settingsSubtitleThemeShowOutline",
"settingsSubtitleThemeTextColor",
@ -1675,20 +1727,36 @@
],
"pt": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"ru": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"tr": [
"entryInfoActionExportMetadata"
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle"
],
"zh": [
"entryInfoActionExportMetadata",
"subtitlePositionTop",
"subtitlePositionBottom",
"editEntryLocationDialogSetCustom",
"settingsSubtitleThemeTextPositionTile",
"settingsSubtitleThemeTextPositionDialogTitle",
"settingsAllowMediaManagement",
"tagEditorSectionPlaceholders",
"tagPlaceholderCountry",