From dc4f3fe1e3413a35bbfdaac957f70f38dc5a575b Mon Sep 17 00:00:00 2001 From: Devin Stickells Date: Fri, 2 Aug 2024 17:33:03 +0200 Subject: [PATCH 1/3] feat: add github.io web deployment --- .metadata | 29 +++++++---------------------- Makefile | 39 +++++++++++++++++++++++++++++++++++++++ test/widget_test.dart | 30 ++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 Makefile create mode 100644 test/widget_test.dart diff --git a/.metadata b/.metadata index 20eb09c..9cef17b 100644 --- a/.metadata +++ b/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: 62bd79521d8d007524e351747471ba66696fc2d4 - channel: stable + revision: "b0850beeb25f6d5b10426284f506557f66181b36" + channel: "stable" project_type: app @@ -13,26 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - - platform: android - create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - - platform: ios - create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - - platform: linux - create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - - platform: macos - create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 + create_revision: b0850beeb25f6d5b10426284f506557f66181b36 + base_revision: b0850beeb25f6d5b10426284f506557f66181b36 - platform: web - create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - - platform: windows - create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 - base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 + create_revision: b0850beeb25f6d5b10426284f506557f66181b36 + base_revision: b0850beeb25f6d5b10426284f506557f66181b36 # User provided section diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d63d92e --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +# Makefile for deploying the Flutter web projects to GitHub +# from https://codewithandrea.com/articles/flutter-web-github-pages/ + +BASE_HREF = /$(OUTPUT)/ +GITHUB_USER = devsticks +GITHUB_REPO = https://github.com/$(GITHUB_USER)/$(OUTPUT) +BUILD_VERSION := $(shell grep 'version:' pubspec.yaml | awk '{print $$2}') + +# Deploy the Flutter web project to GitHub +deploy: +ifndef OUTPUT + $(error OUTPUT is not set. Usage: make deploy OUTPUT=) +endif + + @echo "Clean existing repository" + flutter clean + + @echo "Getting packages..." + flutter pub get + + @echo "Generating the web folder..." + flutter create . --platform web + + @echo "Building for web..." + flutter build web --base-href $(BASE_HREF) --release + + @echo "Deploying to git repository" + cd build/web && \ + git init && \ + git add . && \ + git commit -m "Deploy Version $(BUILD_VERSION)" && \ + git branch -M main && \ + git remote add origin $(GITHUB_REPO) && \ + git push -u -f origin main + + @echo "✅ Finished deploy: $(GITHUB_REPO)" + @echo "🚀 Flutter web URL: https://$(GITHUB_USER).github.io/$(OUTPUT)/" + +.PHONY: deploy \ No newline at end of file diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..faacf15 --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:rostrem/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} From 56efa028ee7ce4f63599a9bb7e3159ff9a3cf332 Mon Sep 17 00:00:00 2001 From: Devin Stickells Date: Fri, 2 Aug 2024 22:43:00 +0200 Subject: [PATCH 2/3] feat: add auto-deployment for main --- .github/workflows/deploy.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..863842d --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,24 @@ +name: Deploy to GitHub Pages + +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: 'stable' + + - name: Run Makefile Deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: make deploy OUTPUT=rostrem-website \ No newline at end of file From 439f34fec3c74da6516e58290b978ab6274d0c59 Mon Sep 17 00:00:00 2001 From: Devin Stickells Date: Sat, 3 Aug 2024 18:29:09 +0200 Subject: [PATCH 3/3] fix(layout): fix overflow issues --- lib/screens/roster_home_page.dart | 235 +++++++++++++++---------- lib/widgets/doctors_summary_table.dart | 4 +- lib/widgets/leave_management.dart | 46 ++--- test/widget_test.dart | 30 ---- 4 files changed, 166 insertions(+), 149 deletions(-) delete mode 100644 test/widget_test.dart diff --git a/lib/screens/roster_home_page.dart b/lib/screens/roster_home_page.dart index 481c1d2..3d54a64 100644 --- a/lib/screens/roster_home_page.dart +++ b/lib/screens/roster_home_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:rostrem/models/assignment_generator.dart'; -import 'package:rostrem/widgets/header_text.dart'; import 'package:rostrem/widgets/loading_overlay.dart'; import '../models/doctor.dart'; import '../models/shift.dart'; @@ -37,6 +36,8 @@ class RosterHomePageState extends State { // year and month for next month int year = DateTime.now().add(const Duration(days: 31)).year; int month = DateTime.now().add(const Duration(days: 31)).month; + late TextEditingController yearController; + late TextEditingController monthController; final List _loadingMessages = [ 'Preparing your new roster...', @@ -78,6 +79,8 @@ class RosterHomePageState extends State { @override void initState() { super.initState(); + yearController = TextEditingController(text: year.toString()); + monthController = TextEditingController(text: month.toString()); _initializeDoctors(); _initializeShifts(); _initializeRoster(); @@ -86,6 +89,8 @@ class RosterHomePageState extends State { @override void dispose() { _postCallBeforeLeaveValueNotifier.dispose(); + yearController.dispose(); + monthController.dispose(); super.dispose(); } @@ -250,35 +255,86 @@ class RosterHomePageState extends State { return Scaffold( appBar: AppBar( title: const Text('Doctors\' Overtime Call Roster'), - actions: [ - // Input for the year and month - Row( - children: [ - const Text('Year: '), - SizedBox( - width: 60, - child: TextField( - controller: TextEditingController(text: year.toString()), - keyboardType: TextInputType.number, - onChanged: (value) { - year = int.tryParse(value) ?? year; - _initializeShifts(); - }, - ), - ), - const Text('Month: '), - SizedBox( - width: 60, - child: TextField( - controller: TextEditingController(text: month.toString()), - keyboardType: TextInputType.number, - onChanged: (value) { - month = int.tryParse(value) ?? month; - _initializeShifts(); + actions: [ + LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + if (MediaQuery.of(context).size.width > 600) { + // Adjust threshold as needed + return Row( + children: [ + const Text('Year: '), + SizedBox( + width: 60, + child: TextField( + controller: yearController, + keyboardType: TextInputType.number, + onChanged: (value) { + year = int.tryParse(value) ?? year; + _initializeShifts(); + }, + ), + ), + const Text('Month: '), + SizedBox( + width: 60, + child: TextField( + controller: monthController, + keyboardType: TextInputType.number, + onChanged: (value) { + month = int.tryParse(value) ?? month; + _initializeShifts(); + }, + ), + ), + ], + ); + } else { + return IconButton( + icon: const Icon(Icons.settings), + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("Set Month"), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: yearController, + keyboardType: TextInputType.number, + decoration: + const InputDecoration(labelText: "Year"), + onChanged: (value) { + year = int.tryParse(value) ?? year; + _initializeShifts(); + }, + ), + TextField( + controller: monthController, + keyboardType: TextInputType.number, + decoration: + const InputDecoration(labelText: "Month"), + onChanged: (value) { + month = int.tryParse(value) ?? month; + _initializeShifts(); + }, + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Close'), + ), + ], + ); + }, + ); }, - ), - ), - ], + ); + } + }, ), IconButton( icon: const Icon(Icons.refresh), @@ -289,84 +345,75 @@ class RosterHomePageState extends State { ), ], ), - body: Stack( + body: Row( children: [ - Row( - children: [ - Expanded( - flex: 1, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Roster', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20.0, - ), - ), - const SizedBox(height: 8.0), - Expanded( - child: RosterDisplay( - shifts: shifts, - isPublicHoliday: _isPublicHoliday, - ), - ), - ], + Expanded( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + 'Roster', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20.0, + ), ), - ), + const SizedBox(height: 8.0), + Expanded( + child: RosterDisplay( + shifts: shifts, + isPublicHoliday: _isPublicHoliday, + ), + ), + ], ), - Expanded( - flex: 1, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Summary', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20.0, - ), - ), - const SizedBox(height: 8.0), - Expanded( - flex: 1, - child: DoctorsSummaryTable(doctors: doctors), - ), - const SizedBox(height: 16), - const Text( - 'Leave Management', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20.0, - ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + 'Summary', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20.0, ), - const SizedBox(height: 8.0), - Expanded( - flex: 1, - child: LeaveManagement( - doctors: doctors, - onAddLeave: _addLeaveDays, - onRemoveLeave: _removeLeaveBlock, - postCallBeforeLeaveValueNotifier: - _postCallBeforeLeaveValueNotifier, - ), + ), + const SizedBox(height: 8.0), + DoctorsSummaryTable(doctors: doctors), + const SizedBox(height: 16), + const Text( + 'Leave Management', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20.0, ), - ], - ), + ), + const SizedBox(height: 8.0), + LeaveManagement( + doctors: doctors, + onAddLeave: _addLeaveDays, + onRemoveLeave: _removeLeaveBlock, + postCallBeforeLeaveValueNotifier: + _postCallBeforeLeaveValueNotifier, + ), + ], ), ), - ], + ), ), ], ), floatingActionButton: FloatingActionButton( child: const Icon(Icons.download), onPressed: () { + // Assuming 'roster' is correctly defined somewhere in your code roster.downloadAsCsv(context); }, tooltip: 'Download as Spreadsheet (CSV)', diff --git a/lib/widgets/doctors_summary_table.dart b/lib/widgets/doctors_summary_table.dart index 5a6572d..c0f2278 100644 --- a/lib/widgets/doctors_summary_table.dart +++ b/lib/widgets/doctors_summary_table.dart @@ -8,8 +8,8 @@ class DoctorsSummaryTable extends StatelessWidget { @override Widget build(BuildContext context) { - return SingleChildScrollView( - scrollDirection: Axis.vertical, + return Container( + // scrollDirection: Axis.vertical, child: DataTable( columnSpacing: 10.0, // Adjust the column spacing as needed columns: const [ diff --git a/lib/widgets/leave_management.dart b/lib/widgets/leave_management.dart index c8c1c21..d9f2d32 100644 --- a/lib/widgets/leave_management.dart +++ b/lib/widgets/leave_management.dart @@ -91,7 +91,6 @@ class _LeaveManagementState extends State { children: [ Row( children: [ - // Check box for whether a doctor should be post-call the day before they start their leave Checkbox( value: _postCallBeforeLeave, onChanged: (value) { @@ -100,7 +99,7 @@ class _LeaveManagementState extends State { widget.postCallBeforeLeaveValueNotifier.value = value; }); }), - const Expanded(child: Text('Post-call the day before leave')), + Expanded(child: Text('Post-call the day before leave')), ], ), LayoutBuilder( @@ -122,27 +121,28 @@ class _LeaveManagementState extends State { } }, ), - Expanded( - child: ListView( - children: widget.doctors.expand((doctor) { - List> leaveBlocks = - _getLeaveBlocks(doctor.leaveDays); - return leaveBlocks.map((block) { - DateTime startDate = block.first; - DateTime endDate = block.last; - return ListTile( - title: Text( - '${doctor.name}: ${startDate.toIso8601String().split('T')[0]} - ${endDate.toIso8601String().split('T')[0]}'), - trailing: IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - widget.onRemoveLeave(doctor, block); - }, - ), - ); - }).toList(); - }).toList(), - ), + ListView( + shrinkWrap: true, // Allows ListView to take minimum needed space + physics: + NeverScrollableScrollPhysics(), // Disables scrolling within the ListView + children: widget.doctors.expand((doctor) { + List> leaveBlocks = + _getLeaveBlocks(doctor.leaveDays); + return leaveBlocks.map((block) { + DateTime startDate = block.first; + DateTime endDate = block.last; + return ListTile( + title: Text( + '${doctor.name}: ${startDate.toIso8601String().split('T')[0]} - ${endDate.toIso8601String().split('T')[0]}'), + trailing: IconButton( + icon: const Icon(Icons.delete), + onPressed: () { + widget.onRemoveLeave(doctor, block); + }, + ), + ); + }).toList(); + }).toList(), ), ], ); diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index faacf15..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:rostrem/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}