fix(frontend): improve custom back-button navigation for documents, students, and archives screens

This commit is contained in:
ssbg04 committed 2026-08-07 21:31:54 +08:00
1 parent 2e182f8301
commit 2ac3a791ce
6 files changed
+62 -16

No files matched your search

+23 -5
View File
@@ -88,16 +88,34 @@ Files backup/restore - mirror mode or zip -->
<!-- ## backend server backup/restore
- do not use zip and unzip -->
# ANDROID APP
# DOCUMENT SCREEN
- add back prevention when user press back button, if multi select menu active, it deactivates multi select menu
- add back prevention when user press back button, if user open student folder, back to student folders tab
- add back prevention active multi select
- 1st back, deactivates multi select
- 2nd back, navigates to dashboard screen
- if the mutli select deactive
- 1st back, navigate to dashboard
- add back prevention inside student folder
- 1st back, navigates back folder 'Student Folders' tab
- 2nd back, navigates to dashboard screen
- if the open folder is not present
- 1st back, navigate to dashboard
# STUDENT SCREEN
- update multi select menu actions design same from the document screen, multi menu replace temporary the line of Students Directory, search icon and filter section
- add back prevention when user press back button, if multi select menu active, it deactivates multi select menu
- add back prevention active multi select
- 1st back, deactivates multi select
- 2nd back, navigates to dashboard screen
- if the mutli select deactive
- 1st back, navigate to dashboard
# ARCHIVES SCREEN
- add back prevention when user press back button, if user open student folder, back to student folders list
- add back prevention inside student folder
- 1st back, navigates back folder 'Student Folders' tab
- 2nd back, navigates to dashboard screen
- if the open folder is not present
- 1st back, navigate to dashboard
@@ -216,6 +216,11 @@ class _AndroidBottomNavLayoutState extends ConsumerState<AndroidBottomNavLayout>
if (didPop) return;
if (activeTab != 'Dashboard') {
if (activeTab == 'Documents' ||
activeTab == 'Students' ||
activeTab == 'Archives') {
return;
}
_onNavTapped('Dashboard');
return;
}
@@ -446,17 +446,27 @@ class _ArchivesScreenState extends ConsumerState<ArchivesScreen>
final isFolderOpened = _openedFolderStudentId != null;
return PopScope(
canPop: !_isMultiSelectMode && !isFolderOpened,
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
if (ref.read(activeTabProvider) != 'Archives') return;
if (_isMultiSelectMode) {
setState(() {
_isMultiSelectMode = false;
_selectedDocumentIds.clear();
if (_openedFolderStudentId != null) {
_openedFolderStudentId = null;
_openedFolderName = null;
if (_tabController.index != 0) {
_tabController.index = 0;
}
}
});
ref.read(openedArchiveFolderProvider.notifier).setFolder(null);
ref.read(archiveDocumentQueryProvider.notifier).setStudentId(null);
return;
}
if (isFolderOpened) {
if (_openedFolderStudentId != null) {
setState(() {
_openedFolderStudentId = null;
_openedFolderName = null;
@@ -468,6 +478,7 @@ class _ArchivesScreenState extends ConsumerState<ArchivesScreen>
ref.read(archiveDocumentQueryProvider.notifier).setStudentId(null);
return;
}
ref.read(activeTabProvider.notifier).setTab('Dashboard');
},
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
@@ -22,8 +22,8 @@ import 'widgets/print_queue_modal.dart';
import 'widgets/student_profile_modal.dart';
import 'widgets/document_preview_modal.dart';
import 'widgets/download_guide_dialog.dart';
import '../../../../core/utils/download_service.dart';
import '../../../../core/network/api_constants.dart';
import '../../../core/utils/download_service.dart';
import '../../../core/network/api_constants.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'widgets/recycle_bin_modal.dart';
import '../../../domain/entities/document_model.dart';
@@ -695,14 +695,24 @@ class _DocumentsScreenState extends ConsumerState<DocumentsScreen>
final isFolderOpened = _openedFolderStudentId != null;
return PopScope(
canPop: !_isMultiSelectMode && _openedFolderStudentId == null,
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
if (ref.read(activeTabProvider) != 'Documents') return;
if (_isMultiSelectMode) {
setState(() {
_isMultiSelectMode = false;
_selectedDocumentIds.clear();
if (_openedFolderStudentId != null) {
_openedFolderStudentId = null;
_openedFolderName = null;
if (_tabController.index != 0) {
_tabController.index = 0;
}
}
});
ref.read(openedFolderProvider.notifier).setFolder(null);
ref.read(documentQueryProvider.notifier).setStudentId(null);
return;
}
if (_openedFolderStudentId != null) {
@@ -717,6 +727,7 @@ class _DocumentsScreenState extends ConsumerState<DocumentsScreen>
ref.read(documentQueryProvider.notifier).setStudentId(null);
return;
}
ref.read(activeTabProvider.notifier).setTab('Dashboard');
},
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
@@ -682,16 +682,18 @@ class _StudentsScreenState extends ConsumerState<StudentsScreen> {
].where((v) => v).length;
return PopScope(
canPop: !_showMultiSelect,
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
if (_showMultiSelect) {
if (ref.read(activeTabProvider) != 'Students') return;
if (_showMultiSelect || _selectedStudentIds.isNotEmpty) {
setState(() {
_showMultiSelect = false;
_selectedStudentIds.clear();
});
return;
}
ref.read(activeTabProvider.notifier).setTab('Dashboard');
},
child: Scaffold(
backgroundColor: Colors.transparent,
@@ -2123,7 +2125,7 @@ class _StudentsScreenState extends ConsumerState<StudentsScreen> {
: null,
child: InkWell(
onTap: () {
if (_showMultiSelect) {
if (_showMultiSelect || _selectedStudentIds.isNotEmpty) {
setState(() {
if (_selectedStudentIds.contains(s.id)) {
_selectedStudentIds.remove(s.id);
+2 -3
View File
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
// Use a relative import to reliably find your main.dart file
import '../lib/main.dart';
import 'package:frontend/main.dart';
void main() {
testWidgets('App boots up and displays the Splash Screen', (
@@ -12,8 +12,7 @@ void main() {
await tester.pumpWidget(const TisRmsApp());
// 2. Verify that our branding text is present on the Splash Screen
expect(find.text('TIS RMS'), findsOneWidget);
expect(find.text('Record Management System'), findsOneWidget);
expect(find.textContaining('TIS RMS'), findsWidgets);
// 3. Verify that the loading spinner is present
expect(find.byType(CircularProgressIndicator), findsOneWidget);