settings: subtitle theme

This commit is contained in:
Thibault Deckers 2021-06-25 10:31:15 +09:00
parent 4345f46cc2
commit caedb78f4f
13 changed files with 560 additions and 118 deletions

View file

@ -607,6 +607,18 @@
"@settingsSubtitleThemeTextAlignmentTile": {},
"settingsSubtitleThemeTextAlignmentTitle": "Text Alignment",
"@settingsSubtitleThemeTextAlignmentTitle": {},
"settingsSubtitleThemeTextSize": "Text size",
"@settingsSubtitleThemeTextSize": {},
"settingsSubtitleThemeShowOutline": "Show outline and shadow",
"@settingsSubtitleThemeShowOutline": {},
"settingsSubtitleThemeTextColor": "Text color",
"@settingsSubtitleThemeTextColor": {},
"settingsSubtitleThemeTextOpacity": "Text opacity",
"@settingsSubtitleThemeTextOpacity": {},
"settingsSubtitleThemeBackgroundColor": "Background color",
"@settingsSubtitleThemeBackgroundColor": {},
"settingsSubtitleThemeBackgroundOpacity": "Background opacity",
"@settingsSubtitleThemeBackgroundOpacity": {},
"settingsSubtitleThemeTextAlignmentLeft": "Left",
"@settingsSubtitleThemeTextAlignmentLeft": {},
"settingsSubtitleThemeTextAlignmentCenter": "Center",

View file

@ -282,6 +282,21 @@
"settingsVideoQuickActionsTile": "빠른 동영상 작업",
"settingsVideoQuickActionEditorTitle": "빠른 동영상 작업",
"settingsSubtitleThemeTile": "자막",
"settingsSubtitleThemeTitle": "자막",
"settingsSubtitleThemeSample": "샘플입니다.",
"settingsSubtitleThemeTextAlignmentTile": "정렬",
"settingsSubtitleThemeTextAlignmentTitle": "정렬",
"settingsSubtitleThemeTextSize": "글자 크기",
"settingsSubtitleThemeShowOutline": "윤곽 및 그림자 표시",
"settingsSubtitleThemeTextColor": "글자 색상",
"settingsSubtitleThemeTextOpacity": "글자 투명도",
"settingsSubtitleThemeBackgroundColor": "배경 색상",
"settingsSubtitleThemeBackgroundOpacity": "배경 투명도",
"settingsSubtitleThemeTextAlignmentLeft": "왼쪽",
"settingsSubtitleThemeTextAlignmentCenter": "가운데",
"settingsSubtitleThemeTextAlignmentRight": "오른쪽",
"settingsSectionPrivacy": "개인정보 보호",
"settingsEnableAnalytics": "진단 데이터 보내기",
"settingsSaveSearchHistory": "검색기록",

View file

