| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- import 'package:electronic_assistant/base/base_page.dart';
- import 'package:electronic_assistant/module/main/controller.dart';
- import 'package:electronic_assistant/module/main/drawer/view.dart';
- import 'package:electronic_assistant/resource/assets.gen.dart';
- import 'package:electronic_assistant/resource/colors.gen.dart';
- import 'package:electronic_assistant/resource/string.gen.dart';
- import 'package:electronic_assistant/utils/expand.dart';
- import 'package:electronic_assistant/utils/toast_util.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter_screenutil/flutter_screenutil.dart';
- import 'package:get/get.dart';
- import '../../data/consts/constants.dart';
- import '../files/view.dart';
- import '../home/view.dart';
- import 'dart:math' as math;
- class MainTabPage extends BasePage<MainController> {
- MainTabPage({super.key});
- final pages = [
- const HomePage(),
- const FilesPage(),
- ];
- @override
- Widget buildBody(BuildContext context) {
- return PopScope(
- canPop: false,
- onPopInvokedWithResult: (bool didPop, dynamic result) async {
- if (controller.scaffoldKey.currentState?.isDrawerOpen == true) {
- controller.closeDrawer();
- return;
- }
- if ((controller.lastPressedAt == null ||
- DateTime.now().difference(controller.lastPressedAt!) >
- const Duration(seconds: 2))) {
- controller.setLastPressedAt(DateTime.now());
- ToastUtil.showToast(StringName.exitAppTip.tr);
- } else {
- controller.exit();
- }
- },
- child: Scaffold(
- extendBody: true,
- backgroundColor: Colors.transparent,
- key: controller.scaffoldKey,
- body: Obx(() {
- return pages[controller.currentIndex];
- }),
- resizeToAvoidBottomInset: false,
- floatingActionButton: buildAIChatBtn(),
- floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
- bottomNavigationBar: buildBottomAppBar(),
- drawerEdgeDragWidth: 0,
- drawer: Drawer(
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.zero,
- ),
- backgroundColor: "#F6F5F8".toColor(),
- child: const MainDrawerView(),
- ),
- ),
- );
- }
- @override
- bool immersive() {
- return true;
- }
- Widget buildAIChatBtn() {
- return GestureDetector(
- onTap: () {
- controller.onChatClick();
- },
- child: SizedBox(
- key: controller.aiGuideKey,
- width: 52.w,
- child: AspectRatio(
- aspectRatio: 1 / 1,
- child: Assets.images.mainTabSecretary.image()),
- ));
- }
- Widget buildBottomAppBar() {
- return Container(
- decoration: BoxDecoration(
- boxShadow: [
- BoxShadow(
- color: ColorName.black5.withOpacity(0.05), // 阴影颜色
- blurRadius: 23, // 阴影模糊半径
- spreadRadius: 2, // 阴影扩展半径
- offset: const Offset(0, 0), // 阴影位置,向上偏移
- ),
- ],
- ),
- child: BottomAppBar(
- color: Colors.white,
- height: Constants.bottomBarHeight,
- padding: EdgeInsets.zero,
- shape: const CusCircularNotchedRectangle(),
- child: Flex(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- direction: Axis.horizontal,
- children: <Widget>[
- Expanded(
- flex: 1,
- child: bottomAppBarItem(0),
- ),
- SizedBox(
- width: 62.w,
- height: double.infinity,
- child: Align(
- alignment: const Alignment(0.0, 0.6),
- child: Text(StringName.mainTabAi.tr,
- style: TextStyle(
- fontSize: 10.sp, color: ColorName.tabUnCheckColor))),
- ),
- Expanded(
- flex: 1,
- child: bottomAppBarItem(1),
- ),
- ],
- ),
- ),
- );
- }
- Widget bottomAppBarItem(int index) {
- return Obx(() {
- TextStyle style;
- TabBean tabBean = controller.tabBeans[index];
- String imagePath;
- if (controller.currentIndex == index) {
- //选中的话
- style = TextStyle(fontSize: 10.sp, color: tabBean.txtSelectedColor);
- imagePath = tabBean.selectedIcon;
- } else {
- style = TextStyle(fontSize: 10.sp, color: tabBean.txtNormalColor);
- imagePath = tabBean.normalIcon;
- }
- return GestureDetector(
- behavior: HitTestBehavior.opaque,
- child: SizedBox(
- height: 56.h,
- child: Center(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Image.asset(imagePath, width: 24.w, height: 24.w),
- Text(
- tabBean.title.tr,
- style: style,
- )
- ],
- ),
- ),
- ),
- onTap: () {
- if (controller.currentIndex != index) {
- controller.updateIndex(index);
- }
- },
- );
- });
- }
- }
- class CusCircularNotchedRectangle extends NotchedShape {
- /// Creates a [CusCircularNotchedRectangle].
- ///
- /// The same object can be used to create multiple shapes.
- const CusCircularNotchedRectangle();
- /// Creates a [Path] that describes a rectangle with a smooth circular notch.
- ///
- /// `host` is the bounding box for the returned shape. Conceptually this is
- /// the rectangle to which the notch will be applied.
- ///
- /// `guest` is the bounding box of a circle that the notch accommodates. All
- /// points in the circle bounded by `guest` will be outside of the returned
- /// path.
- ///
- /// The notch is curve that smoothly connects the host's top edge and
- /// the guest circle.
- // TODO(amirh): add an example diagram here.
- @override
- Path getOuterPath(Rect host, Rect? guest) {
- if (guest == null || !host.overlaps(guest)) {
- return Path()..addRect(host);
- }
- // The guest's shape is a circle bounded by the guest rectangle.
- // So the guest's radius is half the guest width.
- final double notchRadius = guest.width / 2.0;
- // We build a path for the notch from 3 segments:
- // Segment A - a Bezier curve from the host's top edge to segment B.
- // Segment B - an arc with radius notchRadius.
- // Segment C - a Bezier curve from segment B back to the host's top edge.
- //
- // A detailed explanation and the derivation of the formulas below is
- // available at: https://goo.gl/Ufzrqn
- const double s1 = 20.0;
- const double s2 = 6;
- final double r = notchRadius;
- final double a = -1.0 * r - s2;
- final double b = host.top - guest.center.dy;
- final double n2 = math.sqrt(b * b * r * r * (a * a + b * b - r * r));
- final double p2xA = ((a * r * r) - n2) / (a * a + b * b);
- final double p2xB = ((a * r * r) + n2) / (a * a + b * b);
- final double p2yA = math.sqrt(r * r - p2xA * p2xA);
- final double p2yB = math.sqrt(r * r - p2xB * p2xB);
- final List<Offset?> p = List<Offset?>.filled(6, null);
- // p0, p1, and p2 are the control points for segment A.
- p[0] = Offset(a - s1, b);
- p[1] = Offset(a, b);
- final double cmp = b < 0 ? -1.0 : 1.0;
- p[2] = cmp * p2yA > cmp * p2yB ? Offset(p2xA, p2yA) : Offset(p2xB, p2yB);
- // p3, p4, and p5 are the control points for segment B, which is a mirror
- // of segment A around the y axis.
- p[3] = Offset(-1.0 * p[2]!.dx, p[2]!.dy);
- p[4] = Offset(-1.0 * p[1]!.dx, p[1]!.dy);
- p[5] = Offset(-1.0 * p[0]!.dx, p[0]!.dy);
- // translate all points back to the absolute coordinate system.
- for (int i = 0; i < p.length; i += 1) {
- p[i] = p[i]! + guest.center;
- }
- return Path()
- ..moveTo(host.left, host.top)
- ..lineTo(p[0]!.dx, p[0]!.dy)
- ..quadraticBezierTo(p[1]!.dx, p[1]!.dy, p[2]!.dx, p[2]!.dy)
- ..arcToPoint(
- p[3]!,
- radius: Radius.circular(notchRadius),
- clockwise: false,
- )
- ..quadraticBezierTo(p[4]!.dx, p[4]!.dy, p[5]!.dx, p[5]!.dy)
- ..lineTo(host.right, host.top)
- ..lineTo(host.right, host.bottom)
- ..lineTo(host.left, host.bottom)
- ..close();
- }
- }
|