improve the users bottom sheet and button placements
This commit is contained in:
+17
-176
@@ -31,7 +31,6 @@ import 'package:weblibre/features/geckoview/domain/controllers/bottom_sheet.dart
|
||||
import 'package:weblibre/features/geckoview/domain/entities/states/readerable.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/web_extensions_state.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/repositories/tab.dart';
|
||||
@@ -41,8 +40,8 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/contro
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/browser_modules/app_bar_title.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/extension_shortcut_menu.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/history_menu.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/menu_item_buttons.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/navigation_buttons.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_creation_menu.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_menu.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart';
|
||||
@@ -54,6 +53,7 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'
|
||||
import 'package:weblibre/features/geckoview/features/tabs/utils/container_colors.dart';
|
||||
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
|
||||
import 'package:weblibre/features/user/data/models/general_settings.dart';
|
||||
import 'package:weblibre/features/user/domain/presentation/dialogs/quit_browser_dialog.dart';
|
||||
import 'package:weblibre/features/user/domain/providers.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||
import 'package:weblibre/presentation/hooks/cached_future.dart';
|
||||
@@ -61,6 +61,7 @@ import 'package:weblibre/presentation/hooks/menu_controller.dart';
|
||||
import 'package:weblibre/presentation/icons/tor_icons.dart';
|
||||
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
|
||||
import 'package:weblibre/presentation/widgets/url_icon.dart';
|
||||
import 'package:weblibre/utils/exit_app.dart';
|
||||
|
||||
class BrowserTopAppBar extends HookConsumerWidget {
|
||||
final bool showMainToolbar;
|
||||
@@ -372,10 +373,7 @@ class BrowserTabBar extends HookConsumerWidget {
|
||||
showLongPressMenu: true,
|
||||
),
|
||||
if (showMainToolbarNavigationButton)
|
||||
NavigationMenuButton(
|
||||
selectedTabId: selectedTabId,
|
||||
showNavigationButtons: true,
|
||||
),
|
||||
NavigationMenuButton(selectedTabId: selectedTabId),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -441,10 +439,7 @@ class ContextualToolbar extends HookConsumerWidget {
|
||||
displayedSheet: displayedSheet,
|
||||
showLongPressMenu: false,
|
||||
),
|
||||
NavigationMenuButton(
|
||||
selectedTabId: selectedTabId,
|
||||
showNavigationButtons: false,
|
||||
),
|
||||
NavigationMenuButton(selectedTabId: selectedTabId),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -623,13 +618,8 @@ class ShareMenuButton extends HookConsumerWidget {
|
||||
|
||||
class NavigationMenuButton extends HookConsumerWidget {
|
||||
final String? selectedTabId;
|
||||
final bool showNavigationButtons;
|
||||
|
||||
const NavigationMenuButton({
|
||||
super.key,
|
||||
required this.selectedTabId,
|
||||
required this.showNavigationButtons,
|
||||
});
|
||||
const NavigationMenuButton({super.key, required this.selectedTabId});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -670,6 +660,17 @@ class NavigationMenuButton extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final result = await showQuitBrowserDialog(context);
|
||||
|
||||
if (result == true && context.mounted) {
|
||||
await exitApp(ProviderScope.containerOf(context));
|
||||
}
|
||||
},
|
||||
leadingIcon: const Icon(MdiIcons.power),
|
||||
child: const Text('Quit Browser'),
|
||||
),
|
||||
const Divider(),
|
||||
Consumer(
|
||||
builder: (context, childRef, child) {
|
||||
@@ -854,171 +855,11 @@ class NavigationMenuButton extends HookConsumerWidget {
|
||||
leadingIcon: const Icon(Icons.rss_feed),
|
||||
child: const Text('Feeds'),
|
||||
),
|
||||
const Divider(),
|
||||
if (selectedTabId != null)
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(tabId: selectedTabId).notifier,
|
||||
);
|
||||
|
||||
await controller.reload();
|
||||
hamburgerMenuController.close();
|
||||
},
|
||||
leadingIcon: const Icon(Icons.refresh),
|
||||
child: const Text('Reload'),
|
||||
),
|
||||
if (selectedTabId != null && showNavigationButtons) ...[
|
||||
const Divider(),
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history = ref.watch(
|
||||
tabStateProvider(
|
||||
selectedTabId,
|
||||
).select((value) => value?.historyState),
|
||||
);
|
||||
|
||||
final isLoading = ref.watch(
|
||||
selectedTabStateProvider.select(
|
||||
(state) => state?.isLoading ?? false,
|
||||
),
|
||||
);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: NavigateBackButton(
|
||||
selectedTabId: selectedTabId,
|
||||
isLoading: isLoading,
|
||||
menuControllerToClose: hamburgerMenuController,
|
||||
canGoBack: history?.canGoBack == true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 48, child: VerticalDivider()),
|
||||
Expanded(
|
||||
child: NavigateForwardButton(
|
||||
selectedTabId: selectedTabId,
|
||||
menuControllerToClose: hamburgerMenuController,
|
||||
canGoForward: history?.canGoForward == true,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NavigateForwardButton extends HookConsumerWidget {
|
||||
const NavigateForwardButton({
|
||||
super.key,
|
||||
required this.selectedTabId,
|
||||
this.menuControllerToClose,
|
||||
this.canGoForward = true,
|
||||
});
|
||||
|
||||
final String? selectedTabId;
|
||||
final MenuController? menuControllerToClose;
|
||||
final bool canGoForward;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final historyMenuController = useMenuController();
|
||||
|
||||
return HistoryMenu(
|
||||
selectedTabId: selectedTabId,
|
||||
controller: historyMenuController,
|
||||
direction: HistoryMenuDirection.forward,
|
||||
child: IconButton(
|
||||
onPressed: canGoForward
|
||||
? () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(tabId: selectedTabId).notifier,
|
||||
);
|
||||
|
||||
await controller.goForward();
|
||||
menuControllerToClose?.close();
|
||||
}
|
||||
: null,
|
||||
onLongPress: canGoForward
|
||||
? () {
|
||||
if (!historyMenuController.isOpen) {
|
||||
historyMenuController.open();
|
||||
}
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.arrow_forward),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NavigateBackButton extends HookConsumerWidget {
|
||||
const NavigateBackButton({
|
||||
super.key,
|
||||
required this.selectedTabId,
|
||||
required this.isLoading,
|
||||
this.menuControllerToClose,
|
||||
this.canGoBack = true,
|
||||
});
|
||||
|
||||
final String? selectedTabId;
|
||||
final bool isLoading;
|
||||
final MenuController? menuControllerToClose;
|
||||
final bool canGoBack;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final historyMenuController = useMenuController();
|
||||
|
||||
return HistoryMenu(
|
||||
selectedTabId: selectedTabId,
|
||||
controller: historyMenuController,
|
||||
direction: HistoryMenuDirection.back,
|
||||
child: IconButton(
|
||||
onPressed: (canGoBack || isLoading)
|
||||
? () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(tabId: selectedTabId).notifier,
|
||||
);
|
||||
|
||||
final isReaderActive = ref.read(
|
||||
selectedTabStateProvider.select(
|
||||
(state) => state?.readerableState.active ?? false,
|
||||
),
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
await controller.stopLoading();
|
||||
} else if (isReaderActive) {
|
||||
await ref
|
||||
.read(readerableScreenControllerProvider.notifier)
|
||||
.toggleReaderView(false);
|
||||
} else {
|
||||
await controller.goBack();
|
||||
}
|
||||
|
||||
menuControllerToClose?.close();
|
||||
}
|
||||
: null,
|
||||
onLongPress: (canGoBack && !isLoading)
|
||||
? () {
|
||||
if (!historyMenuController.isOpen) {
|
||||
historyMenuController.open();
|
||||
}
|
||||
}
|
||||
: null,
|
||||
icon: isLoading
|
||||
? const Icon(Icons.close)
|
||||
: const Icon(Icons.arrow_back),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AddTabButton extends HookConsumerWidget {
|
||||
const AddTabButton();
|
||||
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/history_menu.dart';
|
||||
import 'package:weblibre/features/geckoview/features/readerview/presentation/controllers/readerable.dart';
|
||||
import 'package:weblibre/presentation/hooks/menu_controller.dart';
|
||||
|
||||
class NavigateForwardButton extends HookConsumerWidget {
|
||||
const NavigateForwardButton({
|
||||
super.key,
|
||||
required this.selectedTabId,
|
||||
this.menuControllerToClose,
|
||||
this.canGoForward = true,
|
||||
});
|
||||
|
||||
final String? selectedTabId;
|
||||
final MenuController? menuControllerToClose;
|
||||
final bool canGoForward;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final historyMenuController = useMenuController();
|
||||
|
||||
return HistoryMenu(
|
||||
selectedTabId: selectedTabId,
|
||||
controller: historyMenuController,
|
||||
direction: HistoryMenuDirection.forward,
|
||||
child: IconButton(
|
||||
onPressed: canGoForward
|
||||
? () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(tabId: selectedTabId).notifier,
|
||||
);
|
||||
|
||||
await controller.goForward();
|
||||
menuControllerToClose?.close();
|
||||
}
|
||||
: null,
|
||||
onLongPress: canGoForward
|
||||
? () {
|
||||
if (!historyMenuController.isOpen) {
|
||||
historyMenuController.open();
|
||||
}
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.arrow_forward),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NavigateBackButton extends HookConsumerWidget {
|
||||
const NavigateBackButton({
|
||||
super.key,
|
||||
required this.selectedTabId,
|
||||
required this.isLoading,
|
||||
this.menuControllerToClose,
|
||||
this.canGoBack = true,
|
||||
});
|
||||
|
||||
final String? selectedTabId;
|
||||
final bool isLoading;
|
||||
final MenuController? menuControllerToClose;
|
||||
final bool canGoBack;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final historyMenuController = useMenuController();
|
||||
|
||||
return HistoryMenu(
|
||||
selectedTabId: selectedTabId,
|
||||
controller: historyMenuController,
|
||||
direction: HistoryMenuDirection.back,
|
||||
child: IconButton(
|
||||
onPressed: (canGoBack || isLoading)
|
||||
? () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(tabId: selectedTabId).notifier,
|
||||
);
|
||||
|
||||
final isReaderActive = ref.read(
|
||||
selectedTabStateProvider.select(
|
||||
(state) => state?.readerableState.active ?? false,
|
||||
),
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
await controller.stopLoading();
|
||||
} else if (isReaderActive) {
|
||||
await ref
|
||||
.read(readerableScreenControllerProvider.notifier)
|
||||
.toggleReaderView(false);
|
||||
} else {
|
||||
await controller.goBack();
|
||||
}
|
||||
|
||||
menuControllerToClose?.close();
|
||||
}
|
||||
: null,
|
||||
onLongPress: (canGoBack && !isLoading)
|
||||
? () {
|
||||
if (!historyMenuController.isOpen) {
|
||||
historyMenuController.open();
|
||||
}
|
||||
}
|
||||
: null,
|
||||
icon: isLoading
|
||||
? const Icon(Icons.close)
|
||||
: const Icon(Icons.arrow_back),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,9 +31,11 @@ import 'package:nullability/nullability.dart';
|
||||
import 'package:weblibre/core/routing/routes.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/controllers/bottom_sheet.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/desktop_mode.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/menu_item_buttons.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/navigation_buttons.dart';
|
||||
import 'package:weblibre/features/geckoview/features/find_in_page/presentation/controllers/find_in_page.dart';
|
||||
import 'package:weblibre/features/geckoview/features/readerview/presentation/controllers/readerable.dart';
|
||||
import 'package:weblibre/features/geckoview/features/readerview/presentation/widgets/reader_button.dart';
|
||||
@@ -451,6 +453,55 @@ class TabMenu extends HookConsumerWidget {
|
||||
leadingIcon: const Icon(MdiIcons.tabMinus),
|
||||
child: const Text('Close Tab'),
|
||||
),
|
||||
const Divider(),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final sessionController = ref.read(
|
||||
tabSessionProvider(tabId: selectedTabId).notifier,
|
||||
);
|
||||
|
||||
await sessionController.reload();
|
||||
controller.close();
|
||||
},
|
||||
leadingIcon: const Icon(Icons.refresh),
|
||||
child: const Text('Reload'),
|
||||
),
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history = ref.watch(
|
||||
tabStateProvider(
|
||||
selectedTabId,
|
||||
).select((value) => value?.historyState),
|
||||
);
|
||||
|
||||
final isLoading = ref.watch(
|
||||
selectedTabStateProvider.select(
|
||||
(state) => state?.isLoading ?? false,
|
||||
),
|
||||
);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: NavigateBackButton(
|
||||
selectedTabId: selectedTabId,
|
||||
isLoading: isLoading,
|
||||
menuControllerToClose: controller,
|
||||
canGoBack: history?.canGoBack == true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 48, child: VerticalDivider()),
|
||||
Expanded(
|
||||
child: NavigateForwardButton(
|
||||
selectedTabId: selectedTabId,
|
||||
menuControllerToClose: controller,
|
||||
canGoForward: history?.canGoForward == true,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:weblibre/core/filesystem.dart';
|
||||
import 'package:weblibre/core/routing/routes.dart';
|
||||
import 'package:weblibre/features/user/domain/presentation/dialogs/quit_browser_dialog.dart';
|
||||
import 'package:weblibre/domain/entities/profile.dart';
|
||||
import 'package:weblibre/features/user/domain/presentation/utils/profile_switch_handler.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/profile.dart';
|
||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||
import 'package:weblibre/utils/exit_app.dart';
|
||||
|
||||
/// Bottom sheet widget to select a user profile.
|
||||
class SelectProfileDialog extends HookConsumerWidget {
|
||||
@@ -44,30 +45,38 @@ class SelectProfileDialog extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
'Users',
|
||||
'Select user',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: 24),
|
||||
usersAsync.when(
|
||||
skipLoadingOnReload: true,
|
||||
data: (profiles) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: profiles.map((profile) {
|
||||
final isSelected =
|
||||
filesystem.selectedProfile == profile.uuidValue;
|
||||
|
||||
return ListTile(
|
||||
key: ValueKey(profile.id),
|
||||
enabled: !isSelected,
|
||||
trailing:
|
||||
!isSelected ? const Icon(MdiIcons.accountSwitch) : null,
|
||||
title: Text(profile.name),
|
||||
subtitle: isSelected ? const Text('Active') : null,
|
||||
data: (profiles) => Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 24,
|
||||
runSpacing: 16,
|
||||
children: [
|
||||
...profiles.map(
|
||||
(profile) => _ProfileAvatar(
|
||||
profile: profile,
|
||||
isActive: filesystem.selectedProfile == profile.uuidValue,
|
||||
onTap: () async {
|
||||
await handleSwitchProfile(context, ref, profile);
|
||||
},
|
||||
onLongPress: () async {
|
||||
await EditProfileRoute(
|
||||
profile: jsonEncode(profile.toJson()),
|
||||
).push(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
_AddProfileAvatar(
|
||||
onTap: () async {
|
||||
await handleSwitchProfile(context, ref, profile);
|
||||
await CreateProfileRoute().push(context);
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
error: (error, stackTrace) => Center(
|
||||
child: FailureWidget(
|
||||
@@ -77,31 +86,13 @@ class SelectProfileDialog extends HookConsumerWidget {
|
||||
),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
icon: const Icon(MdiIcons.power),
|
||||
iconAlignment: IconAlignment.start,
|
||||
label: const Text('Quit Browser'),
|
||||
onPressed: () async {
|
||||
final result = await showQuitBrowserDialog(context);
|
||||
|
||||
if (result == true) {
|
||||
await exitApp(ref.container);
|
||||
}
|
||||
},
|
||||
),
|
||||
TextButton.icon(
|
||||
icon: const Icon(MdiIcons.accountGroup),
|
||||
iconAlignment: IconAlignment.end,
|
||||
label: const Text('Manage'),
|
||||
onPressed: () async {
|
||||
await ProfileListRoute().push(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 24),
|
||||
TextButton.icon(
|
||||
onPressed: () async {
|
||||
await ProfileListRoute().push(context);
|
||||
},
|
||||
icon: const Icon(MdiIcons.accountGroup),
|
||||
label: const Text('Manage Profiles'),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -109,3 +100,105 @@ class SelectProfileDialog extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ProfileAvatar extends StatelessWidget {
|
||||
final Profile profile;
|
||||
final bool isActive;
|
||||
final VoidCallback onTap;
|
||||
final VoidCallback onLongPress;
|
||||
|
||||
const _ProfileAvatar({
|
||||
required this.profile,
|
||||
required this.isActive,
|
||||
required this.onTap,
|
||||
required this.onLongPress,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 28,
|
||||
backgroundColor: isActive
|
||||
? colorScheme.primary
|
||||
: colorScheme.surfaceContainerHighest,
|
||||
child: Icon(
|
||||
Icons.person,
|
||||
size: 24,
|
||||
color: isActive
|
||||
? colorScheme.onPrimary
|
||||
: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
width: 72,
|
||||
child: Text(
|
||||
profile.name,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AddProfileAvatar extends StatelessWidget {
|
||||
final VoidCallback onTap;
|
||||
|
||||
const _AddProfileAvatar({required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 28,
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: colorScheme.onSurfaceVariant,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: colorScheme.outline),
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
size: 24,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
width: 72,
|
||||
child: Text(
|
||||
'Add user',
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user