@ -52,7 +52,6 @@ class Durations {
// settings animations
static const quickActionListAnimation = Duration(milliseconds: 200);
static const quickActionHighlightAnimation = Duration(milliseconds: 200);
static const themeChangeDuration = Duration(milliseconds: 400);
// delays & refresh intervals
static const opToastDisplay = Duration(seconds: 3);

View file

@ -142,6 +142,99 @@ class Constants {
),
];
static const List<Dependency> flutterPackages = [
Dependency(
name: 'Charts',
license: 'Apache 2.0',
licenseUrl: 'https://github.com/google/charts/blob/master/LICENSE',
sourceUrl: 'https://github.com/google/charts',
),
Dependency(
name: 'Decorated Icon',
license: 'MIT',
licenseUrl: 'https://github.com/benPesso/flutter_decorated_icon/blob/master/LICENSE',
sourceUrl: 'https://github.com/benPesso/flutter_decorated_icon',
),
Dependency(
name: 'Expansion Tile Card (Aves fork)',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/deckerst/expansion_tile_card/blob/master/LICENSE',
sourceUrl: 'https://github.com/deckerst/expansion_tile_card',
),
Dependency(
name: 'FlexColorPicker',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/rydmike/flex_color_picker/blob/master/LICENSE',
sourceUrl: 'https://github.com/rydmike/flex_color_picker',
),
Dependency(
name: 'Flutter Highlight',
license: 'MIT',
licenseUrl: 'https://github.com/git-touch/highlight/blob/master/LICENSE',
sourceUrl: 'https://github.com/git-touch/highlight',
),
Dependency(
name: 'Flutter Map',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/fleaflet/flutter_map/blob/master/LICENSE',
sourceUrl: 'https://github.com/fleaflet/flutter_map',
),
Dependency(
name: 'Flutter Markdown',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/flutter/packages/blob/master/packages/flutter_markdown/LICENSE',
sourceUrl: 'https://github.com/flutter/packages/tree/master/packages/flutter_markdown',
),
Dependency(
name: 'Flutter Staggered Animations',
license: 'MIT',
licenseUrl: 'https://github.com/mobiten/flutter_staggered_animations/blob/master/LICENSE',
sourceUrl: 'https://github.com/mobiten/flutter_staggered_animations',
),
Dependency(
name: 'Flutter SVG',
license: 'MIT',
licenseUrl: 'https://github.com/dnfield/flutter_svg/blob/master/LICENSE',
sourceUrl: 'https://github.com/dnfield/flutter_svg',
),
Dependency(
name: 'Material Design Icons Flutter',
license: 'MIT',
licenseUrl: 'https://github.com/ziofat/material_design_icons_flutter/blob/master/LICENSE',
sourceUrl: 'https://github.com/ziofat/material_design_icons_flutter',
),
Dependency(
name: 'Overlay Support',
license: 'Apache 2.0',
licenseUrl: 'https://github.com/boyan01/overlay_support/blob/master/LICENSE',
sourceUrl: 'https://github.com/boyan01/overlay_support',
),
Dependency(
name: 'Palette Generator',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/flutter/packages/blob/master/packages/palette_generator/LICENSE',
sourceUrl: 'https://github.com/flutter/packages/tree/master/packages/palette_generator',
),
Dependency(
name: 'Panorama',
license: 'Apache 2.0',
licenseUrl: 'https://github.com/zesage/panorama/blob/master/LICENSE',
sourceUrl: 'https://github.com/zesage/panorama',
),
Dependency(
name: 'Percent Indicator',
license: 'BSD 2-Clause',
licenseUrl: 'https://github.com/diegoveloper/flutter_percent_indicator/blob/master/LICENSE',
sourceUrl: 'https://github.com/diegoveloper/flutter_percent_indicator/',
),
Dependency(
name: 'Provider',
license: 'MIT',
licenseUrl: 'https://github.com/rrousselGit/provider/blob/master/LICENSE',
sourceUrl: 'https://github.com/rrousselGit/provider',
),
];
static const List<Dependency> dartPackages = [
Dependency(
name: 'Collection',
@ -216,93 +309,6 @@ class Constants {
sourceUrl: 'https://github.com/renggli/dart-xml',
),
];
static const List<Dependency> flutterPackages = [
Dependency(
name: 'Charts',
license: 'Apache 2.0',
licenseUrl: 'https://github.com/google/charts/blob/master/LICENSE',
sourceUrl: 'https://github.com/google/charts',
),
Dependency(
name: 'Decorated Icon',
license: 'MIT',
licenseUrl: 'https://github.com/benPesso/flutter_decorated_icon/blob/master/LICENSE',
sourceUrl: 'https://github.com/benPesso/flutter_decorated_icon',
),
Dependency(
name: 'Expansion Tile Card (Aves fork)',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/deckerst/expansion_tile_card/blob/master/LICENSE',
sourceUrl: 'https://github.com/deckerst/expansion_tile_card',
),
Dependency(
name: 'Flutter Highlight',
license: 'MIT',
licenseUrl: 'https://github.com/git-touch/highlight/blob/master/LICENSE',
sourceUrl: 'https://github.com/git-touch/highlight',
),
Dependency(
name: 'Flutter Map',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/fleaflet/flutter_map/blob/master/LICENSE',
sourceUrl: 'https://github.com/fleaflet/flutter_map',
),
Dependency(
name: 'Flutter Markdown',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/flutter/packages/blob/master/packages/flutter_markdown/LICENSE',
sourceUrl: 'https://github.com/flutter/packages/tree/master/packages/flutter_markdown',
),
Dependency(
name: 'Flutter Staggered Animations',
license: 'MIT',
licenseUrl: 'https://github.com/mobiten/flutter_staggered_animations/blob/master/LICENSE',
sourceUrl: 'https://github.com/mobiten/flutter_staggered_animations',
),
Dependency(
name: 'Flutter SVG',
license: 'MIT',
licenseUrl: 'https://github.com/dnfield/flutter_svg/blob/master/LICENSE',
sourceUrl: 'https://github.com/dnfield/flutter_svg',
),
Dependency(
name: 'Material Design Icons Flutter',
license: 'MIT',
licenseUrl: 'https://github.com/ziofat/material_design_icons_flutter/blob/master/LICENSE',
sourceUrl: 'https://github.com/ziofat/material_design_icons_flutter',
),
Dependency(
name: 'Overlay Support',
license: 'Apache 2.0',
licenseUrl: 'https://github.com/boyan01/overlay_support/blob/master/LICENSE',
sourceUrl: 'https://github.com/boyan01/overlay_support',
),
Dependency(
name: 'Palette Generator',
license: 'BSD 3-Clause',
licenseUrl: 'https://github.com/flutter/packages/blob/master/packages/palette_generator/LICENSE',
sourceUrl: 'https://github.com/flutter/packages/tree/master/packages/palette_generator',
),
Dependency(
name: 'Panorama',
license: 'Apache 2.0',
licenseUrl: 'https://github.com/zesage/panorama/blob/master/LICENSE',
sourceUrl: 'https://github.com/zesage/panorama',
),
Dependency(
name: 'Percent Indicator',
license: 'BSD 2-Clause',
licenseUrl: 'https://github.com/diegoveloper/flutter_percent_indicator/blob/master/LICENSE',
sourceUrl: 'https://github.com/diegoveloper/flutter_percent_indicator/',
),
Dependency(
name: 'Provider',
license: 'MIT',
licenseUrl: 'https://github.com/rrousselGit/provider/blob/master/LICENSE',
sourceUrl: 'https://github.com/rrousselGit/provider',
),
];
}
class Dependency {

View file

@ -0,0 +1,100 @@
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/fx/borders.dart';
import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:flex_color_picker/flex_color_picker.dart';
import 'package:flutter/material.dart';
class ColorListTile extends StatelessWidget {
final String title;
final Color value;
final ValueSetter<Color> onChanged;
static const radius = 16.0;
const ColorListTile({
Key? key,
required this.title,
required this.value,
required this.onChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(title),
trailing: Container(
height: radius * 2,
width: radius * 2,
decoration: BoxDecoration(
color: value,
border: AvesBorder.border,
shape: BoxShape.circle,
),
),
contentPadding: const EdgeInsetsDirectional.only(start: 16, end: 36 - radius),
onTap: () async {
final color = await showDialog<Color>(
context: context,
builder: (context) => ColorPickerDialog(
initialValue: value,
),
);
if (color != null) {
onChanged(color);
}
},
);
}
}
class ColorPickerDialog extends StatefulWidget {
final Color initialValue;
const ColorPickerDialog({
Key? key,
required this.initialValue,
}) : super(key: key);
@override
_ColorPickerDialogState createState() => _ColorPickerDialogState();
}
class _ColorPickerDialogState extends State<ColorPickerDialog> {
late Color color;
@override
void initState() {
super.initState();
color = widget.initialValue;
}
@override
Widget build(BuildContext context) {
return AvesDialog(
context: context,
scrollableContent: [
ColorPicker(
color: color,
onColorChanged: (v) => color = v,
pickersEnabled: const {
ColorPickerType.primary: false,
ColorPickerType.accent: false,
ColorPickerType.wheel: true,
},
hasBorder: true,
borderRadius: 20,
)
],
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
),
TextButton(
onPressed: () => Navigator.pop(context, color),
child: Text(context.l10n.applyButtonLabel),
),
],
);
}
}

