refactor(ui): Minor refactoring, extract repeating title widget

This commit is contained in:
gasaichandesu
2026-06-18 23:48:19 +04:00
parent 51f6a91bbf
commit 2bc54f1cd7
4 changed files with 92 additions and 596 deletions
+9 -78
View File
@@ -1,11 +1,10 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:moonwell_launcher/app/home_screen/bloc/home_screen_bloc.dart';
import 'package:moonwell_launcher/app/home_screen/home_screen_content.dart';
import 'package:moonwell_launcher/app/login_screen/login_screen.dart';
import 'package:moonwell_launcher/app/theme/mw_theme.dart';
import 'package:moonwell_launcher/app/widgets/window_title_bar.dart';
import 'package:moonwell_launcher/features/launcher/application/client_sync_use_case.dart';
import 'package:moonwell_launcher/features/launcher/data/game_installation_service.dart';
import 'package:moonwell_launcher/features/launcher/data/launcher_api_client.dart';
@@ -13,7 +12,6 @@ import 'package:moonwell_launcher/features/launcher/domain/entities/client_manif
import 'package:moonwell_launcher/features/launcher/domain/entities/launcher_session.dart';
import 'package:moonwell_launcher/features/preferences/domain/repositories/preferences_repository.dart';
import 'package:moonwell_launcher/service_container.dart';
import 'package:window_manager/window_manager.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key, required this.session, required this.manifest});
@@ -38,8 +36,8 @@ class HomeScreen extends StatelessWidget {
listener: (context, state) async {
await Navigator.of(context).pushReplacement(
PageRouteBuilder(
pageBuilder: (_, __, ___) => const LoginScreen(),
transitionsBuilder: (_, animation, __, child) {
pageBuilder: (_, _, _) => const LoginScreen(),
transitionsBuilder: (_, animation, _, child) {
return FadeTransition(opacity: animation, child: child);
},
transitionDuration: const Duration(milliseconds: 250),
@@ -49,11 +47,9 @@ class HomeScreen extends StatelessWidget {
child: Scaffold(
body: Stack(
children: [
// Background image
Positioned.fill(
child: Image.asset('assets/background.png', fit: BoxFit.cover),
),
// Gradient overlay
Positioned.fill(
child: DecoratedBox(
decoration: BoxDecoration(
@@ -70,10 +66,13 @@ class HomeScreen extends StatelessWidget {
),
),
),
// Main content
const Positioned.fill(child: HomeScreenContent()),
// Custom title bar
const Positioned(top: 0, left: 0, right: 0, child: _TitleBar()),
const Positioned(
top: 0,
left: 0,
right: 0,
child: WindowTitleBar(),
),
],
),
),
@@ -81,71 +80,3 @@ class HomeScreen extends StatelessWidget {
);
}
}
class _TitleBar extends StatelessWidget {
const _TitleBar();
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return GestureDetector(
onPanStart: (_) => windowManager.startDragging(),
child: SizedBox(
height: 36,
child: Row(
children: [
const Spacer(),
_TitleBarButton(
icon: Icons.remove,
onTap: () => windowManager.minimize(),
color: cs.onSurface,
),
_TitleBarButton(
icon: Icons.crop_square,
onTap: () async {
if (await windowManager.isMaximized()) {
await windowManager.unmaximize();
} else {
await windowManager.maximize();
}
},
color: cs.onSurface,
),
_TitleBarButton(
icon: Icons.close,
onTap: () {
unawaited(windowManager.destroy());
},
color: MWColors.error,
),
],
),
),
);
}
}
class _TitleBarButton extends StatelessWidget {
const _TitleBarButton({
required this.icon,
required this.onTap,
required this.color,
});
final IconData icon;
final VoidCallback onTap;
final Color color;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: SizedBox(
width: 40,
height: 36,
child: Icon(icon, size: 16, color: color.withAlpha(180)),
),
);
}
}
+4 -78
View File
@@ -1,12 +1,10 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:moonwell_launcher/app/home_screen/home_screen.dart';
import 'package:moonwell_launcher/app/theme/mw_theme.dart';
import 'package:moonwell_launcher/app/widgets/window_title_bar.dart';
import 'package:moonwell_launcher/features/launcher/data/launcher_api_client.dart';
import 'package:moonwell_launcher/features/preferences/domain/repositories/preferences_repository.dart';
import 'package:moonwell_launcher/service_container.dart';
import 'package:window_manager/window_manager.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@@ -53,9 +51,9 @@ class _LoginScreenState extends State<LoginScreen> {
await Navigator.of(context).pushReplacement(
PageRouteBuilder(
pageBuilder: (_, __, ___) =>
pageBuilder: (_, _, _) =>
HomeScreen(session: session, manifest: manifest),
transitionsBuilder: (_, animation, __, child) {
transitionsBuilder: (_, animation, _, child) {
return FadeTransition(opacity: animation, child: child);
},
transitionDuration: const Duration(milliseconds: 400),
@@ -83,7 +81,6 @@ class _LoginScreenState extends State<LoginScreen> {
return Scaffold(
body: Stack(
children: [
// Background
Positioned.fill(
child: Image.asset('assets/background.png', fit: BoxFit.cover),
),
@@ -101,23 +98,19 @@ class _LoginScreenState extends State<LoginScreen> {
),
),
),
// Title bar
Positioned(top: 0, left: 0, right: 0, child: _TitleBar(cs: cs)),
// Login form — centered
const Positioned(top: 0, left: 0, right: 0, child: WindowTitleBar()),
Center(
child: SizedBox(
width: 340,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Logo
Image.asset(
'assets/logo.png',
height: 160,
filterQuality: FilterQuality.high,
),
const SizedBox(height: 32),
// Card
Container(
padding: const EdgeInsets.all(28),
decoration: BoxDecoration(
@@ -194,70 +187,3 @@ class _LoginScreenState extends State<LoginScreen> {
);
}
}
class _TitleBar extends StatelessWidget {
const _TitleBar({required this.cs});
final ColorScheme cs;
@override
Widget build(BuildContext context) {
return GestureDetector(
onPanStart: (_) => windowManager.startDragging(),
child: SizedBox(
height: 36,
child: Row(
children: [
const Spacer(),
_TitleBarButton(
icon: Icons.remove,
onTap: () => windowManager.minimize(),
color: cs.onSurface,
),
_TitleBarButton(
icon: Icons.crop_square,
onTap: () async {
if (await windowManager.isMaximized()) {
await windowManager.unmaximize();
} else {
await windowManager.maximize();
}
},
color: cs.onSurface,
),
_TitleBarButton(
icon: Icons.close,
onTap: () {
unawaited(windowManager.destroy());
},
color: MWColors.error,
),
],
),
),
);
}
}
class _TitleBarButton extends StatelessWidget {
const _TitleBarButton({
required this.icon,
required this.onTap,
required this.color,
});
final IconData icon;
final VoidCallback onTap;
final Color color;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: SizedBox(
width: 40,
height: 36,
child: Icon(icon, size: 16, color: color.withAlpha(180)),
),
);
}
}
+77
View File
@@ -0,0 +1,77 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:moonwell_launcher/app/theme/mw_theme.dart';
import 'package:window_manager/window_manager.dart';
class WindowTitleBar extends StatelessWidget {
const WindowTitleBar({super.key});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return GestureDetector(
onPanStart: (_) => windowManager.startDragging(),
child: SizedBox(
height: 36,
child: Row(
children: [
const Spacer(),
_TitleBarButton(
icon: Icons.remove,
onTap: () => windowManager.minimize(),
color: cs.onSurface,
),
_TitleBarButton(
icon: Icons.crop_square,
onTap: () {
unawaited(_toggleMaximized());
},
color: cs.onSurface,
),
_TitleBarButton(
icon: Icons.close,
onTap: () {
unawaited(windowManager.destroy());
},
color: MWColors.error,
),
],
),
),
);
}
Future<void> _toggleMaximized() async {
if (await windowManager.isMaximized()) {
await windowManager.unmaximize();
} else {
await windowManager.maximize();
}
}
}
class _TitleBarButton extends StatelessWidget {
const _TitleBarButton({
required this.icon,
required this.onTap,
required this.color,
});
final IconData icon;
final VoidCallback onTap;
final Color color;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: SizedBox(
width: 40,
height: 36,
child: Icon(icon, size: 16, color: color.withAlpha(180)),
),
);
}
}