video: custom quick actions
This commit is contained in:
parent
68b367a427
commit
d203e0fe2e
11 changed files with 135 additions and 64 deletions
|
@ -590,6 +590,10 @@
|
||||||
"@settingsVideoLoopModeTile": {},
|
"@settingsVideoLoopModeTile": {},
|
||||||
"settingsVideoLoopModeTitle": "Loop Mode",
|
"settingsVideoLoopModeTitle": "Loop Mode",
|
||||||
"@settingsVideoLoopModeTitle": {},
|
"@settingsVideoLoopModeTitle": {},
|
||||||
|
"settingsVideoQuickActionsTile": "Quick video actions",
|
||||||
|
"@settingsVideoQuickActionsTile": {},
|
||||||
|
"settingsVideoQuickActionEditorTitle": "Quick Video Actions",
|
||||||
|
"@settingsVideoQuickActionEditorTitle": {},
|
||||||
|
|
||||||
"settingsSectionPrivacy": "Privacy",
|
"settingsSectionPrivacy": "Privacy",
|
||||||
"@settingsSectionPrivacy": {},
|
"@settingsSectionPrivacy": {},
|
||||||
|
|
|
@ -278,6 +278,8 @@
|
||||||
"settingsVideoEnableAutoPlay": "자동 재생",
|
"settingsVideoEnableAutoPlay": "자동 재생",
|
||||||
"settingsVideoLoopModeTile": "반복 모드",
|
"settingsVideoLoopModeTile": "반복 모드",
|
||||||
"settingsVideoLoopModeTitle": "반복 모드",
|
"settingsVideoLoopModeTitle": "반복 모드",
|
||||||
|
"settingsVideoQuickActionsTile": "빠른 동영상 작업",
|
||||||
|
"settingsVideoQuickActionEditorTitle": "빠른 동영상 작업",
|
||||||
|
|
||||||
"settingsSectionPrivacy": "개인정보 보호",
|
"settingsSectionPrivacy": "개인정보 보호",
|
||||||
"settingsEnableAnalytics": "진단 데이터 보내기",
|
"settingsEnableAnalytics": "진단 데이터 보내기",
|
||||||
|
|
|
@ -43,6 +43,7 @@ class DebugSettingsSection extends StatelessWidget {
|
||||||
'tileExtent - Tags': '${settings.getTileExtent(TagListPage.routeName)}',
|
'tileExtent - Tags': '${settings.getTileExtent(TagListPage.routeName)}',
|
||||||
'infoMapZoom': '${settings.infoMapZoom}',
|
'infoMapZoom': '${settings.infoMapZoom}',
|
||||||
'viewerQuickActions': '${settings.viewerQuickActions}',
|
'viewerQuickActions': '${settings.viewerQuickActions}',
|
||||||
|
'videoQuickActions': '${settings.videoQuickActions}',
|
||||||
'pinnedFilters': toMultiline(settings.pinnedFilters),
|
'pinnedFilters': toMultiline(settings.pinnedFilters),
|
||||||
'hiddenFilters': toMultiline(settings.hiddenFilters),
|
'hiddenFilters': toMultiline(settings.hiddenFilters),
|
||||||
'searchHistory': toMultiline(settings.searchHistory),
|
'searchHistory': toMultiline(settings.searchHistory),
|
||||||
|
|
|
@ -47,6 +47,7 @@ class _VideoStreamSelectionDialogState extends State<VideoStreamSelectionDialog>
|
||||||
final canSelect = canSelectVideo || canSelectAudio || canSelectText;
|
final canSelect = canSelectVideo || canSelectAudio || canSelectText;
|
||||||
return AvesDialog(
|
return AvesDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
content: canSelect ? null : Text(context.l10n.videoStreamSelectionDialogNoSelection),
|
||||||
scrollableContent: canSelect
|
scrollableContent: canSelect
|
||||||
? [
|
? [
|
||||||
if (canSelectVideo)
|
if (canSelectVideo)
|
||||||
|
@ -75,22 +76,17 @@ class _VideoStreamSelectionDialogState extends State<VideoStreamSelectionDialog>
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
]
|
]
|
||||||
: [
|
: null,
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Text(context.l10n.videoStreamSelectionDialogNoSelection),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
|
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
|
||||||
),
|
),
|
||||||
TextButton(
|
if (canSelect)
|
||||||
onPressed: () => _submit(context),
|
TextButton(
|
||||||
child: Text(context.l10n.applyButtonLabel),
|
onPressed: () => _submit(context),
|
||||||
),
|
child: Text(context.l10n.applyButtonLabel),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class QuickActionEditorPage<T extends Object> extends StatefulWidget {
|
class QuickActionEditorPage<T extends Object> extends StatefulWidget {
|
||||||
final String bannerText;
|
final String title, bannerText;
|
||||||
final List<T> allAvailableActions;
|
final List<T> allAvailableActions;
|
||||||
final IconData? Function(T action) actionIcon;
|
final IconData? Function(T action) actionIcon;
|
||||||
final String Function(BuildContext context, T action) actionText;
|
final String Function(BuildContext context, T action) actionText;
|
||||||
|
@ -24,6 +24,7 @@ class QuickActionEditorPage<T extends Object> extends StatefulWidget {
|
||||||
final void Function(List<T> actions) save;
|
final void Function(List<T> actions) save;
|
||||||
|
|
||||||
const QuickActionEditorPage({
|
const QuickActionEditorPage({
|
||||||
|
required this.title,
|
||||||
required this.bannerText,
|
required this.bannerText,
|
||||||
required this.allAvailableActions,
|
required this.allAvailableActions,
|
||||||
required this.actionIcon,
|
required this.actionIcon,
|
||||||
|
@ -96,7 +97,7 @@ class _QuickActionEditorPageState<T extends Object> extends State<QuickActionEdi
|
||||||
return MediaQueryDataProvider(
|
return MediaQueryDataProvider(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(context.l10n.settingsViewerQuickActionEditorTitle),
|
title: Text(widget.title),
|
||||||
),
|
),
|
||||||
body: WillPopScope(
|
body: WillPopScope(
|
||||||
onWillPop: () {
|
onWillPop: () {
|
||||||
|
|
|
@ -19,7 +19,8 @@ import 'package:aves/widgets/settings/access_grants.dart';
|
||||||
import 'package:aves/widgets/settings/entry_background.dart';
|
import 'package:aves/widgets/settings/entry_background.dart';
|
||||||
import 'package:aves/widgets/settings/hidden_filters.dart';
|
import 'package:aves/widgets/settings/hidden_filters.dart';
|
||||||
import 'package:aves/widgets/settings/language.dart';
|
import 'package:aves/widgets/settings/language.dart';
|
||||||
import 'package:aves/widgets/settings/entry_actions_editor.dart';
|
import 'package:aves/widgets/settings/video_actions_editor.dart';
|
||||||
|
import 'package:aves/widgets/settings/viewer_actions_editor.dart';
|
||||||
import 'package:decorated_icon/decorated_icon.dart';
|
import 'package:decorated_icon/decorated_icon.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||||
|
@ -191,7 +192,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
expandedNotifier: _expandedNotifier,
|
expandedNotifier: _expandedNotifier,
|
||||||
showHighlight: false,
|
showHighlight: false,
|
||||||
children: [
|
children: [
|
||||||
QuickEntryActionsTile(),
|
ViewerActionsTile(),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
value: settings.showOverlayMinimap,
|
value: settings.showOverlayMinimap,
|
||||||
onChanged: (v) => settings.showOverlayMinimap = v,
|
onChanged: (v) => settings.showOverlayMinimap = v,
|
||||||
|
@ -267,6 +268,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
VideoActionsTile(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
42
lib/widgets/settings/video_actions_editor.dart
Normal file
42
lib/widgets/settings/video_actions_editor.dart
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import 'package:aves/model/actions/video_actions.dart';
|
||||||
|
import 'package:aves/model/settings/settings.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/settings/quick_actions/editor_page.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class VideoActionsTile extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(context.l10n.settingsVideoQuickActionsTile),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
settings: const RouteSettings(name: VideoActionEditorPage.routeName),
|
||||||
|
builder: (context) => const VideoActionEditorPage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VideoActionEditorPage extends StatelessWidget {
|
||||||
|
static const routeName = '/settings/video_actions';
|
||||||
|
|
||||||
|
const VideoActionEditorPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return QuickActionEditorPage<VideoAction>(
|
||||||
|
title: context.l10n.settingsVideoQuickActionEditorTitle,
|
||||||
|
bannerText: context.l10n.settingsViewerQuickActionEditorBanner,
|
||||||
|
allAvailableActions: VideoActions.all,
|
||||||
|
actionIcon: (action) => action.getIcon(),
|
||||||
|
actionText: (context, action) => action.getText(context),
|
||||||
|
load: () => settings.videoQuickActions.toList(),
|
||||||
|
save: (actions) => settings.videoQuickActions = actions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/settings/quick_actions/editor_page.dart';
|
import 'package:aves/widgets/settings/quick_actions/editor_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class QuickEntryActionsTile extends StatelessWidget {
|
class ViewerActionsTile extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
|
@ -13,8 +13,8 @@ class QuickEntryActionsTile extends StatelessWidget {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
settings: const RouteSettings(name: QuickEntryActionEditorPage.routeName),
|
settings: const RouteSettings(name: ViewerActionEditorPage.routeName),
|
||||||
builder: (context) => const QuickEntryActionEditorPage(),
|
builder: (context) => const ViewerActionEditorPage(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -22,10 +22,10 @@ class QuickEntryActionsTile extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class QuickEntryActionEditorPage extends StatelessWidget {
|
class ViewerActionEditorPage extends StatelessWidget {
|
||||||
static const routeName = '/settings/quick_entry_actions';
|
static const routeName = '/settings/viewer_actions';
|
||||||
|
|
||||||
const QuickEntryActionEditorPage({Key? key}) : super(key: key);
|
const ViewerActionEditorPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
static const allAvailableActions = [
|
static const allAvailableActions = [
|
||||||
EntryAction.info,
|
EntryAction.info,
|
||||||
|
@ -44,6 +44,7 @@ class QuickEntryActionEditorPage extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return QuickActionEditorPage<EntryAction>(
|
return QuickActionEditorPage<EntryAction>(
|
||||||
|
title: context.l10n.settingsViewerQuickActionEditorTitle,
|
||||||
bannerText: context.l10n.settingsViewerQuickActionEditorBanner,
|
bannerText: context.l10n.settingsViewerQuickActionEditorBanner,
|
||||||
allAvailableActions: allAvailableActions,
|
allAvailableActions: allAvailableActions,
|
||||||
actionIcon: (action) => action.getIcon(),
|
actionIcon: (action) => action.getIcon(),
|
|
@ -6,6 +6,7 @@ import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/services/android_app_service.dart';
|
import 'package:aves/services/android_app_service.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/utils/constants.dart';
|
||||||
import 'package:aves/utils/time_utils.dart';
|
import 'package:aves/utils/time_utils.dart';
|
||||||
import 'package:aves/widgets/common/basic/menu_row.dart';
|
import 'package:aves/widgets/common/basic/menu_row.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
@ -18,6 +19,7 @@ import 'package:aves/widgets/viewer/overlay/notifications.dart';
|
||||||
import 'package:aves/widgets/viewer/video/controller.dart';
|
import 'package:aves/widgets/viewer/video/controller.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class VideoControlOverlay extends StatefulWidget {
|
class VideoControlOverlay extends StatefulWidget {
|
||||||
final AvesEntry entry;
|
final AvesEntry entry;
|
||||||
|
@ -51,6 +53,9 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
||||||
|
|
||||||
bool get isPlaying => controller?.isPlaying ?? false;
|
bool get isPlaying => controller?.isPlaying ?? false;
|
||||||
|
|
||||||
|
static const double outerPadding = 8;
|
||||||
|
static const double innerPadding = 8;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StreamBuilder<VideoStatus>(
|
return StreamBuilder<VideoStatus>(
|
||||||
|
@ -58,10 +63,11 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
// do not use stream snapshot because it is obsolete when switching between videos
|
// do not use stream snapshot because it is obsolete when switching between videos
|
||||||
final status = controller?.status ?? VideoStatus.idle;
|
final status = controller?.status ?? VideoStatus.idle;
|
||||||
List<Widget> children;
|
Widget child;
|
||||||
if (status == VideoStatus.error) {
|
if (status == VideoStatus.error) {
|
||||||
children = [
|
child = Align(
|
||||||
OverlayButton(
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
|
child: OverlayButton(
|
||||||
scale: scale,
|
scale: scale,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: const Icon(AIcons.openOutside),
|
icon: const Icon(AIcons.openOutside),
|
||||||
|
@ -69,32 +75,38 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
||||||
tooltip: context.l10n.viewerOpenTooltip,
|
tooltip: context.l10n.viewerOpenTooltip,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
);
|
||||||
} else {
|
} else {
|
||||||
final quickActions = settings.videoQuickActions;
|
child = Selector<MediaQueryData, double>(
|
||||||
final menuActions = VideoActions.all.where((action) => !quickActions.contains(action)).toList();
|
selector: (c, mq) => mq.size.width - mq.padding.horizontal,
|
||||||
children = [
|
builder: (c, mqWidth, child) {
|
||||||
Expanded(
|
final buttonWidth = OverlayButton.getSize(context);
|
||||||
child: _buildProgressBar(),
|
final availableCount = ((mqWidth - outerPadding * 2) / (buttonWidth + innerPadding)).floor();
|
||||||
),
|
final quickActions = settings.videoQuickActions.take(availableCount - 1).toList();
|
||||||
const SizedBox(width: 8),
|
final menuActions = VideoActions.all.where((action) => !quickActions.contains(action)).toList();
|
||||||
_ButtonRow(
|
return Column(
|
||||||
quickActions: quickActions,
|
mainAxisSize: MainAxisSize.min,
|
||||||
menuActions: menuActions,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
scale: scale,
|
children: [
|
||||||
controller: controller,
|
_ButtonRow(
|
||||||
),
|
quickActions: quickActions,
|
||||||
];
|
menuActions: menuActions,
|
||||||
|
scale: scale,
|
||||||
|
controller: controller,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
_buildProgressBar(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TooltipTheme(
|
return TooltipTheme(
|
||||||
data: TooltipTheme.of(context).copyWith(
|
data: TooltipTheme.of(context).copyWith(
|
||||||
preferBelow: false,
|
preferBelow: false,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: child,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: children,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -136,10 +148,16 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
// do not use stream snapshot because it is obsolete when switching between videos
|
// do not use stream snapshot because it is obsolete when switching between videos
|
||||||
final position = controller?.currentPosition.floor() ?? 0;
|
final position = controller?.currentPosition.floor() ?? 0;
|
||||||
return Text(formatFriendlyDuration(Duration(milliseconds: position)));
|
return Text(
|
||||||
|
formatFriendlyDuration(Duration(milliseconds: position)),
|
||||||
|
style: const TextStyle(shadows: Constants.embossShadows),
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Text(entry.durationText),
|
Text(
|
||||||
|
entry.durationText,
|
||||||
|
style: const TextStyle(shadows: Constants.embossShadows),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
|
@ -196,16 +214,20 @@ class _ButtonRow extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
...quickActions.map((action) => _buildOverlayButton(context, action)),
|
...quickActions.map((action) => _buildOverlayButton(context, action)),
|
||||||
OverlayButton(
|
if (menuActions.isNotEmpty)
|
||||||
scale: scale,
|
Padding(
|
||||||
child: PopupMenuButton<VideoAction>(
|
padding: const EdgeInsetsDirectional.only(start: padding),
|
||||||
itemBuilder: (context) => menuActions.map((action) => _buildPopupMenuItem(context, action)).toList(),
|
child: OverlayButton(
|
||||||
onSelected: (action) {
|
scale: scale,
|
||||||
// wait for the popup menu to hide before proceeding with the action
|
child: PopupMenuButton<VideoAction>(
|
||||||
Future.delayed(Durations.popupMenuAnimation * timeDilation, () => _onActionSelected(context, action));
|
itemBuilder: (context) => menuActions.map((action) => _buildPopupMenuItem(context, action)).toList(),
|
||||||
},
|
onSelected: (action) {
|
||||||
|
// wait for the popup menu to hide before proceeding with the action
|
||||||
|
Future.delayed(Durations.popupMenuAnimation * timeDilation, () => _onActionSelected(context, action));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -232,7 +254,7 @@ class _ButtonRow extends StatelessWidget {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsetsDirectional.only(end: padding),
|
padding: const EdgeInsetsDirectional.only(start: padding),
|
||||||
child: OverlayButton(
|
child: OverlayButton(
|
||||||
scale: scale,
|
scale: scale,
|
||||||
child: child,
|
child: child,
|
||||||
|
|
|
@ -34,8 +34,8 @@ class OverlayButton extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// icon (24) + icon padding (8) + button padding (16) + border (2)
|
// icon (24) + icon padding (8) + button padding (16) + border (1 or 2)
|
||||||
static double getSize(BuildContext context) => 50.0;
|
static double getSize(BuildContext context) => 48.0 + AvesBorder.borderWidth * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
class OverlayTextButton extends StatelessWidget {
|
class OverlayTextButton extends StatelessWidget {
|
||||||
|
|
|
@ -25,7 +25,8 @@ class ViewerTopOverlay extends StatelessWidget {
|
||||||
final bool canToggleFavourite;
|
final bool canToggleFavourite;
|
||||||
final ValueNotifier<ViewState>? viewStateNotifier;
|
final ValueNotifier<ViewState>? viewStateNotifier;
|
||||||
|
|
||||||
static const double padding = 8;
|
static const double outerPadding = 8;
|
||||||
|
static const double innerPadding = 8;
|
||||||
|
|
||||||
const ViewerTopOverlay({
|
const ViewerTopOverlay({
|
||||||
Key? key,
|
Key? key,
|
||||||
|
@ -43,11 +44,12 @@ class ViewerTopOverlay extends StatelessWidget {
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
minimum: (viewInsets ?? EdgeInsets.zero) + (viewPadding ?? EdgeInsets.zero),
|
minimum: (viewInsets ?? EdgeInsets.zero) + (viewPadding ?? EdgeInsets.zero),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(padding),
|
padding: const EdgeInsets.all(outerPadding),
|
||||||
child: Selector<MediaQueryData, double>(
|
child: Selector<MediaQueryData, double>(
|
||||||
selector: (c, mq) => mq.size.width - mq.padding.horizontal,
|
selector: (c, mq) => mq.size.width - mq.padding.horizontal,
|
||||||
builder: (c, mqWidth, child) {
|
builder: (c, mqWidth, child) {
|
||||||
final availableCount = (mqWidth / (OverlayButton.getSize(context) + padding)).floor() - 2;
|
final buttonWidth = OverlayButton.getSize(context);
|
||||||
|
final availableCount = ((mqWidth - outerPadding * 2 - buttonWidth) / (buttonWidth + innerPadding)).floor();
|
||||||
|
|
||||||
Widget? child;
|
Widget? child;
|
||||||
if (mainEntry.isMultiPage) {
|
if (mainEntry.isMultiPage) {
|
||||||
|
@ -108,7 +110,7 @@ class ViewerTopOverlay extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final quickActions = settings.viewerQuickActions.where(_canDo).take(availableCount).toList();
|
final quickActions = settings.viewerQuickActions.where(_canDo).take(availableCount - 1).toList();
|
||||||
final inAppActions = EntryActions.inApp.where((action) => !quickActions.contains(action)).where(_canDo).toList();
|
final inAppActions = EntryActions.inApp.where((action) => !quickActions.contains(action)).where(_canDo).toList();
|
||||||
final externalAppActions = EntryActions.externalApp.where(_canDo).toList();
|
final externalAppActions = EntryActions.externalApp.where(_canDo).toList();
|
||||||
final buttonRow = _TopOverlayRow(
|
final buttonRow = _TopOverlayRow(
|
||||||
|
@ -157,8 +159,6 @@ class _TopOverlayRow extends StatelessWidget {
|
||||||
required this.onActionSelected,
|
required this.onActionSelected,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
static const double padding = 8;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
|
@ -228,7 +228,7 @@ class _TopOverlayRow extends StatelessWidget {
|
||||||
}
|
}
|
||||||
return child != null
|
return child != null
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsetsDirectional.only(end: padding),
|
padding: const EdgeInsetsDirectional.only(end: ViewerTopOverlay.innerPadding),
|
||||||
child: OverlayButton(
|
child: OverlayButton(
|
||||||
scale: scale,
|
scale: scale,
|
||||||
child: child,
|
child: child,
|
||||||
|
|
Loading…
Reference in a new issue