diff --git a/assets/icons/error.png b/assets/icons/error.png new file mode 100644 index 0000000..ef023e7 Binary files /dev/null and b/assets/icons/error.png differ diff --git a/assets/images/logos.png b/assets/images/logos.png new file mode 100644 index 0000000..a4cd6f9 Binary files /dev/null and b/assets/images/logos.png differ diff --git a/lib/main.dart b/lib/main.dart index 7c8cecb..d1c6a62 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,36 +6,43 @@ void main() { // Ensures that an instance of the widgets library is initialized. WidgetsFlutterBinding.ensureInitialized(); - // Set landscape preferred orientation + // Set the preferred orientation to landscape. SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); - // Set app in fullscreen mode + // Set the app in fullscreen mode, hiding the system UI overlays. SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); runApp(const Launcher()); } +/// The Launcher widget serves as the entry point for the app. +/// +/// It sets up the background image, the theme, and the initial route for the app. class Launcher extends StatelessWidget { const Launcher({super.key}); @override Widget build(BuildContext context) { - return Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage("assets/images/background.jpg"), - fit: BoxFit.fill, - ), + // Set a background image for the entire app. + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/images/background.jpg"), + fit: BoxFit.fill, ), - child: MaterialApp( - title: 'SpaceVisualizations', - theme: ThemeData(fontFamily: 'Forgotten Futurist'), - onGenerateRoute: makeRoute, - initialRoute: '/', - )); + ), + child: MaterialApp( + title: 'SpaceVisualizations', + // Set the app theme with a custom font. + theme: ThemeData(fontFamily: 'Forgotten Futurist'), + // Define the route generator function. + onGenerateRoute: makeRoute, + // Set the initial route to the splash screen. + initialRoute: '/splash', + ), + ); } -} \ No newline at end of file +} diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 14623cd..b9a08a4 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,9 +1,11 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:lg_space_visualizations/pages/template_page.dart'; +import 'package:lg_space_visualizations/widget/image_button.dart'; import 'package:lg_space_visualizations/utils/styles.dart'; +import 'package:lg_space_visualizations/widget/logo.dart'; +/// The home page of the application, displayed using the [TemplatePage] widget. class HomePage extends StatefulWidget { const HomePage({super.key}); @@ -19,12 +21,34 @@ class _HomePageState extends State { showTopBar: false, children: [ Expanded( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(borderRadius), - color: backgroundColor, + child: Column( + children: [ + SizedBox(height: spaceBetweenWidgets), + const Logo(), + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + ImageButton( + width: 425, + height: 220, + image: const AssetImage('assets/images/rover.png'), + text: 'MARS 2020\nMISSION', + onPressed: () {}, + ), + ImageButton( + width: 425, + height: 220, + image: const AssetImage('assets/images/earth.png'), + text: 'SATELLITE\nEARTH ORBITS', + onPressed: () {}, + ), + ], + ), + ) + ], ), - )), + ) ], ); } diff --git a/lib/pages/splash_screen.dart b/lib/pages/splash_screen.dart new file mode 100644 index 0000000..76b6610 --- /dev/null +++ b/lib/pages/splash_screen.dart @@ -0,0 +1,55 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:lg_space_visualizations/utils/styles.dart'; +import 'package:lg_space_visualizations/widget/logo.dart'; + +/// A widget that represents the splash screen of the app. +/// +/// It displays the logos and a loading indicator at the bottom. +/// When initialized, it waits for 5 seconds before navigating to the home page.s +class SplashPage extends StatefulWidget { + const SplashPage({super.key}); + + @override + _SplashPageState createState() => _SplashPageState(); +} + +class _SplashPageState extends State { + @override + void initState() { + super.initState(); + + // Timer to navigate to the home page after 5 seconds. + Timer(const Duration(seconds: 5), () { + Navigator.of(context).pushReplacementNamed('/home'); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: secondaryColor, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 20), + const Logo(), + Expanded( + child: + Image.asset('assets/images/logos.png', fit: BoxFit.contain), + ), + SizedBox( + height: 4, + child: LinearProgressIndicator( + color: backgroundColor, + backgroundColor: secondaryColor, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/template_page.dart b/lib/pages/template_page.dart index 278ec95..43e6290 100644 --- a/lib/pages/template_page.dart +++ b/lib/pages/template_page.dart @@ -3,16 +3,26 @@ import 'package:lg_space_visualizations/utils/styles.dart'; import 'package:lg_space_visualizations/widget/bottom_bar.dart'; import 'package:lg_space_visualizations/widget/top_bar.dart'; +/// A page template that includes an optional top bar and a bottom bar. +/// +/// The [TemplatePage] widget allows you to specify a [title] and [children] +/// widgets to be displayed. The top bar visibility can be controlled with [showTopBar]. class TemplatePage extends StatefulWidget { - final List children; + /// The title of the page displayed in the top bar. final String title; + + /// The widgets to be displayed in the body of the page. + final List children; + + /// Controls the visibility of the top bar. final bool showTopBar; - const TemplatePage( - {super.key, - required this.title, - this.showTopBar = true, - required this.children}); + const TemplatePage({ + super.key, + required this.title, + this.showTopBar = true, + required this.children, + }); @override _TemplatePageState createState() => _TemplatePageState(); @@ -22,13 +32,15 @@ class _TemplatePageState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.transparent, - appBar: widget.showTopBar ? TopBar(title: widget.title) : null, - body: Padding( - padding: EdgeInsets.all(spaceBetweenWidgets), - child: Row( - children: widget.children, - )), - bottomNavigationBar: const BottomBar()); + backgroundColor: Colors.transparent, + appBar: widget.showTopBar ? TopBar(title: widget.title) : null, + body: Padding( + padding: EdgeInsets.all(spaceBetweenWidgets), + child: Row( + children: widget.children, + ), + ), + bottomNavigationBar: const BottomBar(), + ); } } diff --git a/lib/utils/routes.dart b/lib/utils/routes.dart index 974fa15..8dc2c32 100644 --- a/lib/utils/routes.dart +++ b/lib/utils/routes.dart @@ -1,21 +1,42 @@ import 'package:flutter/material.dart'; import 'package:lg_space_visualizations/pages/home_page.dart'; +import 'package:lg_space_visualizations/pages/splash_screen.dart'; +/// Generates a [Route] for the application based on the provided [RouteSettings]. +/// +/// This function takes [settings] as a parameter, which contains the name of +/// the route to be generated. It returns a [Route] corresponding to the route +/// name. If the route name is not recognized, it defaults to the home page. Route makeRoute(RouteSettings settings) { + WidgetBuilder builder; switch (settings.name) { - case '/': - return customRoute(const HomePage()); + case '/home': + // Route for the home page. + builder = (BuildContext context) => const HomePage(); + break; + case '/splash': + // Route for the splash screen. + builder = (BuildContext context) => const SplashPage(); + break; default: - throw 'Route is not defined'; + // Default route if no match is found, redirects to the home page. + builder = (BuildContext context) => const HomePage(); } + // Return a custom route with a very short transition animation. + return AnimationPageRoute(builder: builder, settings: settings); } -PageRouteBuilder customRoute(Widget page) { - return PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => page, - transitionDuration: const Duration(milliseconds: 500), - transitionsBuilder: (context, animation, animation2, child) { - return FadeTransition(opacity: animation, child: child); - }, - ); +/// A custom [MaterialPageRoute] that disables transition animations but keeps a transition duration of 10 ms. +class AnimationPageRoute extends MaterialPageRoute { + AnimationPageRoute({required super.builder, super.settings}); + + @override + Duration get transitionDuration => const Duration(milliseconds: 10); + + @override + Widget buildTransitions(BuildContext context, Animation animation, + Animation secondaryAnimation, Widget child) { + // Return the child widget without any transition animations. + return child; + } } diff --git a/lib/utils/styles.dart b/lib/utils/styles.dart index 621ca58..99e2145 100644 --- a/lib/utils/styles.dart +++ b/lib/utils/styles.dart @@ -1,25 +1,56 @@ import 'package:flutter/material.dart'; -// Dimensions +/// Dimensions used in the application. double borderRadius = 10.0; double barHeight = 60.0; double barWidth = 1366.0; -// Colors +/// Colors used throughout in the application. Color primaryColor = const Color(0xFF000000); Color secondaryColor = const Color(0xFF281F5E); Color backgroundColor = const Color(0xFFD9D9D9); Color grey = const Color(0xFFA7A7A7); -// Extra + +/// Spacing used between widgets. double spaceBetweenWidgets = 20.0; -// Text styles -TextStyle hugeTitle = TextStyle(color: backgroundColor, fontWeight: FontWeight.bold, fontSize: 80); -TextStyle bigTitle = TextStyle(color: primaryColor, fontWeight: FontWeight.bold, fontSize: 40); -TextStyle middleTitle = TextStyle(color: primaryColor, fontWeight: FontWeight.bold, fontSize: 30); +/// Text styles used in the application. +TextStyle hugeTitle = TextStyle( + color: backgroundColor, + fontWeight: FontWeight.bold, + fontSize: 80, +); + +TextStyle bigTitle = TextStyle( + color: primaryColor, + fontWeight: FontWeight.bold, + fontSize: 40, +); + +TextStyle middleTitle = TextStyle( + color: primaryColor, + fontWeight: FontWeight.bold, + fontSize: 30, +); + +TextStyle bigText = TextStyle( + color: primaryColor, + fontSize: 25, +); + +TextStyle middleText = TextStyle( + color: primaryColor, + fontSize: 20, +); -TextStyle bigText = TextStyle(color: primaryColor, fontSize: 25); -TextStyle middleText = TextStyle(color: primaryColor, fontSize: 20); +TextStyle buttonText = TextStyle( + color: backgroundColor, + fontSize: 20, +); -TextStyle buttonText = TextStyle(color: backgroundColor, fontSize: 20); -TextStyle buttonTextBold = TextStyle(color: backgroundColor, fontWeight: FontWeight.bold, height: 1.2, fontSize: 40); \ No newline at end of file +TextStyle buttonTextBold = TextStyle( + color: backgroundColor, + fontWeight: FontWeight.bold, + height: 1.2, + fontSize: 40, +); diff --git a/lib/widget/bottom_bar.dart b/lib/widget/bottom_bar.dart index 2fbe5a1..57dd969 100644 --- a/lib/widget/bottom_bar.dart +++ b/lib/widget/bottom_bar.dart @@ -4,6 +4,10 @@ import 'package:lg_space_visualizations/widget/button.dart'; import 'package:lg_space_visualizations/widget/custom_icon.dart'; import 'package:lg_space_visualizations/widget/led_status.dart'; +/// Bottom navigation bar with various buttons and a status indicator. +/// +/// The [BottomBar] contains buttons for navigating to the home, settings, service, and info pages, +/// with a LED status indicator. It provides a common bottom navigation interface across the application. class BottomBar extends StatelessWidget { const BottomBar({super.key}); @@ -11,84 +15,89 @@ class BottomBar extends StatelessWidget { Widget build(BuildContext context) { return Container( margin: EdgeInsets.only( - bottom: spaceBetweenWidgets, - left: spaceBetweenWidgets, - right: spaceBetweenWidgets), + bottom: spaceBetweenWidgets, + left: spaceBetweenWidgets, + right: spaceBetweenWidgets, + ), height: barHeight, decoration: BoxDecoration( borderRadius: BorderRadius.circular(borderRadius), color: backgroundColor, ), child: Padding( - padding: - const EdgeInsets.only(left: 20, right: 20, top: 5, bottom: 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Button( - borderRadius: BorderRadius.circular(borderRadius), - color: secondaryColor, - icon: CustomIcon( - name: 'home', - width: 35, - height: 35, - color: backgroundColor, - ), - padding: const EdgeInsets.only( - left: 25, right: 25, top: 8, bottom: 8), - onPressed: () { - // Navigate to home only if the current route is not home ('/') - if (ModalRoute.of(context)!.settings.name != '/') { - Navigator.pushNamed(context, '/'); - } - }), - const Spacer(), - Button( - color: Colors.transparent, - borderRadius: BorderRadius.circular(0), - icon: CustomIcon( - name: "settings", - color: secondaryColor, - width: 40, - height: 40, - ), - onPressed: () { - // Navigate to settings only if the current route is not settings ('/settings') - if (ModalRoute.of(context)!.settings.name != '/settings') { - Navigator.pushNamed(context, '/settings'); - } - }), - Container(width: 35), - Button( - color: Colors.transparent, - borderRadius: BorderRadius.circular(0), - icon: CustomIcon( - name: "services", - color: secondaryColor, - width: 40, - height: 40, - ), - onPressed: () { - // Navigate to service only if the current route is not service ('/service') - if (ModalRoute.of(context)!.settings.name != '/service') { - Navigator.pushNamed(context, '/service'); - } - }), - Container(width: 35), - Button( - color: Colors.transparent, - borderRadius: BorderRadius.circular(0), - icon: CustomIcon( - name: "info", - color: secondaryColor, - width: 40, - height: 40, - ), - onPressed: () {}), - Container(width: 40), - const LedStatus(isOn: false, size: 35) - ], - )), + padding: const EdgeInsets.only(left: 20, right: 20, top: 5, bottom: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Button( + borderRadius: BorderRadius.circular(borderRadius), + color: secondaryColor, + icon: CustomIcon( + name: 'home', + width: 35, + height: 35, + color: backgroundColor, + ), + padding: + const EdgeInsets.only(left: 25, right: 25, top: 8, bottom: 8), + onPressed: () { + // Navigate to home only if the current route is not home ('/') + if (ModalRoute.of(context)!.settings.name != '/') { + Navigator.pushNamed(context, '/'); + } + }, + ), + const Spacer(), + Button( + color: Colors.transparent, + borderRadius: BorderRadius.circular(0), + icon: CustomIcon( + name: "settings", + color: secondaryColor, + width: 40, + height: 40, + ), + onPressed: () { + // Navigate to settings only if the current route is not settings ('/settings') + if (ModalRoute.of(context)!.settings.name != '/settings') { + Navigator.pushNamed(context, '/settings'); + } + }, + ), + Container(width: 35), + Button( + color: Colors.transparent, + borderRadius: BorderRadius.circular(0), + icon: CustomIcon( + name: "services", + color: secondaryColor, + width: 40, + height: 40, + ), + onPressed: () { + // Navigate to service only if the current route is not service ('/service') + if (ModalRoute.of(context)!.settings.name != '/service') { + Navigator.pushNamed(context, '/service'); + } + }, + ), + Container(width: 35), + Button( + color: Colors.transparent, + borderRadius: BorderRadius.circular(0), + icon: CustomIcon( + name: "info", + color: secondaryColor, + width: 40, + height: 40, + ), + onPressed: () {}, + ), + Container(width: 40), + const LedStatus(status: false, size: 35) + ], + ), + ), ); } } diff --git a/lib/widget/button.dart b/lib/widget/button.dart index ae69da0..10ec53e 100644 --- a/lib/widget/button.dart +++ b/lib/widget/button.dart @@ -2,61 +2,87 @@ import 'package:flutter/material.dart'; import 'package:lg_space_visualizations/widget/custom_icon.dart'; import 'package:lg_space_visualizations/utils/styles.dart'; +/// A customizable button widget that can display an icon and optional text. +/// +/// The [Button] widget allows for flexible customization of its appearance and behavior. +/// It supports displaying an icon with optional text, which can be arranged either in a single line or across multiple lines. +/// The [icon] and [onPressed] parameters are required. The [color], [borderRadius], [text], +/// [padding], [bold], and [multiLine] parameters are optional and have default values. class Button extends StatelessWidget { + /// The icon to be displayed inside the button. final CustomIcon icon; + + /// The background color of the button. final Color color; + + /// The border radius of the button. final BorderRadius borderRadius; + + /// The callback function to be executed when the button is pressed. final VoidCallback onPressed; + + /// Optional text to be displayed under the icon. final String? text; + + /// The padding inside the button. final EdgeInsets padding; - // set to true if you want the text to be bold + /// Set the text to bold. final bool bold; - // set to true if you want the icon and text to be in different lines + + /// Set the button in multi-line mode. The icon will be above the text. final bool multiLine; - const Button( - {super.key, - required this.icon, - this.color = Colors.transparent, - this.borderRadius = BorderRadius.zero, - required this.onPressed, - this.text, - this.padding = EdgeInsets.zero, - this.bold = false, - this.multiLine = false}); + const Button({ + super.key, + required this.icon, + this.color = Colors.transparent, + this.borderRadius = BorderRadius.zero, + required this.onPressed, + this.text, + this.padding = EdgeInsets.zero, + this.bold = false, + this.multiLine = false, + }); @override Widget build(BuildContext context) { return GestureDetector( - onTap: onPressed, - child: Container( - decoration: BoxDecoration( - borderRadius: borderRadius, - color: color, - ), - child: text != null - ? !multiLine - ? Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - icon, - SizedBox(width: spaceBetweenWidgets), - Text(text!, style: buttonText) - ], - ) - : Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: spaceBetweenWidgets), - icon, - SizedBox(height: spaceBetweenWidgets), - Text(text!, textAlign: TextAlign.center, - style: bold ? buttonTextBold : buttonText) - ], - ) - : Padding(padding: padding, child: icon), - )); + onTap: onPressed, + child: Container( + decoration: BoxDecoration( + borderRadius: borderRadius, + color: color, + ), + child: text != null + ? !multiLine + ? Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + icon, + SizedBox(width: spaceBetweenWidgets), + Text(text!, style: buttonText), + ], + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: spaceBetweenWidgets), + icon, + SizedBox(height: spaceBetweenWidgets), + Text( + text!, + textAlign: TextAlign.center, + style: bold ? buttonTextBold : buttonText, + ), + ], + ) + : Padding( + padding: padding, + child: icon, + ), + ), + ); } } diff --git a/lib/widget/custom_icon.dart b/lib/widget/custom_icon.dart index 8ef7795..7f00942 100644 --- a/lib/widget/custom_icon.dart +++ b/lib/widget/custom_icon.dart @@ -1,12 +1,29 @@ import 'package:flutter/material.dart'; +/// A widget that displays a custom icon from the asset folder. +/// +/// The [CustomIcon] widget allows you to display a custom icon by providing the +/// [name] of the icon file with its [width], [height], and [color]. class CustomIcon extends StatelessWidget { + /// The name of the icon file (without extension) to be displayed. final String name; + + /// The width of the icon. final double width; + + /// The height of the icon. final double height; + + /// The color to apply to the icon. final Color color; - const CustomIcon({super.key, required this.name, required this.width, required this.height, required this.color}); + const CustomIcon({ + super.key, + required this.name, + required this.width, + required this.height, + required this.color, + }); @override Widget build(BuildContext context) { @@ -17,4 +34,4 @@ class CustomIcon extends StatelessWidget { color: color, ); } -} \ No newline at end of file +} diff --git a/lib/widget/image_button.dart b/lib/widget/image_button.dart new file mode 100644 index 0000000..47c181a --- /dev/null +++ b/lib/widget/image_button.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:lg_space_visualizations/utils/styles.dart'; + +/// A widget that displays an image button with text. +/// +/// The [ImageButton] widget allows you to display an image with text. +/// The button can be customized with [image], [width], [height], [onPressed], and [text] required parameters . +class ImageButton extends StatelessWidget { + /// The image to be displayed inside the button. + final ImageProvider image; + + /// The width of the button. + final double width; + + /// The height of the button. + final double height; + + /// The callback function to be executed when the button is pressed. + final VoidCallback onPressed; + + /// The text to be displayed inside the button. + final String text; + + const ImageButton({ + super.key, + required this.image, + required this.width, + required this.height, + required this.onPressed, + required this.text, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: Container( + height: height, + width: width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(borderRadius), + color: backgroundColor, + image: DecorationImage( + image: image, + fit: BoxFit.fitHeight, + alignment: Alignment.bottomLeft, + ), + ), + child: Padding( + padding: EdgeInsets.all(spaceBetweenWidgets), + child: Align( + alignment: Alignment.centerRight, + child: Text( + text, + style: bigTitle, + textAlign: TextAlign.center, + ), + ), + ), + ), + ); + } +} diff --git a/lib/widget/led_status.dart b/lib/widget/led_status.dart index ee89087..b2f9fff 100644 --- a/lib/widget/led_status.dart +++ b/lib/widget/led_status.dart @@ -1,11 +1,22 @@ import 'package:flutter/material.dart'; import 'package:lg_space_visualizations/utils/styles.dart'; +/// A widget that displays a circular LED indicator. +/// +/// The [LedStatus] widget represents an LED that indicates the connection status with the Liquid Galaxy and the application. +/// You can customize it with the required parameters [size] (diameter) and [status] (on/off). class LedStatus extends StatelessWidget { - final bool isOn; + /// Indicates the LED status (true -> connected, false -> not connected). + final bool status; + + /// The size of the LED. final double size; - const LedStatus({super.key, required this.isOn, required this.size}); + const LedStatus({ + super.key, + required this.status, + required this.size, + }); @override Widget build(BuildContext context) { @@ -14,7 +25,7 @@ class LedStatus extends StatelessWidget { height: size, decoration: BoxDecoration( shape: BoxShape.circle, - color: isOn ? Colors.green : Colors.red, + color: status ? Colors.green : Colors.red, border: Border.all( color: secondaryColor, width: 2.5, @@ -22,4 +33,4 @@ class LedStatus extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/widget/logo.dart b/lib/widget/logo.dart new file mode 100644 index 0000000..9094c61 --- /dev/null +++ b/lib/widget/logo.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:lg_space_visualizations/utils/styles.dart'; + +/// A widget that displays the application's logo. +/// +/// The [Logo] widget shows an [image] with the name of the application. +class Logo extends StatelessWidget { + /// The image to be displayed as the logo. + /// + /// Defaults to `assets/images/logo.png`. + final AssetImage image; + + const Logo( + {super.key, this.image = const AssetImage('assets/images/logo.png')}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Image(image: image, height: 200), + Text("Space Visualizations", style: hugeTitle), + Transform.translate( + offset: const Offset(0, -25), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + color: backgroundColor, + height: 10, + width: 175, + margin: const EdgeInsets.only(right: 25), + ), + Text( + "for Liquid Galaxy", + style: bigTitle.apply(color: backgroundColor), + ), + Container( + color: backgroundColor, + height: 10, + width: 175, + margin: const EdgeInsets.only(left: 25), + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/widget/top_bar.dart b/lib/widget/top_bar.dart index fdc8e6c..df27eaa 100644 --- a/lib/widget/top_bar.dart +++ b/lib/widget/top_bar.dart @@ -4,8 +4,15 @@ import 'package:lg_space_visualizations/utils/styles.dart'; import 'package:lg_space_visualizations/widget/custom_icon.dart'; import 'package:lg_space_visualizations/widget/button.dart'; +/// A widget that displays the top bar with a title and a back button. +/// +/// The [TopBar] widget shows a back button on the left and a [title] in the center. +/// It provides a common top navigation interface for the application. class TopBar extends StatelessWidget implements PreferredSizeWidget { + /// The title to be displayed in the top bar. final String title; + + /// The height of the top bar. final double height = barHeight + spaceBetweenWidgets; TopBar({super.key, required this.title}); @@ -16,43 +23,54 @@ class TopBar extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { return Container( - margin: EdgeInsets.only( - top: spaceBetweenWidgets, - left: spaceBetweenWidgets, - right: spaceBetweenWidgets), - child: Row(children: [ + margin: EdgeInsets.only( + top: spaceBetweenWidgets, + left: spaceBetweenWidgets, + right: spaceBetweenWidgets, + ), + child: Row( + children: [ Expanded( - flex: 1, // 8.3% of space - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(borderRadius), - color: backgroundColor, + flex: 1, // 8.3% of space + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(borderRadius), + color: backgroundColor, + ), + child: Center( + child: Button( + color: backgroundColor, + icon: CustomIcon( + name: 'back', + width: 50, + height: 50, + color: primaryColor, ), - child: Center( - child: Button( - color: backgroundColor, - icon: CustomIcon( - name: 'back', - width: 50, - height: 50, - color: primaryColor), - onPressed: () { - Navigator.pop(context); - }), - ))), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ), + ), SizedBox(width: spaceBetweenWidgets), Expanded( - flex: 11, // 91.7% of space - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(borderRadius), - color: backgroundColor, - ), - child: Center( - child: Text( - title, - style: bigTitle, - )))), - ])); + flex: 11, // 91.7% of space + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(borderRadius), + color: backgroundColor, + ), + child: Center( + child: Text( + title, + style: bigTitle, + ), + ), + ), + ), + ], + ), + ); } }