diff --git a/toolbox/spanner/lib/components/window_controls.dart b/toolbox/spanner/lib/components/window_controls.dart new file mode 100644 index 0000000..f901663 --- /dev/null +++ b/toolbox/spanner/lib/components/window_controls.dart @@ -0,0 +1,44 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; + +class WindowControls extends StatelessWidget { + const WindowControls({super.key}); + + bool isDesktop() { + // TODO: Add OHOS support. + if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) { + return true; + } else { + return false; + } + } + + @override + Widget build(BuildContext context) { + return Row( + children: isDesktop() + ? [ + VerticalDivider(width: 16, indent: 16, endIndent: 16), + IconButton( + icon: Icon(Icons.minimize), + tooltip: "Minimize", + onPressed: () {}, + ), + IconButton( + icon: Icon(Icons.square_outlined), + tooltip: "Maximize", + onPressed: () {}, + ), + Container( + padding: EdgeInsetsGeometry.only(right: 6.0), + child: IconButton( + icon: Icon(Icons.close), + tooltip: "Close", + onPressed: () {}, + ), + ), + ] + : [], + ); + } +} diff --git a/toolbox/spanner/lib/features/configurator/components/shell.dart b/toolbox/spanner/lib/features/configurator/components/shell.dart index 6e562fe..2b286e4 100644 --- a/toolbox/spanner/lib/features/configurator/components/shell.dart +++ b/toolbox/spanner/lib/features/configurator/components/shell.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:spanner/components/window_controls.dart'; class NavDestinationConfig { final String id; // Unique identifier for reordering/keys @@ -86,11 +87,13 @@ class ConfiguratorShell extends StatelessWidget { padding: EdgeInsetsGeometry.only(right: 6.0), child: IconButton( icon: Icon(Icons.settings_outlined), + tooltip: "Settings", onPressed: () { context.push("/settings"); }, ), ), + WindowControls(), ], ), bottomNavigationBar: isSmall diff --git a/toolbox/spanner/lib/features/settings/components/shell.dart b/toolbox/spanner/lib/features/settings/components/shell.dart new file mode 100644 index 0000000..c41d6d5 --- /dev/null +++ b/toolbox/spanner/lib/features/settings/components/shell.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:spanner/components/window_controls.dart'; + +class SettingsShell extends StatelessWidget { + final Widget child; + + const SettingsShell({super.key, required this.child}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + context.pop(); + }, + ), + title: Text("Settings"), + actions: [WindowControls()], + ), + body: child, + ); + } +} diff --git a/toolbox/spanner/lib/features/settings/screens/categories.dart b/toolbox/spanner/lib/features/settings/screens/categories.dart index 1bf69ea..25f55f1 100644 --- a/toolbox/spanner/lib/features/settings/screens/categories.dart +++ b/toolbox/spanner/lib/features/settings/screens/categories.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; class SettingCategory { final String id; @@ -29,45 +28,34 @@ class SettingsCategories extends StatelessWidget { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - leading: IconButton( - icon: Icon(Icons.arrow_back), - onPressed: () { - context.pop(); - }, - ), - title: Text("Settings"), - ), - body: Container( - padding: EdgeInsets.all(16.0), - child: Column( - children: [ - TextField( - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Search', - icon: Icon(Icons.search), - ), + return Container( + padding: EdgeInsets.all(16.0), + child: Column( + children: [ + TextField( + decoration: InputDecoration( + border: InputBorder.none, + labelText: 'Search', + icon: Icon(Icons.search), ), - Expanded( - child: Container( - padding: EdgeInsets.only(top: 8.0), - child: ListView.builder( - itemCount: settingsCategories.length, - itemBuilder: (context, index) { - final category = settingsCategories[index]; - return ListTile( - leading: category.icon, - title: Text(category.name), - subtitle: Text(category.description), - ); - }, - ), + ), + Expanded( + child: Container( + padding: EdgeInsets.only(top: 8.0), + child: ListView.builder( + itemCount: settingsCategories.length, + itemBuilder: (context, index) { + final category = settingsCategories[index]; + return ListTile( + leading: category.icon, + title: Text(category.name), + subtitle: Text(category.description), + ); + }, ), ), - ], - ), + ), + ], ), ); } diff --git a/toolbox/spanner/lib/features/welcome/screens/landing.dart b/toolbox/spanner/lib/features/welcome/screens/landing.dart index a437ca3..c5d890d 100644 --- a/toolbox/spanner/lib/features/welcome/screens/landing.dart +++ b/toolbox/spanner/lib/features/welcome/screens/landing.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:spanner/components/window_controls.dart'; class LandingPage extends StatelessWidget { const LandingPage({super.key}); @@ -7,7 +8,7 @@ class LandingPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text("Spanner")), + appBar: AppBar(title: Text("Spanner"), actions: [WindowControls()]), body: Column( children: [ Text("Welcome to Spanner!"), diff --git a/toolbox/spanner/lib/features/wizard/components/shell.dart b/toolbox/spanner/lib/features/wizard/components/shell.dart index 6d69a5a..4301d3f 100644 --- a/toolbox/spanner/lib/features/wizard/components/shell.dart +++ b/toolbox/spanner/lib/features/wizard/components/shell.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:spanner/components/window_controls.dart'; class WizardShell extends StatelessWidget { final Widget child; @@ -9,7 +10,7 @@ class WizardShell extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( // TODO: Add progress bar. - appBar: AppBar(title: Text("Setup Wizard")), + appBar: AppBar(title: Text("Setup Wizard"), actions: [WindowControls()]), body: child, ); } diff --git a/toolbox/spanner/lib/main.dart b/toolbox/spanner/lib/main.dart index 7ca91b6..8b7145f 100644 --- a/toolbox/spanner/lib/main.dart +++ b/toolbox/spanner/lib/main.dart @@ -2,28 +2,29 @@ import 'package:flutter/material.dart'; import 'router.dart'; void main() { + // TODO: Custom window decorations when running on desktop. runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); - // This widget is the root of your application. + // TODO: Match B.E.N.T.O. more closely. + ThemeData _generateTheme(bool isDark) { + return ThemeData( + brightness: isDark ? Brightness.dark : Brightness.light, + colorSchemeSeed: const Color(0xFF7CCF9E), + useMaterial3: true, + ); + } + @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: router, title: 'Spanner', - theme: ThemeData( - brightness: Brightness.light, - colorSchemeSeed: const Color(0xFF7CCF9E), - useMaterial3: true, - ), - darkTheme: ThemeData( - brightness: Brightness.dark, - colorSchemeSeed: const Color(0xFF7CCF9E), - useMaterial3: true, - ), + theme: _generateTheme(false), + darkTheme: _generateTheme(true), themeMode: ThemeMode.system, ); } diff --git a/toolbox/spanner/lib/router.dart b/toolbox/spanner/lib/router.dart index 4ce3d82..0271cb0 100644 --- a/toolbox/spanner/lib/router.dart +++ b/toolbox/spanner/lib/router.dart @@ -2,6 +2,7 @@ import 'package:go_router/go_router.dart'; import 'package:spanner/features/welcome/screens/landing.dart'; +import 'package:spanner/features/settings/components/shell.dart'; import 'package:spanner/features/settings/screens/categories.dart'; import 'features/configurator/components/shell.dart'; @@ -77,9 +78,16 @@ final router = GoRouter( ], ), // TODO: Move to ShellRoute for desktop/tablet optimization - GoRoute( - path: "/settings", - builder: (context, state) => const SettingsCategories(), + ShellRoute( + builder: (context, state, child) { + return SettingsShell(child: child); + }, + routes: [ + GoRoute( + path: "/settings", + builder: (context, state) => const SettingsCategories(), + ), + ], ), GoRoute(path: "/", builder: (context, state) => const LandingPage()), ],