mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-18 11:46:33 -07:00
feature(Desktop): Usability improvements to top carousel
This commit is contained in:
parent
6c71a8e63d
commit
f445d8908b
1 changed files with 174 additions and 122 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:ficonsax/ficonsax.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:fladder/models/item_base_model.dart';
|
||||
|
|
@ -30,9 +31,15 @@ class CarouselBanner extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _CarouselBannerState extends ConsumerState<CarouselBanner> {
|
||||
final carouselController = CarouselController();
|
||||
bool showControls = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ConstrainedBox(
|
||||
return MouseRegion(
|
||||
onEnter: (event) => setState(() => showControls = true),
|
||||
onExit: (event) => setState(() => showControls = false),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: widget.maxHeight),
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
|
|
@ -41,16 +48,21 @@ class _CarouselBannerState extends ConsumerState<CarouselBanner> {
|
|||
(MediaQuery.sizeOf(context).shortestSide * 0.75).clamp(251.0, double.maxFinite),
|
||||
);
|
||||
final border = BorderRadius.circular(18);
|
||||
final itemExtent = widget.items.length == 1 ? MediaQuery.sizeOf(context).width : maxExtent;
|
||||
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 4).copyWith(top: AdaptiveLayout.of(context).isDesktop ? 6 : 10),
|
||||
child: CarouselView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4)
|
||||
.copyWith(top: AdaptiveLayout.of(context).isDesktop ? 6 : 10),
|
||||
child: Stack(
|
||||
children: [
|
||||
CarouselView(
|
||||
elevation: 3,
|
||||
shrinkExtent: 0,
|
||||
controller: carouselController,
|
||||
shape: RoundedRectangleBorder(borderRadius: border),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
enableSplash: false,
|
||||
itemExtent: widget.items.length == 1 ? MediaQuery.sizeOf(context).width : maxExtent,
|
||||
itemExtent: itemExtent,
|
||||
children: [
|
||||
...widget.items.mapIndexed(
|
||||
(index, item) => LayoutBuilder(builder: (context, constraints) {
|
||||
|
|
@ -97,7 +109,8 @@ class _CarouselBannerState extends ConsumerState<CarouselBanner> {
|
|||
maxLines: 2,
|
||||
softWrap: item.title.length > 25,
|
||||
overflow: TextOverflow.fade,
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(color: Colors.white),
|
||||
style:
|
||||
Theme.of(context).textTheme.headlineMedium?.copyWith(color: Colors.white),
|
||||
),
|
||||
if (item.label(context) != null || item.subText != null)
|
||||
Text(
|
||||
|
|
@ -133,8 +146,8 @@ class _CarouselBannerState extends ConsumerState<CarouselBanner> {
|
|||
? null
|
||||
: (details) async {
|
||||
Offset localPosition = details.globalPosition;
|
||||
RelativeRect position = RelativeRect.fromLTRB(
|
||||
localPosition.dx - 320, localPosition.dy, localPosition.dx, localPosition.dy);
|
||||
RelativeRect position = RelativeRect.fromLTRB(localPosition.dx - 320,
|
||||
localPosition.dy, localPosition.dx, localPosition.dy);
|
||||
final poster = widget.items[index];
|
||||
|
||||
await showMenu(
|
||||
|
|
@ -161,9 +174,48 @@ class _CarouselBannerState extends ConsumerState<CarouselBanner> {
|
|||
)
|
||||
],
|
||||
),
|
||||
if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer)
|
||||
AnimatedOpacity(
|
||||
duration: const Duration(milliseconds: 250),
|
||||
opacity: showControls ? 1 : 0,
|
||||
child: IgnorePointer(
|
||||
ignoring: !showControls,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton.filledTonal(
|
||||
onPressed: () {
|
||||
final currentPos = carouselController.position;
|
||||
carouselController.animateTo(currentPos.pixels - itemExtent,
|
||||
curve: Curves.easeInOutCubic, duration: const Duration(milliseconds: 250));
|
||||
},
|
||||
icon: const Icon(IconsaxOutline.arrow_left_2),
|
||||
),
|
||||
IconButton.filledTonal(
|
||||
onPressed: () {
|
||||
final currentPos = carouselController.position;
|
||||
carouselController.animateTo(currentPos.pixels + itemExtent,
|
||||
curve: Curves.easeInOutCubic, duration: const Duration(milliseconds: 250));
|
||||
},
|
||||
icon: const Icon(IconsaxOutline.arrow_right_3),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue