quiz redirecionado aos videos | redesing da notificação
This commit is contained in:
19
lib/widgets/name_input_formatter.dart
Normal file
19
lib/widgets/name_input_formatter.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// Capitaliza automaticamente a primeira letra à medida que o utilizador
|
||||
/// escreve — usado nos campos de nome (criança e conta) para não depender
|
||||
/// só da sugestão do teclado (que o utilizador pode ignorar ou que pode
|
||||
/// não existir em todos os teclados).
|
||||
class CapitalizeFirstLetterFormatter extends TextInputFormatter {
|
||||
@override
|
||||
TextEditingValue formatEditUpdate(
|
||||
TextEditingValue oldValue,
|
||||
TextEditingValue newValue,
|
||||
) {
|
||||
final text = newValue.text;
|
||||
if (text.isEmpty) return newValue;
|
||||
final capitalized = text[0].toUpperCase() + text.substring(1);
|
||||
if (capitalized == text) return newValue;
|
||||
return newValue.copyWith(text: capitalized, selection: newValue.selection);
|
||||
}
|
||||
}
|
||||
73
lib/widgets/pill_snackbar.dart
Normal file
73
lib/widgets/pill_snackbar.dart
Normal file
@@ -0,0 +1,73 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Notificação em formato de pílula flutuante (fundo branco, texto rosa,
|
||||
/// cantos totalmente arredondados, com um pequeno "pop" de entrada), usada
|
||||
/// em toda a app em vez do SnackBar padrão do Material (barra preta a
|
||||
/// ocupar a largura toda). O SnackBar continua a ser o mecanismo por trás
|
||||
/// — só o visual muda: fica transparente/sem elevação e o conteúdo real é
|
||||
/// este contentor central que abraça o texto em vez de esticar de ponta a
|
||||
/// ponta.
|
||||
void showPillSnackBar(BuildContext context, String message) {
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
messenger
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(
|
||||
SnackBar(
|
||||
behavior: SnackBarBehavior.floating,
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
duration: const Duration(seconds: 2),
|
||||
padding: EdgeInsets.zero,
|
||||
content: Center(child: _AnimatedPill(message: message)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Pequeno "pop" de entrada (escala + fade, com leve ultrapassagem via
|
||||
/// [Curves.easeOutBack]) para a pílula de notificação — em vez de aparecer
|
||||
/// estática, dá-lhe uma sensação de vida ao surgir. Corre uma única vez,
|
||||
/// automaticamente, assim que este widget é construído (cada chamada a
|
||||
/// [showPillSnackBar] cria uma instância nova).
|
||||
class _AnimatedPill extends StatelessWidget {
|
||||
const _AnimatedPill({required this.message});
|
||||
|
||||
final String message;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
duration: const Duration(milliseconds: 380),
|
||||
curve: Curves.easeOutBack,
|
||||
builder: (context, value, child) {
|
||||
return Opacity(
|
||||
opacity: value.clamp(0.0, 1.0),
|
||||
child: Transform.scale(scale: value, child: child),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 22, vertical: 14),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.08),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 3),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Text(
|
||||
message,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFFF55A7),
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user