setting tab abr long press url copy

This commit is contained in:
Fabian Freund
2026-03-24 17:32:02 +01:00
parent 160a258fea
commit 87d6e81609
11 changed files with 91 additions and 5 deletions
@@ -42,7 +42,7 @@ final class BrowserAddonServiceProvider
} }
String _$browserAddonServiceHash() => String _$browserAddonServiceHash() =>
r'6f07d93576a0816bf1b9e1b36397b89b7cacf43f'; r'1485fd056ce32e142e342e920affb82a5c77a370';
abstract class _$BrowserAddonService extends $Notifier<void> { abstract class _$BrowserAddonService extends $Notifier<void> {
void build(); void build();
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:skeletonizer/skeletonizer.dart'; import 'package:skeletonizer/skeletonizer.dart';
@@ -64,6 +65,7 @@ class CompactAppBarTitle extends ConsumerWidget {
isTabTunneled: isTabTunneled:
isTabTuneledAsync.hasValue && isTabTuneledAsync.value == true, isTabTuneledAsync.hasValue && isTabTuneledAsync.value == true,
showSiteSettingsBadge: showSiteSettingsBadge, showSiteSettingsBadge: showSiteSettingsBadge,
longPressUrlCopy: settings.tabBarLongPressUrlCopy,
onSiteSettingsTap: () { onSiteSettingsTap: () {
ref ref
.read(bottomSheetControllerProvider.notifier) .read(bottomSheetControllerProvider.notifier)
@@ -89,6 +91,7 @@ class CompactAppBarTitleView extends StatelessWidget {
required this.onSiteSettingsTap, required this.onSiteSettingsTap,
required this.onTitleTap, required this.onTitleTap,
this.tabIcon, this.tabIcon,
this.longPressUrlCopy = true,
}); });
final TabState tabState; final TabState tabState;
@@ -97,6 +100,7 @@ class CompactAppBarTitleView extends StatelessWidget {
final VoidCallback onSiteSettingsTap; final VoidCallback onSiteSettingsTap;
final VoidCallback onTitleTap; final VoidCallback onTitleTap;
final Widget? tabIcon; final Widget? tabIcon;
final bool longPressUrlCopy;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -168,6 +172,13 @@ class CompactAppBarTitleView extends StatelessWidget {
style: theme.textTheme.bodyMedium?.copyWith( style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurface, color: theme.colorScheme.onSurface,
), ),
onTooltipTriggered: longPressUrlCopy
? () async {
await Clipboard.setData(
ClipboardData(text: tabState.url.toString()),
);
}
: null,
), ),
), ),
], ],
@@ -209,6 +220,7 @@ class AppBarTitle extends ConsumerWidget {
isTabTunneled: isTabTunneled:
isTabTuneledAsync.hasValue && isTabTuneledAsync.value == true, isTabTuneledAsync.hasValue && isTabTuneledAsync.value == true,
showSiteSettingsBadge: showSiteSettingsBadge, showSiteSettingsBadge: showSiteSettingsBadge,
longPressUrlCopy: settings.tabBarLongPressUrlCopy,
onSiteSettingsTap: () { onSiteSettingsTap: () {
ref ref
.read(bottomSheetControllerProvider.notifier) .read(bottomSheetControllerProvider.notifier)
@@ -233,6 +245,7 @@ class AppBarTitleView extends StatelessWidget {
required this.showSiteSettingsBadge, required this.showSiteSettingsBadge,
required this.onSiteSettingsTap, required this.onSiteSettingsTap,
required this.onTitleTap, required this.onTitleTap,
required this.longPressUrlCopy,
this.tabIcon, this.tabIcon,
}); });
@@ -242,6 +255,7 @@ class AppBarTitleView extends StatelessWidget {
final VoidCallback onSiteSettingsTap; final VoidCallback onSiteSettingsTap;
final VoidCallback onTitleTap; final VoidCallback onTitleTap;
final Widget? tabIcon; final Widget? tabIcon;
final bool longPressUrlCopy;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -333,6 +347,13 @@ class AppBarTitleView extends StatelessWidget {
style: theme.textTheme.bodyMedium?.copyWith( style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurface, color: theme.colorScheme.onSurface,
), ),
onTooltipTriggered: longPressUrlCopy
? () async {
await Clipboard.setData(
ClipboardData(text: tabState.url.toString()),
);
}
: null,
), ),
), ),
], ],
@@ -37,6 +37,7 @@ class ToolbarLayoutContent extends StatelessWidget {
_TabBarPositionSection(), _TabBarPositionSection(),
_TabBarLayoutModeSection(), _TabBarLayoutModeSection(),
_AutoHideTabBarTile(), _AutoHideTabBarTile(),
_TabBarLongPressUrlCopyTile(),
SettingSection(name: 'Contextual Toolbar'), SettingSection(name: 'Contextual Toolbar'),
_ShowContextualTabBarTile(), _ShowContextualTabBarTile(),
_CustomizeToolbarButtonsTile(), _CustomizeToolbarButtonsTile(),
@@ -423,6 +424,36 @@ class _BottomSheetTabViewTile extends HookConsumerWidget {
} }
} }
class _TabBarLongPressUrlCopyTile extends HookConsumerWidget {
const _TabBarLongPressUrlCopyTile();
@override
Widget build(BuildContext context, WidgetRef ref) {
final tabBarLongPressUrlCopy = ref.watch(
generalSettingsWithDefaultsProvider.select(
(s) => s.tabBarLongPressUrlCopy,
),
);
return SwitchListTile.adaptive(
title: const Text('Long Press URL to Copy'),
subtitle: const Text(
'Copy the page URL to clipboard when long pressing the address bar',
),
secondary: const Icon(MdiIcons.contentCopy),
value: tabBarLongPressUrlCopy,
onChanged: (value) async {
await ref
.read(saveGeneralSettingsControllerProvider.notifier)
.save(
(currentSettings) =>
currentSettings.copyWith.tabBarLongPressUrlCopy(value),
);
},
);
}
}
class _TabListShowFaviconsTile extends HookConsumerWidget { class _TabListShowFaviconsTile extends HookConsumerWidget {
const _TabListShowFaviconsTile(); const _TabListShowFaviconsTile();
@@ -355,6 +355,7 @@ class _RegularPreviewTitle extends StatelessWidget {
onSiteSettingsTap: _noop, onSiteSettingsTap: _noop,
onTitleTap: _noop, onTitleTap: _noop,
tabIcon: const Icon(MdiIcons.web, size: 24), tabIcon: const Icon(MdiIcons.web, size: 24),
longPressUrlCopy: false,
); );
} }
} }
@@ -224,7 +224,7 @@ final class SmallWebSessionControllerProvider
} }
String _$smallWebSessionControllerHash() => String _$smallWebSessionControllerHash() =>
r'90680807b38de577e3322941b47792952d66428a'; r'ee57d24b33b5a7dffe668fe3ddd2b77d84f58eae';
abstract class _$SmallWebSessionController abstract class _$SmallWebSessionController
extends $Notifier<AsyncValue<SmallWebSessionState>> { extends $Notifier<AsyncValue<SmallWebSessionState>> {
@@ -115,6 +115,7 @@ class GeneralSettings with FastEquatable {
final int? urlCleanerLastCheckEpochMs; final int? urlCleanerLastCheckEpochMs;
final bool urlCleanerLastUpdateWasAuto; final bool urlCleanerLastUpdateWasAuto;
final TabType smallWebTabType; final TabType smallWebTabType;
final bool tabBarLongPressUrlCopy;
final bool unshortenerEnabled; final bool unshortenerEnabled;
final String unshortenerToken; final String unshortenerToken;
@@ -164,6 +165,7 @@ class GeneralSettings with FastEquatable {
required this.urlCleanerLastCheckEpochMs, required this.urlCleanerLastCheckEpochMs,
required this.urlCleanerLastUpdateWasAuto, required this.urlCleanerLastUpdateWasAuto,
required this.smallWebTabType, required this.smallWebTabType,
required this.tabBarLongPressUrlCopy,
required this.unshortenerEnabled, required this.unshortenerEnabled,
required this.unshortenerToken, required this.unshortenerToken,
}); });
@@ -214,6 +216,7 @@ class GeneralSettings with FastEquatable {
this.urlCleanerLastCheckEpochMs, this.urlCleanerLastCheckEpochMs,
bool? urlCleanerLastUpdateWasAuto, bool? urlCleanerLastUpdateWasAuto,
TabType? smallWebTabType, TabType? smallWebTabType,
bool? tabBarLongPressUrlCopy,
bool? unshortenerEnabled, bool? unshortenerEnabled,
String? unshortenerToken, String? unshortenerToken,
}) : themeMode = themeMode ?? ThemeMode.dark, }) : themeMode = themeMode ?? ThemeMode.dark,
@@ -271,6 +274,7 @@ class GeneralSettings with FastEquatable {
urlCleanerAutoUpdate = urlCleanerAutoUpdate ?? false, urlCleanerAutoUpdate = urlCleanerAutoUpdate ?? false,
urlCleanerLastUpdateWasAuto = urlCleanerLastUpdateWasAuto ?? false, urlCleanerLastUpdateWasAuto = urlCleanerLastUpdateWasAuto ?? false,
smallWebTabType = smallWebTabType ?? TabType.private, smallWebTabType = smallWebTabType ?? TabType.private,
tabBarLongPressUrlCopy = tabBarLongPressUrlCopy ?? true,
unshortenerEnabled = unshortenerEnabled ?? false, unshortenerEnabled = unshortenerEnabled ?? false,
unshortenerToken = unshortenerToken ?? ''; unshortenerToken = unshortenerToken ?? '';
@@ -341,6 +345,7 @@ class GeneralSettings with FastEquatable {
urlCleanerLastCheckEpochMs, urlCleanerLastCheckEpochMs,
urlCleanerLastUpdateWasAuto, urlCleanerLastUpdateWasAuto,
smallWebTabType, smallWebTabType,
tabBarLongPressUrlCopy,
unshortenerEnabled, unshortenerEnabled,
unshortenerToken, unshortenerToken,
]; ];
@@ -115,6 +115,8 @@ abstract class _$GeneralSettingsCWProxy {
GeneralSettings smallWebTabType(TabType smallWebTabType); GeneralSettings smallWebTabType(TabType smallWebTabType);
GeneralSettings tabBarLongPressUrlCopy(bool tabBarLongPressUrlCopy);
GeneralSettings unshortenerEnabled(bool unshortenerEnabled); GeneralSettings unshortenerEnabled(bool unshortenerEnabled);
GeneralSettings unshortenerToken(String unshortenerToken); GeneralSettings unshortenerToken(String unshortenerToken);
@@ -172,6 +174,7 @@ abstract class _$GeneralSettingsCWProxy {
int? urlCleanerLastCheckEpochMs, int? urlCleanerLastCheckEpochMs,
bool urlCleanerLastUpdateWasAuto, bool urlCleanerLastUpdateWasAuto,
TabType smallWebTabType, TabType smallWebTabType,
bool tabBarLongPressUrlCopy,
bool unshortenerEnabled, bool unshortenerEnabled,
String unshortenerToken, String unshortenerToken,
}); });
@@ -376,6 +379,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
GeneralSettings smallWebTabType(TabType smallWebTabType) => GeneralSettings smallWebTabType(TabType smallWebTabType) =>
call(smallWebTabType: smallWebTabType); call(smallWebTabType: smallWebTabType);
@override
GeneralSettings tabBarLongPressUrlCopy(bool tabBarLongPressUrlCopy) =>
call(tabBarLongPressUrlCopy: tabBarLongPressUrlCopy);
@override @override
GeneralSettings unshortenerEnabled(bool unshortenerEnabled) => GeneralSettings unshortenerEnabled(bool unshortenerEnabled) =>
call(unshortenerEnabled: unshortenerEnabled); call(unshortenerEnabled: unshortenerEnabled);
@@ -439,6 +446,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
Object? urlCleanerLastCheckEpochMs = const $CopyWithPlaceholder(), Object? urlCleanerLastCheckEpochMs = const $CopyWithPlaceholder(),
Object? urlCleanerLastUpdateWasAuto = const $CopyWithPlaceholder(), Object? urlCleanerLastUpdateWasAuto = const $CopyWithPlaceholder(),
Object? smallWebTabType = const $CopyWithPlaceholder(), Object? smallWebTabType = const $CopyWithPlaceholder(),
Object? tabBarLongPressUrlCopy = const $CopyWithPlaceholder(),
Object? unshortenerEnabled = const $CopyWithPlaceholder(), Object? unshortenerEnabled = const $CopyWithPlaceholder(),
Object? unshortenerToken = const $CopyWithPlaceholder(), Object? unshortenerToken = const $CopyWithPlaceholder(),
}) { }) {
@@ -707,6 +715,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
? _value.smallWebTabType ? _value.smallWebTabType
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: smallWebTabType as TabType, : smallWebTabType as TabType,
tabBarLongPressUrlCopy:
tabBarLongPressUrlCopy == const $CopyWithPlaceholder() ||
tabBarLongPressUrlCopy == null
? _value.tabBarLongPressUrlCopy
// ignore: cast_nullable_to_non_nullable
: tabBarLongPressUrlCopy as bool,
unshortenerEnabled: unshortenerEnabled:
unshortenerEnabled == const $CopyWithPlaceholder() || unshortenerEnabled == const $CopyWithPlaceholder() ||
unshortenerEnabled == null unshortenerEnabled == null
@@ -826,6 +840,7 @@ GeneralSettings _$GeneralSettingsFromJson(
_$TabTypeEnumMap, _$TabTypeEnumMap,
json['smallWebTabType'], json['smallWebTabType'],
), ),
tabBarLongPressUrlCopy: json['tabBarLongPressUrlCopy'] as bool?,
unshortenerEnabled: json['unshortenerEnabled'] as bool?, unshortenerEnabled: json['unshortenerEnabled'] as bool?,
unshortenerToken: json['unshortenerToken'] as String?, unshortenerToken: json['unshortenerToken'] as String?,
); );
@@ -889,6 +904,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
'urlCleanerLastCheckEpochMs': instance.urlCleanerLastCheckEpochMs, 'urlCleanerLastCheckEpochMs': instance.urlCleanerLastCheckEpochMs,
'urlCleanerLastUpdateWasAuto': instance.urlCleanerLastUpdateWasAuto, 'urlCleanerLastUpdateWasAuto': instance.urlCleanerLastUpdateWasAuto,
'smallWebTabType': _$TabTypeEnumMap[instance.smallWebTabType]!, 'smallWebTabType': _$TabTypeEnumMap[instance.smallWebTabType]!,
'tabBarLongPressUrlCopy': instance.tabBarLongPressUrlCopy,
'unshortenerEnabled': instance.unshortenerEnabled, 'unshortenerEnabled': instance.unshortenerEnabled,
'unshortenerToken': instance.unshortenerToken, 'unshortenerToken': instance.unshortenerToken,
}; };
@@ -200,4 +200,4 @@ final class BackupListProvider
} }
} }
String _$backupListHash() => r'cdce1b5f195f0c9b72132f7da0c9d173dfc119eb'; String _$backupListHash() => r'527bfdab7b537b08764ff77dd69de14d38846d41';
@@ -217,6 +217,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
DriftSqlType.string, DriftSqlType.string,
db.typeMapping, db.typeMapping,
), ),
'tabBarLongPressUrlCopy': settings['tabBarLongPressUrlCopy']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'unshortenerEnabled': settings['unshortenerEnabled']?.readAs( 'unshortenerEnabled': settings['unshortenerEnabled']?.readAs(
DriftSqlType.bool, DriftSqlType.bool,
db.typeMapping, db.typeMapping,
@@ -41,7 +41,7 @@ final class UserBackupServiceProvider
} }
} }
String _$userBackupServiceHash() => r'74cd6fd9818a8350a91b1225d904e23f48bc9e30'; String _$userBackupServiceHash() => r'3746ae59d490e25a44815c125f30cd0981de555d';
abstract class _$UserBackupService extends $Notifier<void> { abstract class _$UserBackupService extends $Notifier<void> {
void build(); void build();
@@ -25,13 +25,21 @@ class UriBreadcrumb extends StatelessWidget {
final Uri uri; final Uri uri;
final Widget? icon; final Widget? icon;
final TextStyle? style; final TextStyle? style;
final void Function()? onTooltipTriggered;
const UriBreadcrumb({super.key, required this.uri, this.icon, this.style}); const UriBreadcrumb({
super.key,
required this.uri,
this.icon,
this.style,
this.onTooltipTriggered,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Tooltip( return Tooltip(
message: uri.toString(), message: uri.toString(),
onTriggered: onTooltipTriggered,
child: DefaultTextStyle( child: DefaultTextStyle(
style: style ?? DefaultTextStyle.of(context).style, style: style ?? DefaultTextStyle.of(context).style,
child: FadingScroll( child: FadingScroll(