diff --git a/flutter_app/.metadata b/flutter_app/.metadata index 6e12c20..ea59ad0 100644 --- a/flutter_app/.metadata +++ b/flutter_app/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" + revision: "2663184aa79047d0a33a14a3b607954f8fdd8730" channel: "stable" project_type: app @@ -13,26 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: android - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: ios - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: linux - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: macos - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: web - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 - platform: windows - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 # User provided section @@ -41,5 +26,5 @@ migration: # # Files that are not part of the templates will be ignored by default. unmanaged_files: - - "lib/main.dart" - - "ios/Runner.xcodeproj/project.pbxproj" + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_app/lib/main.dart b/flutter_app/lib/main.dart index 878e68d..06ddaf0 100644 --- a/flutter_app/lib/main.dart +++ b/flutter_app/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:imacs/screens/home_screen.dart'; +import 'package:imacs/widgets/nav_bar_widget.dart'; void main() async { runApp(const App()); @@ -17,6 +18,12 @@ class App extends StatelessWidget { ), routes: { '/': (BuildContext context) => HomePage(title: 'WARG IMACS'), + '/logs': (BuildContext context) => + const PlaceholderScreen(title: 'Logs'), + '/camera': (BuildContext context) => + const PlaceholderScreen(title: 'Camera'), + '/sitl': (BuildContext context) => + const PlaceholderScreen(title: 'SITL'), }, ); } diff --git a/flutter_app/lib/screens/home_screen.dart b/flutter_app/lib/screens/home_screen.dart index 93f369c..09802e9 100644 --- a/flutter_app/lib/screens/home_screen.dart +++ b/flutter_app/lib/screens/home_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:imacs/modules/mavlink_communication.dart'; import 'package:imacs/modules/get_drone_information.dart'; import 'package:imacs/widgets/drone_information_widget.dart'; +import 'package:imacs/widgets/nav_bar_widget.dart'; class HomePage extends StatelessWidget { HomePage({Key? key, required this.title}) : super(key: key); @@ -13,16 +14,16 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: Column( - children: [ - DroneInformation( - getDroneInformation: GetDroneInformation(comm: comm), - ), - ], - ), - ); + appBar: AppBar( + title: Text(title), + ), + body: Column( + children: [ + DroneInformation( + getDroneInformation: GetDroneInformation(comm: comm), + ), + ], + ), + bottomNavigationBar: const NavBar()); } } diff --git a/flutter_app/lib/widgets/nav_bar_widget.dart b/flutter_app/lib/widgets/nav_bar_widget.dart new file mode 100644 index 0000000..6e42d93 --- /dev/null +++ b/flutter_app/lib/widgets/nav_bar_widget.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; + +/// Widget for navigating between different screens +/// +/// This widget displays the different sceeens in tabs along a bar at +/// the bottom of the screen. When clicked, each tab will navigate to +/// the corresponding screen. +class NavBar extends StatelessWidget { + /// @brief Constructs a NavBar widget. + const NavBar({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BottomNavigationBar( + onTap: (int index) { + switch (index) { + case 0: + Navigator.pushReplacementNamed(context, '/'); + break; + case 1: + Navigator.popAndPushNamed(context, '/logs'); + break; + case 2: + Navigator.popAndPushNamed(context, '/camera'); + break; + default: + Navigator.popAndPushNamed(context, '/sitl'); + break; + } + }, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.home_sharp), + label: 'Home', + ), + BottomNavigationBarItem( + icon: Icon(Icons.format_list_bulleted_sharp), + label: 'Logs', + ), + BottomNavigationBarItem( + icon: Icon(Icons.camera_sharp), + label: 'Camera', + ), + BottomNavigationBarItem( + icon: Icon(Icons.check_box_sharp), + label: 'SITL', + ) + ], + unselectedItemColor: Colors.black, + selectedItemColor: Colors.black, + showUnselectedLabels: true, + ); + } +} + +/// A placeholder screen with title text and the navigation bar +/// +/// This widget is a placeholder screen containing a title, +/// placeholder body, and the navigation bar. +class PlaceholderScreen extends StatelessWidget { + /// @brief Constructs a PlaceholderScreen widget. + const PlaceholderScreen({Key? key, required this.title}) : super(key: key); + + final String title; + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: const Placeholder(), + bottomNavigationBar: const NavBar()); + } +} diff --git a/flutter_app/pubspec.lock b/flutter_app/pubspec.lock index df9b2af..3e0a02f 100644 --- a/flutter_app/pubspec.lock +++ b/flutter_app/pubspec.lock @@ -477,10 +477,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.4" + version: "14.2.5" watcher: dependency: transitive description: diff --git a/flutter_app/test/widget/nav_bar_widget_test.dart b/flutter_app/test/widget/nav_bar_widget_test.dart new file mode 100644 index 0000000..8eff77a --- /dev/null +++ b/flutter_app/test/widget/nav_bar_widget_test.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:imacs/widgets/nav_bar_widget.dart'; + +void main() { + group('Navbar widget', () { + testWidgets('NavBar navigates to correct route', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (context) => const Scaffold( + body: Text('Home Page'), bottomNavigationBar: NavBar()), + '/logs': (context) => const Scaffold( + body: Text('Logs Page'), bottomNavigationBar: NavBar()), + '/camera': (context) => const Scaffold( + body: Text('Camera Page'), bottomNavigationBar: NavBar()), + '/sitl': (context) => const Scaffold( + body: Text('SITL Page'), bottomNavigationBar: NavBar()), + }, + ), + ); + + expect(find.byType(BottomNavigationBar), findsOneWidget); + + // Test home icon tap + await tester.tap(find.text('Home')); + await tester.pumpAndSettle(); + expect(find.text('Home Page'), findsOneWidget); + + await tester.tap(find.text('Logs')); + await tester.pumpAndSettle(); + expect(find.text('Logs Page'), findsOneWidget); + + await tester.tap(find.text('Camera')); + await tester.pumpAndSettle(); + expect(find.text('Camera Page'), findsOneWidget); + + await tester.tap(find.text('SITL')); + await tester.pumpAndSettle(); + expect(find.text('SITL Page'), findsOneWidget); + }); + }); +}