mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-14 17:55:58 -07:00
fix: Improve dPad navigation buttons (#605)
This commit is contained in:
parent
e9f32f522b
commit
493f40645c
3 changed files with 91 additions and 61 deletions
|
|
@ -14,6 +14,7 @@ import 'package:fladder/screens/shared/animated_fade_size.dart';
|
||||||
import 'package:fladder/screens/shared/fladder_logo.dart';
|
import 'package:fladder/screens/shared/fladder_logo.dart';
|
||||||
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
|
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
|
||||||
import 'package:fladder/widgets/keyboard/slide_in_keyboard.dart';
|
import 'package:fladder/widgets/keyboard/slide_in_keyboard.dart';
|
||||||
|
import 'package:fladder/widgets/navigation_scaffold/components/adaptive_fab.dart';
|
||||||
import 'package:fladder/widgets/navigation_scaffold/components/fladder_app_bar.dart';
|
import 'package:fladder/widgets/navigation_scaffold/components/fladder_app_bar.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
|
|
@ -53,20 +54,22 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
spacing: 16,
|
spacing: 16,
|
||||||
children: [
|
children: [
|
||||||
if (!AdaptiveLayout.of(context).isDesktop)
|
if (AdaptiveLayout.of(context).isDesktop)
|
||||||
FloatingActionButton(
|
AdaptiveFab(
|
||||||
|
context: context,
|
||||||
key: const Key("edit_user_button"),
|
key: const Key("edit_user_button"),
|
||||||
heroTag: "edit_user_button",
|
heroTag: "edit_user_button",
|
||||||
backgroundColor: editUsersMode ? Theme.of(context).colorScheme.errorContainer : null,
|
backgroundColor: editUsersMode ? Theme.of(context).colorScheme.errorContainer : null,
|
||||||
child: const Icon(IconsaxPlusLinear.edit_2),
|
child: const Icon(IconsaxPlusLinear.edit_2),
|
||||||
onPressed: () => setState(() => editUsersMode = !editUsersMode),
|
onPressed: () => setState(() => editUsersMode = !editUsersMode),
|
||||||
),
|
).normal,
|
||||||
FloatingActionButton(
|
AdaptiveFab(
|
||||||
|
context: context,
|
||||||
key: const Key("new_user_button"),
|
key: const Key("new_user_button"),
|
||||||
heroTag: "new_user_button",
|
heroTag: "new_user_button",
|
||||||
child: const Icon(IconsaxPlusLinear.add_square),
|
child: const Icon(IconsaxPlusLinear.add_square),
|
||||||
onPressed: () => ref.read(authProvider.notifier).addNewUser(),
|
onPressed: () => ref.read(authProvider.notifier).addNewUser(),
|
||||||
),
|
).normal,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
_ => null,
|
_ => null,
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||||
import 'package:iconsax_plus/iconsax_plus.dart';
|
import 'package:iconsax_plus/iconsax_plus.dart';
|
||||||
|
|
||||||
|
import 'package:fladder/screens/shared/flat_button.dart';
|
||||||
|
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:fladder/util/sticky_header_text.dart';
|
import 'package:fladder/widgets/shared/ensure_visible.dart';
|
||||||
|
|
||||||
class ExpandingOverview extends ConsumerStatefulWidget {
|
class ExpandingOverview extends ConsumerStatefulWidget {
|
||||||
final String text;
|
final String text;
|
||||||
|
|
@ -29,58 +31,68 @@ class _ExpandingOverviewState extends ConsumerState<ExpandingOverview> {
|
||||||
final color = Theme.of(context).colorScheme.onSurface;
|
final color = Theme.of(context).colorScheme.onSurface;
|
||||||
const int maxLength = 200;
|
const int maxLength = 200;
|
||||||
final bool canExpand = widget.text.length > maxLength;
|
final bool canExpand = widget.text.length > maxLength;
|
||||||
return AnimatedSize(
|
final isDpad = AdaptiveLayout.inputDeviceOf(context) == InputDevice.dPad;
|
||||||
duration: const Duration(milliseconds: 250),
|
return FlatButton(
|
||||||
alignment: Alignment.topCenter,
|
onTap: canExpand && isDpad ? toggleState : null,
|
||||||
child: Column(
|
onFocusChange: (value) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
if (value) {
|
||||||
mainAxisSize: MainAxisSize.min,
|
context.ensureVisible();
|
||||||
children: [
|
}
|
||||||
StickyHeaderText(
|
},
|
||||||
label: context.localized.overview,
|
child: AnimatedSize(
|
||||||
),
|
duration: const Duration(milliseconds: 250),
|
||||||
ShaderMask(
|
alignment: Alignment.topCenter,
|
||||||
shaderCallback: (bounds) => LinearGradient(
|
child: Column(
|
||||||
begin: Alignment.topCenter,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
end: Alignment.bottomCenter,
|
mainAxisSize: MainAxisSize.min,
|
||||||
stops: const [0, 1],
|
children: [
|
||||||
colors: [
|
Text(
|
||||||
color,
|
context.localized.overview,
|
||||||
color.withValues(
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
alpha: !canExpand
|
|
||||||
? 1
|
|
||||||
: expanded
|
|
||||||
? 1
|
|
||||||
: 0),
|
|
||||||
],
|
|
||||||
).createShader(bounds),
|
|
||||||
child: HtmlWidget(
|
|
||||||
widget.text.substring(0, !expanded ? maxLength.clamp(0, widget.text.length) : widget.text.length - 1),
|
|
||||||
textStyle: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
),
|
||||||
),
|
ShaderMask(
|
||||||
if (canExpand) ...{
|
shaderCallback: (bounds) => LinearGradient(
|
||||||
const SizedBox(height: 16),
|
begin: Alignment.topCenter,
|
||||||
Align(
|
end: Alignment.bottomCenter,
|
||||||
alignment: Alignment.center,
|
stops: const [0, 1],
|
||||||
child: Transform.translate(
|
colors: [
|
||||||
offset: Offset(0, expanded ? 0 : -15),
|
color,
|
||||||
child: AnimatedSwitcher(
|
color.withValues(
|
||||||
duration: const Duration(milliseconds: 250),
|
alpha: !canExpand
|
||||||
child: expanded
|
? 1
|
||||||
? IconButton.filledTonal(
|
: expanded
|
||||||
onPressed: toggleState,
|
? 1
|
||||||
icon: const Icon(IconsaxPlusLinear.arrow_up_1),
|
: 0),
|
||||||
)
|
],
|
||||||
: IconButton.filledTonal(
|
).createShader(bounds),
|
||||||
onPressed: toggleState,
|
child: HtmlWidget(
|
||||||
icon: const Icon(IconsaxPlusLinear.arrow_down),
|
widget.text.substring(0, !expanded ? maxLength.clamp(0, widget.text.length) : widget.text.length - 1),
|
||||||
),
|
textStyle: Theme.of(context).textTheme.bodyLarge,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
if (canExpand && !isDpad) ...{
|
||||||
],
|
const SizedBox(height: 16),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: Offset(0, expanded ? 0 : -15),
|
||||||
|
child: AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 250),
|
||||||
|
child: expanded
|
||||||
|
? IconButton.filledTonal(
|
||||||
|
onPressed: toggleState,
|
||||||
|
icon: const Icon(IconsaxPlusLinear.arrow_up_1),
|
||||||
|
)
|
||||||
|
: IconButton.filledTonal(
|
||||||
|
onPressed: toggleState,
|
||||||
|
icon: const Icon(IconsaxPlusLinear.arrow_down),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,37 @@ import 'package:flutter/material.dart';
|
||||||
class AdaptiveFab {
|
class AdaptiveFab {
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
final String title;
|
final String title;
|
||||||
|
final String? heroTag;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final Function() onPressed;
|
final Function() onPressed;
|
||||||
|
final Color? backgroundColor;
|
||||||
final Key? key;
|
final Key? key;
|
||||||
AdaptiveFab({
|
AdaptiveFab({
|
||||||
required this.context,
|
required this.context,
|
||||||
this.title = '',
|
this.title = '',
|
||||||
|
this.heroTag,
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
this.key,
|
this.key,
|
||||||
|
this.backgroundColor,
|
||||||
});
|
});
|
||||||
|
|
||||||
FloatingActionButton get normal {
|
Widget get normal {
|
||||||
return FloatingActionButton(
|
return Hero(
|
||||||
key: key,
|
tag: heroTag ?? UniqueKey(),
|
||||||
onPressed: onPressed,
|
child: IconButton.filledTonal(
|
||||||
tooltip: title,
|
iconSize: 26,
|
||||||
child: child,
|
key: key,
|
||||||
|
tooltip: title,
|
||||||
|
onPressed: onPressed,
|
||||||
|
style: IconButton.styleFrom(
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
),
|
||||||
|
icon: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,6 +48,7 @@ class AdaptiveFab {
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
style: FilledButton.styleFrom(
|
style: FilledButton.styleFrom(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
spacing: 16,
|
spacing: 16,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue