✨ Notification stacks on the mobile
This commit is contained in:
@@ -12,6 +12,8 @@ class NotificationItemWidget extends HookConsumerWidget {
|
|||||||
final NotificationItem item;
|
final NotificationItem item;
|
||||||
final VoidCallback onDismiss;
|
final VoidCallback onDismiss;
|
||||||
final bool isDesktop;
|
final bool isDesktop;
|
||||||
|
final int index;
|
||||||
|
final int totalNotifications;
|
||||||
final Animation<double> progress;
|
final Animation<double> progress;
|
||||||
|
|
||||||
const NotificationItemWidget({
|
const NotificationItemWidget({
|
||||||
@@ -19,6 +21,8 @@ class NotificationItemWidget extends HookConsumerWidget {
|
|||||||
required this.item,
|
required this.item,
|
||||||
required this.onDismiss,
|
required this.onDismiss,
|
||||||
required this.isDesktop,
|
required this.isDesktop,
|
||||||
|
required this.index,
|
||||||
|
required this.totalNotifications,
|
||||||
required this.progress,
|
required this.progress,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,7 +52,7 @@ class NotificationItemWidget extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
child: Card(
|
child: Card(
|
||||||
elevation: 4,
|
elevation: (index == 0 && !isDesktop && totalNotifications > 1) ? 8 : 4,
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
@@ -117,4 +121,4 @@ class NotificationItemWidget extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,39 +29,79 @@ class NotificationOverlay extends HookConsumerWidget {
|
|||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
final itemWidth = isDesktop ? 420.0 : MediaQuery.sizeOf(context).width - 40;
|
final itemWidth = isDesktop ? 420.0 : MediaQuery.sizeOf(context).width;
|
||||||
|
|
||||||
return Positioned(
|
if (isDesktop) {
|
||||||
top: topOffset,
|
return Positioned(
|
||||||
left: 0,
|
top: topOffset,
|
||||||
right: 0,
|
left: 0,
|
||||||
child:
|
right: 0,
|
||||||
Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: isDesktop
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
? CrossAxisAlignment.end
|
mainAxisSize: MainAxisSize.min,
|
||||||
: CrossAxisAlignment.center,
|
children: notifications.asMap().entries.map((entry) {
|
||||||
mainAxisSize: MainAxisSize.min,
|
final index = entry.key;
|
||||||
children: notifications.asMap().entries.map((entry) {
|
final item = entry.value;
|
||||||
final item = entry.value;
|
return AnimatedNotificationItem(
|
||||||
return AnimatedNotificationItem(
|
key: Key(item.id),
|
||||||
key: Key(item.id),
|
item: item,
|
||||||
item: item,
|
isDesktop: true,
|
||||||
isDesktop: isDesktop,
|
index: index,
|
||||||
onDismiss: () {
|
totalNotifications: notifications.length,
|
||||||
ref
|
onDismiss: () {
|
||||||
.read(notificationStateProvider.notifier)
|
ref.read(notificationStateProvider.notifier).remove(item.id);
|
||||||
.remove(item.id);
|
},
|
||||||
},
|
);
|
||||||
);
|
}).toList(),
|
||||||
}).toList(),
|
),
|
||||||
),
|
).width(itemWidth).alignment(Alignment.topRight),
|
||||||
)
|
);
|
||||||
.width(itemWidth)
|
} else {
|
||||||
.alignment(isDesktop ? Alignment.topRight : Alignment.topCenter),
|
// Non-desktop: use Stack with overlapping
|
||||||
);
|
const double notificationHeight = 80.0;
|
||||||
|
const double overlap = 20.0;
|
||||||
|
final stackHeight =
|
||||||
|
notificationHeight + (notifications.length - 1) * overlap;
|
||||||
|
|
||||||
|
return Positioned(
|
||||||
|
top: topOffset,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: SizedBox(
|
||||||
|
height: stackHeight,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
children: notifications.asMap().entries.map((entry) {
|
||||||
|
final index = entry.key;
|
||||||
|
final item = entry.value;
|
||||||
|
return Positioned(
|
||||||
|
top: index * overlap,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
child: AnimatedNotificationItem(
|
||||||
|
key: Key(item.id),
|
||||||
|
item: item,
|
||||||
|
isDesktop: false,
|
||||||
|
index: index,
|
||||||
|
totalNotifications: notifications.length,
|
||||||
|
onDismiss: () {
|
||||||
|
ref
|
||||||
|
.read(notificationStateProvider.notifier)
|
||||||
|
.remove(item.id);
|
||||||
|
},
|
||||||
|
).clipRRect(all: 8),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).width(itemWidth).alignment(Alignment.topCenter),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,12 +109,16 @@ class AnimatedNotificationItem extends HookConsumerWidget {
|
|||||||
final NotificationItem item;
|
final NotificationItem item;
|
||||||
final VoidCallback onDismiss;
|
final VoidCallback onDismiss;
|
||||||
final bool isDesktop;
|
final bool isDesktop;
|
||||||
|
final int index;
|
||||||
|
final int totalNotifications;
|
||||||
|
|
||||||
const AnimatedNotificationItem({
|
const AnimatedNotificationItem({
|
||||||
super.key,
|
super.key,
|
||||||
required this.item,
|
required this.item,
|
||||||
required this.onDismiss,
|
required this.onDismiss,
|
||||||
required this.isDesktop,
|
required this.isDesktop,
|
||||||
|
required this.index,
|
||||||
|
required this.totalNotifications,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -124,16 +168,13 @@ class AnimatedNotificationItem extends HookConsumerWidget {
|
|||||||
child: SizeTransition(
|
child: SizeTransition(
|
||||||
sizeFactor: curvedAnimation,
|
sizeFactor: curvedAnimation,
|
||||||
axis: Axis.vertical,
|
axis: Axis.vertical,
|
||||||
child: Padding(
|
child: NotificationItemWidget(
|
||||||
padding: isDesktop
|
item: item,
|
||||||
? const EdgeInsets.only(bottom: 12, right: 16)
|
isDesktop: isDesktop,
|
||||||
: const EdgeInsets.only(bottom: 12, left: 16, right: 16),
|
index: index,
|
||||||
child: NotificationItemWidget(
|
totalNotifications: totalNotifications,
|
||||||
item: item,
|
onDismiss: () {},
|
||||||
isDesktop: isDesktop,
|
progress: progressAnimation,
|
||||||
onDismiss: () {},
|
|
||||||
progress: progressAnimation,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user