View file

@ -25,9 +25,17 @@ class OutlinedText extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO TLAD [subtitles] fix background area for mixed alphabetic-ideographic text
// as of Flutter v2.2.2, the area computed for `backgroundColor` has inconsistent height
// in case of mixed alphabetic-ideographic text. The painted boxes depends on the script.
// Possible workarounds would be to use metrics from:
// - `TextPainter.getBoxesForSelection`
// - `Paragraph.getBoxesForRange`
// and paint the background at the bottom of the `Stack`
final hasOutline = outlineWidth > 0;
return Stack(
children: [
if (outlineWidth > 0)
if (hasOutline)
ImageFiltered(
imageFilter: outlineBlurSigma > 0
? ImageFilter.blur(
@ -46,7 +54,7 @@ class OutlinedText extends StatelessWidget {
),
Text.rich(
TextSpan(
children: textSpans,
children: hasOutline ? textSpans.map(_toFillSpan).toList() : textSpans,
),
textAlign: textAlign,
),
@ -64,4 +72,12 @@ class OutlinedText extends StatelessWidget {
..color = outlineColor,
),
);
TextSpan _toFillSpan(TextSpan span) => TextSpan(
text: span.text,
children: span.children,
style: (span.style ?? const TextStyle()).copyWith(
backgroundColor: Colors.transparent,
),
);
}

View file

@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
class SliderListTile extends StatelessWidget {
final String title;
final double value;
final ValueChanged<double>? onChanged;
final double min;
final double max;
final int? divisions;
const SliderListTile({
Key? key,
required this.title,
required this.value,
required this.onChanged,
this.min = 0.0,
this.max = 1.0,
this.divisions,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SliderTheme(
data: const SliderThemeData(
overlayShape: RoundSliderOverlayShape(
// align `Slider`s on `Switch`es by matching their overlay/reaction radius
// `kRadialReactionRadius` is used when `SwitchThemeData.splashRadius` is undefined
overlayRadius: kRadialReactionRadius,
),
),
child: DefaultTextStyle(
style: Theme.of(context).textTheme.subtitle1!,
child: Padding(
padding: const EdgeInsets.only(top: 16, bottom: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsetsDirectional.only(start: 16),
child: Text(title),
),
Padding(
// match `SwitchListTile.contentPadding`
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Slider(
value: value,
onChanged: onChanged,
min: min,
max: max,
divisions: divisions,
),
),
],
),
),
),
);
}
}

View file

@ -0,0 +1,82 @@
import 'package:aves/model/settings/settings.dart';
import 'package:aves/widgets/common/basic/outlined_text.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/fx/borders.dart';
import 'package:aves/widgets/viewer/visual/subtitle/subtitle.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class SubtitleSample extends StatelessWidget {
const SubtitleSample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<Settings>(
builder: (context, settings, child) {
final outlineColor = Colors.black.withOpacity(settings.subtitleTextColor.opacity);
final shadows = [
Shadow(
color: outlineColor,
offset: VideoSubtitles.baseShadowOffset,
),
];
return Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
// Bora Bora
Color(0xff2bc0e4),
Color(0xffeaecc6),
],
),
border: AvesBorder.border,
borderRadius: const BorderRadius.all(Radius.circular(24)),
),
height: 128,
child: AnimatedAlign(
alignment: _getAlignment(settings.subtitleTextAlignment),
curve: Curves.easeInOutCubic,
duration: const Duration(milliseconds: 400),
child: Padding(
padding: const EdgeInsets.all(16),
child: AnimatedDefaultTextStyle(
style: TextStyle(
color: settings.subtitleTextColor,
backgroundColor: settings.subtitleBackgroundColor,
fontSize: settings.subtitleFontSize,
shadows: settings.subtitleShowOutline ? shadows : null,
),
textAlign: settings.subtitleTextAlignment,
duration: const Duration(milliseconds: 200),
child: OutlinedText(
textSpans: [
TextSpan(
text: context.l10n.settingsSubtitleThemeSample,
),
],
outlineWidth: settings.subtitleShowOutline ? 1 : 0,
outlineColor: outlineColor,
),
),
),
),
);
},
);
}
Alignment _getAlignment(TextAlign textAlign) {
switch (textAlign) {
case TextAlign.left:
return Alignment.bottomLeft;
case TextAlign.right:
return Alignment.bottomRight;
case TextAlign.center:
default:
return Alignment.bottomCenter;
}
}
}

View file

@ -0,0 +1,126 @@
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';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/dialogs/aves_selection_dialog.dart';
import 'package:aves/widgets/settings/video/subtitle_sample.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class SubtitleThemeTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(context.l10n.settingsSubtitleThemeTile),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
settings: const RouteSettings(name: SubtitleThemePage.routeName),
builder: (context) => SubtitleThemePage(),
),
);
},
);
}
}
class SubtitleThemePage extends StatelessWidget {
static const routeName = '/settings/subtitle_theme';
static const textAlignOptions = [TextAlign.left, TextAlign.center, TextAlign.right];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(context.l10n.settingsSubtitleThemeTitle),
),
body: SafeArea(
child: Consumer<Settings>(
builder: (context, settings, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(16),
child: SubtitleSample(),
),
const Divider(height: 0),
Expanded(
child: ListView(
children: [
ListTile(
title: Text(context.l10n.settingsSubtitleThemeTextAlignmentTile),
subtitle: Text(_getTextAlignName(context, settings.subtitleTextAlignment)),
onTap: () async {
final value = await showDialog<TextAlign>(
context: context,
builder: (context) => AvesSelectionDialog<TextAlign>(
initialValue: settings.subtitleTextAlignment,
options: Map.fromEntries(textAlignOptions.map((v) => MapEntry(v, _getTextAlignName(context, v)))),
title: context.l10n.settingsSubtitleThemeTextAlignmentTitle,
),
);
if (value != null) {
settings.subtitleTextAlignment = value;
}
},
),
SliderListTile(
title: context.l10n.settingsSubtitleThemeTextSize,
value: settings.subtitleFontSize,
onChanged: (v) => settings.subtitleFontSize = v,
min: 10,
max: 40,
divisions: 6,
),
ColorListTile(
title: context.l10n.settingsSubtitleThemeTextColor,
value: settings.subtitleTextColor.withOpacity(1),
onChanged: (v) => settings.subtitleTextColor = v.withOpacity(settings.subtitleTextColor.opacity),
),
SliderListTile(
title: context.l10n.settingsSubtitleThemeTextOpacity,
value: settings.subtitleTextColor.opacity,
onChanged: (v) => settings.subtitleTextColor = settings.subtitleTextColor.withOpacity(v),
),
ColorListTile(
title: context.l10n.settingsSubtitleThemeBackgroundColor,
value: settings.subtitleBackgroundColor.withOpacity(1),
onChanged: (v) => settings.subtitleBackgroundColor = v.withOpacity(settings.subtitleBackgroundColor.opacity),
),
SliderListTile(
title: context.l10n.settingsSubtitleThemeBackgroundOpacity,
value: settings.subtitleBackgroundColor.opacity,
onChanged: (v) => settings.subtitleBackgroundColor = settings.subtitleBackgroundColor.withOpacity(v),
),
SwitchListTile(
value: settings.subtitleShowOutline,
onChanged: (v) => settings.subtitleShowOutline = v,
title: Text(context.l10n.settingsSubtitleThemeShowOutline),
),
],
),
),
],
);
},
),
),
);
}
String _getTextAlignName(BuildContext context, TextAlign align) {
switch (align) {
case TextAlign.left:
return context.l10n.settingsSubtitleThemeTextAlignmentLeft;
case TextAlign.center:
return context.l10n.settingsSubtitleThemeTextAlignmentCenter;
case TextAlign.right:
return context.l10n.settingsSubtitleThemeTextAlignmentRight;
default:
return '';
}
}
}

