You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
7.9 KiB
Dart
206 lines
7.9 KiB
Dart
import 'dart:ui';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
|
import 'package:hmg_patient_app_new/core/app_export.dart';
|
|
import 'package:hmg_patient_app_new/core/app_state.dart';
|
|
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
|
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
|
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
|
|
|
import '../../core/dependencies.dart';
|
|
|
|
class CollapsingToolbar extends StatefulWidget {
|
|
final String title;
|
|
Widget child;
|
|
VoidCallback? search;
|
|
VoidCallback? report;
|
|
VoidCallback? logout;
|
|
VoidCallback? history;
|
|
VoidCallback? instructions;
|
|
VoidCallback? requests;
|
|
Widget? bottomChild;
|
|
Widget? trailing;
|
|
bool isClose;
|
|
bool isLeading;
|
|
|
|
CollapsingToolbar({
|
|
super.key,
|
|
required this.title,
|
|
required this.child,
|
|
this.search,
|
|
this.isClose = false,
|
|
this.bottomChild,
|
|
this.report,
|
|
this.logout,
|
|
this.history,
|
|
this.instructions,
|
|
this.requests,
|
|
this.isLeading = true,
|
|
this.trailing,
|
|
});
|
|
|
|
@override
|
|
State<CollapsingToolbar> createState() => _CollapsingToolbarState();
|
|
}
|
|
|
|
class _CollapsingToolbarState extends State<CollapsingToolbar> {
|
|
bool isCollapsed = false;
|
|
|
|
final ScrollController _controller = ScrollController();
|
|
double expandedHeight = 0;
|
|
|
|
double get maxCollapseOffset => expandedHeight - kToolbarHeight;
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
|
|
_controller.addListener(() {
|
|
// If scrolling UP beyond collapsed point → force stop
|
|
print("the height is $maxCollapseOffset");
|
|
if (_controller.offset > maxCollapseOffset) {
|
|
_controller.jumpTo(maxCollapseOffset);
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
expandedHeight = MediaQuery.of(context).size.height * 0.11.h;
|
|
AppState appState = getIt.get<AppState>();
|
|
return Scaffold(
|
|
backgroundColor: AppColors.bgScaffoldColor,
|
|
body:
|
|
// Column(
|
|
// children: [
|
|
NestedScrollView(
|
|
controller: _controller,
|
|
floatHeaderSlivers: true,
|
|
physics: isCollapsed?NeverScrollableScrollPhysics():BouncingScrollPhysics(),
|
|
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
|
return [
|
|
SliverAppBar(
|
|
automaticallyImplyLeading: false,
|
|
pinned: true,
|
|
expandedHeight: MediaQuery.of(context).size.height * 0.11.h,
|
|
stretch: true,
|
|
systemOverlayStyle: SystemUiOverlayStyle(statusBarBrightness: Brightness.light),
|
|
surfaceTintColor: Colors.transparent,
|
|
backgroundColor: AppColors.bgScaffoldColor,
|
|
leading: widget.isLeading
|
|
? Transform.flip(
|
|
flipX: appState.isArabic(),
|
|
child: IconButton(
|
|
icon: Utils.buildSvgWithAssets(icon: widget.isClose ? AppAssets.closeBottomNav : AppAssets.arrow_back, width: 32.h, height: 32.h),
|
|
padding: EdgeInsets.only(left: 12),
|
|
onPressed: () => Navigator.pop(context),
|
|
highlightColor: Colors.transparent,
|
|
),
|
|
)
|
|
: SizedBox.shrink(),
|
|
flexibleSpace: LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
final double maxHeight = 100.h;
|
|
final double minHeight = kToolbarHeight;
|
|
double t = (constraints.maxHeight - minHeight) / (maxHeight - minHeight);
|
|
t = t - 1;
|
|
if (t < 0.7) t = 0.7;
|
|
t = t.clamp(0.0, 1.0);
|
|
|
|
final double fontSize = lerpDouble(14, 18, t)!;
|
|
final double bottomPadding = lerpDouble(0, 0, t)!;
|
|
final double leftPadding = lerpDouble(150, 24, t)!;
|
|
|
|
return Stack(
|
|
children: [
|
|
Align(
|
|
alignment: Alignment.lerp(
|
|
Alignment.center,
|
|
Alignment.bottomLeft,
|
|
t,
|
|
)!,
|
|
child: Padding(
|
|
padding: EdgeInsets.only(left: appState.isArabic() ? 0 : leftPadding, right: appState.isArabic() ? leftPadding : 0, bottom: bottomPadding),
|
|
child: Row(
|
|
spacing: 4.h,
|
|
children: [
|
|
Text(
|
|
widget.title,
|
|
maxLines: 1,
|
|
style: TextStyle(
|
|
fontSize: (27 - (5 * (2 - t))).f,
|
|
fontWeight: FontWeight.lerp(
|
|
FontWeight.w300,
|
|
FontWeight.w600,
|
|
t,
|
|
)!,
|
|
color: AppColors.blackColor,
|
|
letterSpacing: -0.5),
|
|
).expanded,
|
|
if (widget.logout != null) actionButton(context, t, title: "Logout".needTranslation, icon: AppAssets.logout).onPress(widget.logout!),
|
|
if (widget.report != null) actionButton(context, t, title: "Report".needTranslation, icon: AppAssets.report_icon).onPress(widget.report!),
|
|
if (widget.history != null) actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon).onPress(widget.history!),
|
|
if (widget.instructions != null) actionButton(context, t, title: "Instructions".needTranslation, icon: AppAssets.requests).onPress(widget.instructions!),
|
|
if (widget.requests != null) actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon).onPress(widget.requests!),
|
|
if (widget.search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(widget.search!).paddingOnly(right: 24),
|
|
if (widget.trailing != null) widget.trailing!,
|
|
],
|
|
)),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
),
|
|
];
|
|
},
|
|
body: widget.child,
|
|
),
|
|
|
|
// ],
|
|
// ),
|
|
);
|
|
}
|
|
|
|
Widget actionButton(BuildContext context, double t, {required String title, required String icon}) {
|
|
return AnimatedSize(
|
|
duration: Duration(milliseconds: 150),
|
|
child: Container(
|
|
height: 40.h,
|
|
padding: EdgeInsets.all(8.w),
|
|
margin: EdgeInsets.only(right: 24.w),
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
|
color: AppColors.secondaryLightRedColor,
|
|
borderRadius: 10.r,
|
|
),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
mainAxisSize: MainAxisSize.min,
|
|
spacing: 8.h,
|
|
children: [
|
|
Utils.buildSvgWithAssets(icon: icon, iconColor: AppColors.primaryRedColor),
|
|
if (t == 1)
|
|
Text(
|
|
title,
|
|
style: context.dynamicTextStyle(
|
|
color: AppColors.primaryRedColor,
|
|
letterSpacing: -0.4,
|
|
fontSize: (14 - (2 * (1 - t))).f,
|
|
fontWeight: FontWeight.lerp(
|
|
FontWeight.w300,
|
|
FontWeight.w500,
|
|
t,
|
|
)!,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|