Files
b0esche_cloud/b0esche_cloud/lib/pages/home_page.dart
Leon Bösche dd1aa4775c good morning
2025-12-17 14:48:55 +01:00

297 lines
12 KiB
Dart

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../blocs/auth/auth_bloc.dart';
import '../blocs/auth/auth_state.dart';
import '../theme/app_theme.dart';
import 'login_form.dart';
import 'file_explorer.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
late String _selectedTab = 'Drive';
late AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 400),
vsync: this,
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppTheme.primaryBackground,
body: Stack(
children: [
Center(
child: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
final isLoggedIn = state is AuthAuthenticated;
if (isLoggedIn && !_animationController.isAnimating) {
_animationController.forward();
} else if (!isLoggedIn) {
_animationController.reverse();
}
return AnimatedContainer(
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
width: isLoggedIn
? MediaQuery.of(context).size.width * 0.9
: 340,
height: isLoggedIn
? MediaQuery.of(context).size.height * 0.9
: 280,
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Stack(
children: [
Container(
decoration: AppTheme.glassDecoration,
child: isLoggedIn
? const FileExplorer(orgId: 'org1')
: const LoginForm(),
),
// Top-left radial glow - primary accent light
AnimatedPositioned(
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
top: isLoggedIn ? -180 : -120,
left: isLoggedIn ? -180 : -120,
child: IgnorePointer(
child: AnimatedContainer(
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
width: isLoggedIn ? 550 : 400,
height: isLoggedIn ? 550 : 400,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
AppTheme.accentColor.withValues(
alpha: isLoggedIn ? 0.12 : 0.15,
),
AppTheme.accentColor.withValues(
alpha: 0.04,
),
Colors.transparent,
],
stops: const [0.0, 0.6, 1.0],
),
),
),
),
),
// Bottom-right warm glow - complementary lighting
AnimatedPositioned(
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
bottom: isLoggedIn ? -200 : -140,
right: isLoggedIn ? -200 : -140,
child: IgnorePointer(
child: AnimatedContainer(
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
width: isLoggedIn ? 530 : 380,
height: isLoggedIn ? 530 : 380,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
Colors.cyan.withValues(
alpha: isLoggedIn ? 0.06 : 0.08,
),
Colors.transparent,
],
),
),
),
),
),
// Top edge subtle highlight
Positioned(
top: 0,
left: 0,
right: 0,
child: IgnorePointer(
child: Container(
height: 60,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.white.withValues(alpha: 0.05),
Colors.transparent,
],
),
),
),
),
),
// Left edge subtle side lighting
Positioned(
left: 0,
top: 0,
bottom: 0,
child: IgnorePointer(
child: Container(
width: 40,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
AppTheme.accentColor.withValues(
alpha: 0.04,
),
Colors.transparent,
],
),
),
),
),
),
// Diagonal shimmer overlay
Positioned(
top: 0,
left: 0,
child: IgnorePointer(
child: Transform.rotate(
angle: 0.785,
child: Container(
width: 600,
height: 100,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.white.withValues(alpha: 0),
Colors.white.withValues(alpha: 0.06),
Colors.white.withValues(alpha: 0),
],
),
),
),
),
),
),
],
),
),
),
);
},
),
),
Positioned(
top: 10,
left: 0,
right: 0,
child: Center(
child: Text(
'b0esche.cloud',
style: TextStyle(
fontFamily: 'PixelatedElegance',
fontSize: 42,
color: AppTheme.primaryText,
decoration: TextDecoration.underline,
decorationColor: AppTheme.primaryText,
fontFeatures: [const FontFeature.slashedZero()],
),
),
),
),
Positioned(
top: 10,
right: 20,
child: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
final isLoggedIn = state is AuthAuthenticated;
if (!isLoggedIn) {
return const SizedBox.shrink();
}
return ScaleTransition(
scale: Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(
parent: _animationController,
curve: Curves.easeOutBack,
),
),
child: Row(
children: [
_buildNavButton('Drive', Icons.cloud),
const SizedBox(width: 16),
_buildNavButton('Mail', Icons.mail),
const SizedBox(width: 16),
_buildNavButton('Add', Icons.add),
const SizedBox(width: 16),
_buildNavButton('Profile', Icons.person, isAvatar: true),
],
),
);
},
),
),
],
),
);
}
Widget _buildNavButton(String label, IconData icon, {bool isAvatar = false}) {
final isSelected = _selectedTab == label;
final highlightColor = Color.fromARGB(255, 100, 200, 255);
final defaultColor = AppTheme.secondaryText;
return GestureDetector(
onTap: () {
setState(() {
_selectedTab = label;
});
},
child: isAvatar
? CircleAvatar(
backgroundColor: isSelected ? highlightColor : defaultColor,
child: Icon(icon, color: AppTheme.primaryBackground),
)
: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
color: isSelected ? highlightColor : defaultColor,
size: 24,
),
const SizedBox(height: 4),
Text(
label,
style: TextStyle(
color: isSelected ? highlightColor : defaultColor,
fontSize: 12,
fontWeight: isSelected
? FontWeight.bold
: FontWeight.normal,
),
),
],
),
);
}
}