View file

@ -9,6 +9,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/dialogs/aves_selection_dialog.dart';
import 'package:aves/widgets/settings/common/tile_leading.dart';
import 'package:aves/widgets/settings/video/subtitle_theme.dart';
import 'package:aves/widgets/settings/video/video_actions_editor.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -42,6 +43,7 @@ class VideoSection extends StatelessWidget {
onChanged: (v) => context.read<CollectionSource>().changeFilterVisibility(MimeFilter.video, v),
title: Text(context.l10n.settingsVideoShowVideos),
),
VideoActionsTile(),
SwitchListTile(
value: currentEnableVideoHardwareAcceleration,
onChanged: (v) => settings.enableVideoHardwareAcceleration = v,
@ -69,7 +71,7 @@ class VideoSection extends StatelessWidget {
}
},
),
VideoActionsTile(),
SubtitleThemeTile(),
],
);
}

View file

@ -16,13 +16,7 @@ class VideoSubtitles extends StatelessWidget {
final ValueNotifier<ViewState> viewStateNotifier;
final bool debugMode;
static const baseOutlineColor = Colors.black;
static const baseShadows = [
Shadow(
color: Colors.black54,
offset: Offset(1, 1),
),
];
static const baseShadowOffset = Offset(1, 1);
const VideoSubtitles({
Key? key,
@ -39,6 +33,13 @@ class VideoSubtitles extends StatelessWidget {
builder: (context, settings, child) {
final baseTextAlign = settings.subtitleTextAlignment;
final baseOutlineWidth = settings.subtitleShowOutline ? 1 : 0;
final baseOutlineColor = Colors.black.withOpacity(settings.subtitleTextColor.opacity);
final baseShadows = [
Shadow(
color: baseOutlineColor,
offset: baseShadowOffset,
),
];
final baseStyle = TextStyle(
color: settings.subtitleTextColor,
backgroundColor: settings.subtitleBackgroundColor,
@ -50,18 +51,6 @@ class VideoSubtitles extends StatelessWidget {
selector: (c, mq) => mq.orientation,
builder: (c, orientation, child) {
final bottom = orientation == Orientation.portrait ? .5 : .8;
Alignment toVerticalAlignment(SubtitleStyle extraStyle) {
switch (extraStyle.vAlign) {
case TextAlignVertical.top:
return Alignment(0, -bottom);
case TextAlignVertical.center:
return Alignment.center;
case TextAlignVertical.bottom:
default:
return Alignment(0, bottom);
}
}
final viewportSize = context.read<MediaQueryData>().size;
return ValueListenableBuilder<ViewState>(
@ -132,6 +121,7 @@ class VideoSubtitles extends StatelessWidget {
);
}).toList();
final drawingPaths = extraStyle.drawingPaths;
final textAlign = extraStyle.hAlign ?? (position != null ? TextAlign.center : baseTextAlign);
Widget child;
if (drawingPaths != null) {
@ -150,7 +140,7 @@ class VideoSubtitles extends StatelessWidget {
outlineWidth: outlineWidth * (position != null ? viewScale : baseOutlineWidth),
outlineColor: extraStyle.borderColor ?? baseOutlineColor,
outlineBlurSigma: extraStyle.edgeBlur ?? 0,
textAlign: extraStyle.hAlign ?? baseTextAlign,
textAlign: textAlign,
);
}
@ -166,7 +156,7 @@ class VideoSubtitles extends StatelessWidget {
final textHeight = para.getMaxIntrinsicHeight(double.infinity);
late double anchorOffsetX, anchorOffsetY;
switch (extraStyle.hAlign ?? baseTextAlign) {
switch (textAlign) {
case TextAlign.left:
anchorOffsetX = 0;
break;
@ -174,9 +164,7 @@ class VideoSubtitles extends StatelessWidget {
anchorOffsetX = -textWidth;
break;
case TextAlign.center:
case TextAlign.start:
case TextAlign.end:
case TextAlign.justify:
default:
anchorOffsetX = -textWidth / 2;
break;
}
@ -227,9 +215,38 @@ class VideoSubtitles extends StatelessWidget {
}
if (position == null) {
child = Align(
alignment: toVerticalAlignment(extraStyle),
child: child,
late double alignX;
switch (textAlign) {
case TextAlign.left:
alignX = -1;
break;
case TextAlign.right:
alignX = 1;
break;
case TextAlign.center:
default:
alignX = 0;
break;
}
late double alignY;
switch (extraStyle.vAlign) {
case TextAlignVertical.top:
alignY = -bottom;
break;
case TextAlignVertical.center:
alignY = 0;
break;
case TextAlignVertical.bottom:
default:
alignY = bottom;
break;
}
child = Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Align(
alignment: Alignment(alignX, alignY),
child: child,
),
);
}

View file

@ -292,6 +292,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.6"
flex_color_picker:
dependency: "direct main"
description:
name: flex_color_picker
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
flutter:
dependency: "direct main"
description: flutter

View file

@ -31,6 +31,7 @@ dependencies:
firebase_core:
firebase_analytics:
firebase_crashlytics:
flex_color_picker:
flutter_highlight:
flutter_map:
flutter_markdown: