Files
school-attendance/lib/ui/launchpad_transition.dart
T
sihooandClaude Sonnet 5 f885719674 런치패드 스타일 화면 전환 + 설정/로그아웃 메뉴 오버레이 + 알약형 알림 추가
- 좌우 슬라이드 대신 맥북 런치패드처럼 확대+페이드로 나타나고 전환 중 뒤 화면이
  블러 처리되는 LaunchpadPageRoute 추가, 대시보드의 모든 기능 타일 이동에 적용
- 오른쪽 위 설정 아이콘 + 로그아웃 아이콘 2개를 ">" 버튼 1개로 통합하고,
  누르면 로그아웃/설정 메뉴가 런치패드 스타일 오버레이(배경 블러 유지)로 뜨게 변경
- 기능 타일을 누를 때 뜨는 안내 메시지를 스낵바 대신 알약(pill) 모양 알림으로 교체
  (AppNotice) - 웹에서는 왼쪽 위, 앱에서는 기존처럼 아래쪽에 표시. 푸시 알림과는 무관.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 23:25:23 +09:00

116 lines
4.5 KiB
Dart

// 🚀 맥북 런치패드처럼 "앞에서 확대되며 나타나고, 뒤는 블러 처리되는" 전환 효과.
// 기존의 좌우 슬라이드 전환을 대체한다. 두 가지 쓰임새가 있다:
// 1) launchpadPageRoute — 전체 화면 이동(다른 기능 타일 진입)용. 전환 중에만 블러가 보이고,
// 화면이 다 뜨면 원래 화면(대시보드)은 완전히 가려진다.
// 2) showLaunchpadMenu — 설정/로그아웃 같은 작은 메뉴 오버레이용. 메뉴가 떠 있는 동안
// 뒤에 있는 대시보드가 계속 뿌옇게 보인다. 바깥을 탭하면 닫힌다.
import 'dart:ui';
import 'package:flutter/material.dart';
class LaunchpadPageRoute<T> extends PageRouteBuilder<T> {
LaunchpadPageRoute({required WidgetBuilder builder})
: super(
transitionDuration: const Duration(milliseconds: 320),
reverseTransitionDuration: const Duration(milliseconds: 240),
pageBuilder: (context, animation, secondaryAnimation) =>
builder(context),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final curved = CurvedAnimation(
parent: animation,
curve: Curves.easeOutCubic,
reverseCurve: Curves.easeInCubic,
);
return AnimatedBuilder(
animation: curved,
child: child,
builder: (context, child) {
final t = curved.value;
return Stack(
children: [
// 뒤에 있던 화면(대시보드)을 전환하는 동안만 뿌옇게 보여준다.
Positioned.fill(
child: IgnorePointer(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 22 * t,
sigmaY: 22 * t,
),
child: Container(
color: Colors.black.withValues(alpha: 0.12 * t),
),
),
),
),
Opacity(
opacity: t,
child: Transform.scale(
scale: 0.94 + 0.06 * t,
child: child,
),
),
],
);
},
);
},
);
}
/// 화면 전체 이동에 런치패드 전환 효과를 적용한다. MaterialPageRoute 대신 이걸 쓰면 됨.
Future<T?> pushLaunchpad<T>(BuildContext context, WidgetBuilder builder) {
return Navigator.push<T>(context, LaunchpadPageRoute<T>(builder: builder));
}
/// 설정/로그아웃 같은 작은 메뉴를 런치패드 스타일(확대+페이드, 배경은 계속 블러 유지)로 띄운다.
/// 바깥을 탭하면 닫힌다. builder는 화면 전체를 채우는 Align 등으로 메뉴 위치를 직접 잡아야 한다.
Future<T?> showLaunchpadMenu<T>({
required BuildContext context,
required WidgetBuilder builder,
}) {
return showGeneralDialog<T>(
context: context,
barrierDismissible: true,
barrierLabel: 'menu',
barrierColor: Colors.transparent,
transitionDuration: const Duration(milliseconds: 260),
pageBuilder: (context, animation, secondaryAnimation) => builder(context),
transitionBuilder: (context, animation, secondaryAnimation, child) {
final curved = CurvedAnimation(
parent: animation,
curve: Curves.easeOutCubic,
reverseCurve: Curves.easeInCubic,
);
return AnimatedBuilder(
animation: curved,
child: child,
builder: (context, child) {
final t = curved.value;
return Stack(
children: [
// 메뉴가 떠 있는 동안 계속 뿌옇게 — 기능 화면이랑 헷갈리지 않게 진하게.
Positioned.fill(
child: IgnorePointer(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 32 * t, sigmaY: 32 * t),
child: Container(
color: Colors.black.withValues(alpha: 0.28 * t),
),
),
),
),
Opacity(
opacity: t,
child: Transform.scale(
alignment: Alignment.topRight,
scale: 0.85 + 0.15 * t,
child: child,
),
),
],
);
},
);
},
);
}