Procházet zdrojové kódy

[new]优化首页tab

zk před 1 rokem
rodič
revize
0aec243f11

+ 1 - 0
assets/color/color.xml

@@ -8,4 +8,5 @@
     <color name="tertiaryTextColor">#AFAFAF</color>
 
     <color name="recordBackgroundColor">#25262A</color>
+    <color name="tabUnCheckColor">#969696</color>
 </resources>

binární
assets/images/main_tab_secretary.webp


+ 1 - 0
assets/string/base/string.xml

@@ -2,6 +2,7 @@
 <resources>
     <string name="app_name">小听</string>
     <string name="main_tab_home">首页</string>
+    <string name="main_tab_ai">AI秘书</string>
     <string name="main_tab_file">文件</string>
     <string name="home_go_login">立即登录</string>
     <string name="home_talk_record">谈话记录</string>

+ 4 - 2
lib/data/consts/constants.dart

@@ -1,4 +1,5 @@
 import 'package:electronic_assistant/utils/mmkv_util.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_umeng/flutter_umeng.dart';
 
 import '../../utils/common_utils.dart';
@@ -6,7 +7,7 @@ import '../../utils/common_utils.dart';
 class Constants {
   Constants._();
 
-  static const String env = envProd;
+  static const String env = envTest;
 
   static const String envDev = 'dev';
 
@@ -47,6 +48,7 @@ class Constants {
   static const String appChanelName = "app_channel_name";
   static const String appChannelId = "app_channel_id";
   static const String appTgPlatformId = "app_tg_platform_id";
+  static double bottomBarHeight = 56.h;
 }
 
 String getBaseUrl() {
@@ -95,4 +97,4 @@ class GuideConstants {
   static const String talkAddTemplateGuide = "talkAddTemplateGuide";
 
   static const String mainGuide = "mainGuide";
-}
+}

+ 1 - 1
lib/main.dart

@@ -1,4 +1,3 @@
-
 import 'package:atmob_channel_reader/atmob_channel_reader.dart';
 import 'package:electronic_assistant/data/consts/build_config.dart';
 import 'package:electronic_assistant/resource/colors.gen.dart';
@@ -126,6 +125,7 @@ class MyApp extends StatelessWidget {
         noDataText: StringName.loadNoData.tr,
         failedText: StringName.loadFailed.tr,
       ),
+      maxUnderScrollExtent: 100, // 底部最大可以拖动的范围
       child: GetMaterialApp(
         onGenerateTitle: (_) => StringName.appName.tr,
         getPages: AppPage.pages,

+ 15 - 0
lib/module/files/view.dart

@@ -1,5 +1,6 @@
 import 'package:electronic_assistant/base/base_page.dart';
 import 'package:electronic_assistant/data/bean/talks.dart';
+import 'package:electronic_assistant/data/consts/constants.dart';
 import 'package:electronic_assistant/module/files/controller.dart';
 import 'package:electronic_assistant/module/talk/view.dart';
 import 'package:electronic_assistant/resource/colors.gen.dart';
@@ -86,6 +87,20 @@ class FilesPage extends BasePage<FilesController> {
               controller: controller.refreshController,
               onRefresh: controller.onRefreshData,
               onLoading: controller.onLoadMoreTalkData,
+              footer: ClassicFooter(
+                height: Constants.bottomBarHeight + 80,
+                outerBuilder: (child) {
+                  return Padding(
+                    padding: EdgeInsets.only(bottom: Constants.bottomBarHeight),
+                    child: child,
+                  );
+                },
+                canLoadingText: StringName.loadingMore.tr,
+                idleText: StringName.loadPullUp.tr,
+                loadingText: StringName.loadingTxt.tr,
+                noDataText: StringName.loadNoData.tr,
+                failedText: StringName.loadFailed.tr,
+              ),
               child: CustomScrollView(
                 slivers: [
                   // SliverAnimatedGrid(

+ 4 - 2
lib/module/home/view.dart

@@ -1,5 +1,6 @@
 import 'package:electronic_assistant/base/base_page.dart';
 import 'package:electronic_assistant/data/bean/talks.dart';
+import 'package:electronic_assistant/data/consts/constants.dart';
 import 'package:electronic_assistant/data/repositories/account_repository.dart';
 import 'package:electronic_assistant/dialog/rename_dialog.dart';
 import 'package:electronic_assistant/dialog/talk_delete_dialog.dart';
@@ -29,6 +30,7 @@ class HomePage extends BasePage<HomePageController> {
       children: [
         buildBgBox(),
         SafeArea(
+          bottom: false,
           child: Column(
             children: [
               Container(
@@ -117,7 +119,8 @@ class HomePage extends BasePage<HomePageController> {
           visible: controller.agendaList.isNotEmpty,
           child: Container(
             alignment: Alignment.center,
-            padding: const EdgeInsets.only(top: 12, bottom: 36).w,
+            padding: EdgeInsets.only(
+                top: 12.w, bottom: 56.w + Constants.bottomBarHeight),
             child: RichText(
               text: TextSpan(
                 text: StringName.homeTalkTodo1.tr,
@@ -519,7 +522,6 @@ class HomePage extends BasePage<HomePageController> {
     );
   }
 
-
   void showRenameTalkDialog(TalkBean item) {
     reNameDialog(StringName.talkRenameTitle.tr, item.title.value,
         hintTxt: StringName.talkRenameTitleHint.tr,

+ 2 - 2
lib/module/main/controller.dart

@@ -29,13 +29,13 @@ class MainController extends BaseController {
         StringName.mainTabHome,
         Assets.images.mainTabHomeUnSelect.path,
         Assets.images.mainTabHomeSelected.path,
-        "#969696".toColor(),
+        ColorName.tabUnCheckColor,
         ColorName.primaryTextColor),
     TabBean(
         StringName.mainTabFile,
         Assets.images.mainTabFileUnSelect.path,
         Assets.images.mainTabFileSelected.path,
-        "#969696".toColor(),
+        ColorName.tabUnCheckColor,
         ColorName.primaryTextColor),
   ];
 

+ 136 - 31
lib/module/main/view.dart

@@ -7,11 +7,12 @@ 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/services.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});
@@ -32,7 +33,7 @@ class MainTabPage extends BasePage<MainController> {
         }
         if ((controller.lastPressedAt == null ||
             DateTime.now().difference(controller.lastPressedAt!) >
-                    const Duration(seconds: 2))) {
+                const Duration(seconds: 2))) {
           controller.setLastPressedAt(DateTime.now());
           ToastUtil.showToast(StringName.exitAppTip.tr);
         } else {
@@ -40,6 +41,8 @@ class MainTabPage extends BasePage<MainController> {
         }
       },
       child: Scaffold(
+        extendBody: true,
+        backgroundColor: Colors.transparent,
         key: controller.scaffoldKey,
         body: Obx(() {
           return pages[controller.currentIndex];
@@ -67,41 +70,58 @@ class MainTabPage extends BasePage<MainController> {
 
   Widget buildAIChatBtn() {
     return GestureDetector(
-      onTap: () {
-        controller.onChatClick();
-      },
-        child: Align(
-          alignment: Alignment.bottomCenter,
-          child: SizedBox(
-            width: 62.w,
-            child: AspectRatio(
-                aspectRatio: 195 / 223,
-                child: Assets.images.mainTabSecretary.image()),
-          ),
+        onTap: () {
+          controller.onChatClick();
+        },
+        child: SizedBox(
+          width: 52.w,
+          child: AspectRatio(
+              aspectRatio: 1 / 1,
+              child: Assets.images.mainTabSecretary.image()),
         ));
   }
 
-  BottomAppBar buildBottomAppBar() {
-    return BottomAppBar(
-      color: Colors.white,
-      height: 56.h,
-      padding: EdgeInsets.zero,
-      child: Flex(
-        mainAxisAlignment: MainAxisAlignment.spaceAround,
-        direction: Axis.horizontal,
-        children: <Widget>[
-          Expanded(
-            flex: 1,
-            child: bottomAppBarItem(0),
-          ),
-          SizedBox(width: 62.w),
-          const SizedBox(),
-          Expanded(
-            flex: 1,
-            child: bottomAppBarItem(1),
+  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),
+            ),
+          ],
+        ),
+      ),
     );
   }
 
@@ -144,3 +164,88 @@ class MainTabPage extends BasePage<MainController> {
     });
   }
 }
+
+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();
+  }
+}

+ 1 - 1
lib/module/splash/controller.dart

@@ -83,7 +83,7 @@ class SplashController extends BaseController {
         confirmOnTap: () async {
           EAAlertDialog.dismiss();
           setPrivacyPolicy(true);
-          await initAfterGrant();
+          // await initAfterGrant();
           await Future.delayed(const Duration(seconds: 1));
           Get.offNamed(RoutePath.mainTab);
         },