fix(ui): add backdrop overlay mini blur, search bar margins, and lock backdrop positioning on search active

This commit is contained in:
ssbg04 committed 2026-08-22 20:22:40 +08:00
1 parent 6b35dae427
commit 2e25b78c52
27 files changed
+89 -77

No files matched your search

@@ -2,7 +2,6 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../core/constants/app_colors.dart';
import '../../core/constants/app_sizes.dart';
import '../screens/dashboard/dashboard_screen.dart';
import '../screens/settings/settings_screen.dart';
import '../screens/students/students_screen.dart';
@@ -265,11 +264,20 @@ class _AndroidBottomNavLayoutState extends ConsumerState<AndroidBottomNavLayout>
SystemNavigator.pop();
}
},
child: SafeArea(
child: Scaffold(
key: _scaffoldKey,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
child: Builder(
builder: (context) {
final mediaQuery = MediaQuery.of(context);
final lockedMediaQuery = mediaQuery.copyWith(
viewInsets: EdgeInsets.zero,
padding: mediaQuery.viewPadding,
);
return MediaQuery(
data: lockedMediaQuery,
child: Scaffold(
key: _scaffoldKey,
resizeToAvoidBottomInset: false,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
foregroundColor: Theme.of(context).colorScheme.onSurface,
iconTheme: IconThemeData(color: Theme.of(context).colorScheme.onSurface),
@@ -524,9 +532,11 @@ class _AndroidBottomNavLayoutState extends ConsumerState<AndroidBottomNavLayout>
),
),
),
),
);
}
);
},
),
);
}
Widget _buildDrawerItem(
Map<String, dynamic> tab,
@@ -375,23 +375,13 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
child: WindowCaption(
brightness: Brightness.dark,
backgroundColor: AppColors.primaryGreen,
title: Row(
children: [
Image.asset(
'assets/images/logo.png',
width: 18,
height: 18,
),
const SizedBox(width: 8),
const Text(
'TIS Record Management System',
style: TextStyle(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
],
title: const Text(
'TIS Record Management System',
style: TextStyle(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
),
),
@@ -1065,7 +1065,8 @@ class _ArchivesScreenState extends ConsumerState<ArchivesScreen>
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
backgroundColor: Colors.transparent,
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: (!_isMultiSelectMode &&
!_searchFocusNode.hasFocus &&
@@ -1188,7 +1189,7 @@ class _ArchivesScreenState extends ConsumerState<ArchivesScreen>
return Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.only(top: kToolbarHeight + 24),
padding: const EdgeInsets.fromLTRB(16, kToolbarHeight + 24, 16, 0),
child: Material(
color: isDark ? AppColors.darkSurfaceCard : Colors.white,
elevation: 4,
@@ -305,6 +305,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
focusNode: _shortcutFocusNode,
autofocus: true,
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: SafeArea(
child: dashboardAsync.when(
@@ -703,7 +704,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
return Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.only(top: kToolbarHeight + 24),
padding: const EdgeInsets.fromLTRB(16, kToolbarHeight + 24, 16, 0),
child: Material(
color: isDark ? AppColors.darkSurfaceCard : Colors.white,
elevation: 4,
@@ -679,7 +679,8 @@ class _DocumentsScreenState extends ConsumerState<DocumentsScreen>
onTap: () => FocusScope.of(context).unfocus(),
behavior: HitTestBehavior.translucent,
child: Scaffold(
backgroundColor: Colors.transparent,
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton:
(_tabController.index != 2 &&
@@ -884,7 +885,7 @@ class _DocumentsScreenState extends ConsumerState<DocumentsScreen>
return Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.only(top: kToolbarHeight + 24),
padding: const EdgeInsets.fromLTRB(16, kToolbarHeight + 24, 16, 0),
child: Material(
color: isDark ? AppColors.darkSurfaceCard : Colors.white,
elevation: 4,
@@ -246,23 +246,13 @@ class _LoginScreenState extends ConsumerState<LoginScreen> with SingleTickerProv
child: WindowCaption(
brightness: Brightness.dark,
backgroundColor: AppColors.primaryGreen,
title: Row(
children: [
Image.asset(
'assets/images/logo.png',
width: 18,
height: 18,
),
const SizedBox(width: 8),
const Text(
'TIS Record Management System',
style: TextStyle(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
],
title: const Text(
'TIS Record Management System',
style: TextStyle(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
),
),
@@ -479,6 +479,7 @@ class _ReportsScreenState extends ConsumerState<ReportsScreen> {
final storageAsync = ref.watch(storageStatsProvider);
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: SafeArea(
child: RefreshIndicator(
@@ -243,23 +243,13 @@ class _SplashScreenState extends ConsumerState<SplashScreen>
child: WindowCaption(
brightness: Brightness.dark,
backgroundColor: AppColors.primaryGreen,
title: Row(
children: [
Image.asset(
'assets/images/logo.png',
width: 18,
height: 18,
),
const SizedBox(width: 8),
const Text(
'TIS Record Management System',
style: TextStyle(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
],
title: const Text(
'TIS Record Management System',
style: TextStyle(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
),
),
@@ -810,7 +810,8 @@ class _StudentsScreenState extends ConsumerState<StudentsScreen> {
child: _buildDragDropWrapper(
context,
child: Scaffold(
backgroundColor: Colors.transparent,
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton:
(widget.userRole == 'teacher' ||
@@ -944,7 +945,7 @@ class _StudentsScreenState extends ConsumerState<StudentsScreen> {
return Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.only(top: kToolbarHeight + 24),
padding: const EdgeInsets.fromLTRB(16, kToolbarHeight + 24, 16, 0),
child: Material(
color: isDark ? AppColors.darkSurfaceCard : Colors.white,
elevation: 4,
@@ -478,7 +478,8 @@ class _UsersScreenState extends ConsumerState<UsersScreen> {
focusNode: _shortcutFocusNode,
autofocus: true,
child: Scaffold(
backgroundColor: Colors.transparent,
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: (MediaQuery.of(context).size.width > 800 ||
_searchFocusNode.hasFocus ||
@@ -736,7 +737,7 @@ class _UsersScreenState extends ConsumerState<UsersScreen> {
return Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.only(top: kToolbarHeight + 24),
padding: const EdgeInsets.fromLTRB(16, kToolbarHeight + 24, 16, 0),
child: Material(
color: isDark ? AppColors.darkSurfaceCard : Colors.white,
elevation: 4,
@@ -1,3 +1,4 @@
import 'dart:ui' show ImageFilter;
import 'package:flutter/material.dart';
/// An adaptive backdrop widget that displays the appropriate high-resolution
@@ -12,12 +13,14 @@ class AbstractBackground extends StatelessWidget {
final Widget child;
final bool withOverlay;
final double overlayOpacity;
final double blurSigma;
const AbstractBackground({
super.key,
required this.child,
this.withOverlay = false,
this.overlayOpacity = 0.0,
this.blurSigma = 2.5,
});
/// Helper to get the correct asset path based on brightness and orientation
@@ -40,8 +43,7 @@ class AbstractBackground extends StatelessWidget {
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final mediaQuery = MediaQuery.of(context);
final isLandscape = mediaQuery.orientation == Orientation.landscape ||
mediaQuery.size.width >= mediaQuery.size.height;
final isLandscape = mediaQuery.orientation == Orientation.landscape;
final assetPath = getBackdropAsset(
isDark: isDark,
@@ -51,13 +53,26 @@ class AbstractBackground extends StatelessWidget {
return Stack(
fit: StackFit.expand,
children: [
// Background image matching orientation and theme
// Background image with original normal positioning and overlay mini blur
Positioned.fill(
child: Image.asset(
assetPath,
fit: BoxFit.cover,
alignment: Alignment.center,
),
child: blurSigma > 0
? ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: blurSigma,
sigmaY: blurSigma,
tileMode: TileMode.clamp,
),
child: Image.asset(
assetPath,
fit: BoxFit.cover,
alignment: Alignment.center,
),
)
: Image.asset(
assetPath,
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
if (withOverlay && overlayOpacity > 0)
Positioned.fill(