flutty 0.2.1
flutty: ^0.2.1 copied to clipboard
FluttyUI Component Library
example/lib/main.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutty/flutty.dart';
import 'package:flutty_example/theme_controller.dart';
import 'app_routes.dart';
import 'flutty_scaffold.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const ExampleApp());
}
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
@override
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
ThemeData _currentTheme = fluttyDark;
int _currentIndex = 0;
void _toggleTheme() {
setState(() {
_currentTheme = _currentTheme == fluttyDark ? fluttyLight : fluttyDark;
});
}
Map<String, WidgetBuilder> wrapInScaffold(Map<String, WidgetBuilder> routes) {
return routes.map((key, pageBuilder) {
return MapEntry(
key,
(context) => FluttyScaffold(
title: key.replaceFirst('/', ''),
body: pageBuilder(context),
),
);
});
}
@override
Widget build(BuildContext context) {
return ThemeController(
theme: _currentTheme,
toggleTheme: _toggleTheme,
child: FluttyApp(
debugShowCheckedModeBanner: false,
navigatorKey: toastNavigatorKey,
theme: _currentTheme,
routes: {
...wrapInScaffold(appRoutes),
...wrapInScaffold(appBlocksRoutes),
},
home: Builder(builder: (context) {
final theme = ThemeValueResolver.of(context);
final random = Random();
// Helper for random rotation/offset "chaos"
Widget chaos(Widget child) {
final dx = (random.nextDouble() - 0.5) * 10;
final dy = (random.nextDouble() - 0.5) * 10;
final rot = (random.nextDouble() - 0.5) * 0.08;
return SizedBox(
width: MediaQuery.of(context).size.width,
child: Center(
child: Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..translate(dx, dy)
..rotateZ(rot),
child: child,
),
),
);
}
// All bottom nav pages
final pages = [
_buildChaosPage(context, theme, chaos),
const Center(child: Text("Components")),
const Center(child: Text("Docs")),
const Center(child: Text("About")),
const Center(child: Text("sssss")),
];
final items = [
BottomNavigationBarItem(
icon: const Icon(Icons.home_outlined),
label: "Home",
),
BottomNavigationBarItem(
icon: const Icon(Icons.widgets_outlined),
label: "Components",
),
BottomNavigationBarItem(
icon: const Icon(Icons.book_outlined),
label: "Docs",
),
BottomNavigationBarItem(
icon: const Icon(Icons.info_outline),
label: "About",
),
BottomNavigationBarItem(
icon: const Icon(Icons.info_outline),
label: "Someelso",
),
];
// β
FIXED: place bottom navigation inside the body column
return FluttyScaffold(
title: "Demo screen",
body: Column(
children: [
Expanded(child: pages[_currentIndex]),
FluttyBottomNavigation(
color: ColorVariant.primary,
isFloating: false,
items: items,
radius: RadiusVariant.none,
currentIndex: _currentIndex,
onTap: (i) => setState(() => _currentIndex = i),
),
],
),
);
}),
),
);
}
/// π§ Builds your levitating chaos demo
Widget _buildChaosPage(BuildContext context, ThemeValueResolver theme,
Widget Function(Widget) chaos) {
return SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 32),
Wrap(
spacing: 16,
runSpacing: 16,
alignment: WrapAlignment.center,
children: [
FluttyLevitate(
randomness: 0.3,
child: chaos(
FluttyUser(
username: "John Doe",
description: "Flutter Developer",
infoPosition: UserInfoPosition.right,
avatarProps: const FluttyAvatarProps(
imageUrl: "https://i.pravatar.cc/150?img=1",
size: SizeVariant.sm,
bordered: true,
color: ColorVariant.primary,
),
),
),
),
FluttyLevitate(
randomness: 0.1,
child: chaos(
FluttyButton(
text: "Explore Flutty",
color: ColorVariant.primary,
onPressed: () {},
),
),
),
FluttyLevitate(
randomness: 0.4,
child: chaos(
FluttyCheckbox(
onChanged: (_) {},
label: "Check me",
),
),
),
FluttyLevitate(
randomness: 0.7,
child: chaos(
FluttyChip(
color: ColorVariant.secondary,
label: 'Chip',
),
),
),
FluttyLevitate(
randomness: 0.2,
child: chaos(
FluttyProgress(
color: ColorVariant.success,
progress: 0.6,
),
),
),
FluttyLevitate(
randomness: 0.5,
child: chaos(
FluttyAvatar(
name: "FT",
color: ColorVariant.primary,
size: SizeVariant.md,
imageUrl: '',
),
),
),
FluttyLevitate(
randomness: 0.9,
child: Text.rich(
TextSpan(
style: TextStyle(
fontSize: 38,
fontWeight: FontWeight.w700,
color: theme.foreground,
),
children: [
const TextSpan(text: "Join the "),
TextSpan(
text: "Flutter Revolution",
style: TextStyle(
foreground: Paint()
..shader = const LinearGradient(
colors: [
Color(0xFFE3428B),
Color(0xFF7A1051)
],
).createShader(
const Rect.fromLTWH(0, 0, 300, 50),
),
),
),
],
),
textAlign: TextAlign.center,
),
),
FluttyLevitate(
randomness: 0.6,
child: chaos(
FluttyAlert(
title: "Danger Alert",
message: "Chaos Alert incoming!",
color: ColorVariant.danger,
),
),
),
const SizedBox(height: 12),
FluttyLevitate(
randomness: 1.2,
child: Text(
"Flutty is changing how Flutter apps are built. Open the drawer and dive into it.",
style: TextStyle(
fontSize: 18,
color: theme.divider.withAlpha(170),
),
textAlign: TextAlign.center,
),
),
],
),
const SizedBox(height: 40),
FluttyLevitate(
randomness: 1.1,
child: chaos(
FluttyButton(
text: "Get Started",
color: ColorVariant.secondary,
onPressed: () {},
),
),
),
const SizedBox(height: 60),
],
),
),
),
),
);
}
}
/// π Smooth levitating effect wrapper
class FluttyLevitate extends StatefulWidget {
final Widget child;
final double amplitude;
final double speed;
final double randomness;
const FluttyLevitate({
super.key,
required this.child,
this.amplitude = 10.0,
this.speed = 1.0,
this.randomness = 2.0,
});
@override
State<FluttyLevitate> createState() => _FluttyLevitateState();
}
class _FluttyLevitateState extends State<FluttyLevitate>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late double _phaseOffset;
@override
void initState() {
super.initState();
final random = Random();
_phaseOffset = random.nextDouble() * pi * widget.randomness;
final duration = Duration(
milliseconds: max(2000, (8000 ~/ max(0.1, widget.speed))),
);
_controller = AnimationController(vsync: this, duration: duration)
..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
final progress = _controller.value * 2 * pi;
final dy = sin(progress + _phaseOffset) * widget.amplitude;
return Transform.translate(offset: Offset(0, dy), child: child);
},
child: widget.child,
);
}
}