فهرست منبع

2025年9月10日basic更新:
1、新增ContextHelper类,可以在除EntryAbility以外的任意地方获取context,UIContext,abilityContext。
2、修复了我的页面的部分bug 如输入密码后无法验证码登录 上传大图片会导致闪退等。
3、新增可拖动的悬浮窗FloatingComp组件
4、新增注册字体工具类 可调用registerFont方法快速注册字体
5、更新了YTPhotoHelper类 新增传入组件id即可截图保存至相册,压缩图片的方法
6、更新了YTButton,使其可以传入渐变色 新增节流功能,使用YTButton则不需要考虑节流问题,但需要快速点击的场景不建议使用。
7、更新了YTRequest方法,将入参默认设置为any类型。
8、更新了YTToast方法,使其可以通过key值获取多例,解决了某些需要多个弹窗的场景。

wangcy 1 ماه پیش
والد
کامیت
f89c256168
24فایلهای تغییر یافته به همراه830 افزوده شده و 139 حذف شده
  1. 14 6
      commons/basic/Index.ets
  2. 5 6
      commons/basic/src/main/ets/apis/YTRequest.ets
  3. 3 3
      commons/basic/src/main/ets/apis/YTUserRequest.ets
  4. 50 0
      commons/basic/src/main/ets/components/ToastBuilders/AgreePrivacy.ets
  5. 44 0
      commons/basic/src/main/ets/components/ToastBuilders/LoginToUse.ets
  6. 54 0
      commons/basic/src/main/ets/components/ToastBuilders/YtDoubleConfirm.ets
  7. 43 9
      commons/basic/src/main/ets/components/generalComp/YTButton.ets
  8. 243 0
      commons/basic/src/main/ets/components/generalComp/YTSwiper.ets
  9. 44 0
      commons/basic/src/main/ets/models/index.ets
  10. 112 0
      commons/basic/src/main/ets/utils/ContextHelper.ets
  11. 29 0
      commons/basic/src/main/ets/utils/RegisterFontUtil.ets
  12. 78 15
      commons/basic/src/main/ets/utils/YTPhotoHelper.ets
  13. 37 24
      commons/basic/src/main/ets/utils/YTToast.ets
  14. BIN
      commons/basic/src/main/resources/rawfile/MiSansVF.ttf
  15. BIN
      commons/basic/src/main/resources/rawfile/SourceHanSansCN.otf
  16. BIN
      commons/basic/src/main/resources/rawfile/SourceHanSansSC.otf
  17. 40 0
      features/feature/src/main/ets/components/FloatingComp.ets
  18. 2 1
      features/feature/src/main/ets/view/SecondView.ets
  19. 1 1
      features/feature/src/main/ets/view/ThirdView.ets
  20. 22 9
      features/user/src/main/ets/pages/DelPhotoPage.ets
  21. 1 1
      features/user/src/main/ets/pages/SettingPage.ets
  22. 1 0
      features/user/src/main/ets/views/LoginView.ets
  23. 4 49
      products/entry/src/main/ets/entryability/EntryAbility.ets
  24. 3 15
      products/entry/src/main/ets/pages/Index.ets

+ 14 - 6
commons/basic/Index.ets

@@ -1,6 +1,17 @@
+export { registerFontUtil } from './src/main/ets/utils/RegisterFontUtil'
+
+export { YTToast } from './src/main/ets/utils/YTToast'
+
+export { ContextHelper } from './src/main/ets/utils/ContextHelper'
+
+export { YTSwiper } from './src/main/ets/components/generalComp/YTSwiper'
+
 export { BackgroundPageModifier } from './src/main/ets/styles/AttributeModifier'
+
 export { TextSelect } from './src/main/ets/components/generalComp/TextSelect'
+
 export { DropDownImageInfo, DropDownInfo, TextInfo, TextInputInfo } from './src/main/ets/models/TextSelectModel'
+
 export { pushMessageUtil } from './src/main/ets/utils/NoticeUtil'
 
 export { yTPreferences } from './src/main/ets/utils/YTPreferencesUtil'
@@ -9,21 +20,18 @@ export { yTToast } from './src/main/ets/utils/YTToast'
 
 export { PanGrid } from './src/main/ets/components/generalComp/PanGrid'
 
-
 export { YTPhotoHelper } from './src/main/ets/utils/YTPhotoHelper'
 
-
 export { YTUserRequest } from './src/main/ets/apis/YTUserRequest'
 
-
 export { ScanCodeUtil } from './src/main/ets/utils/ScanCodeUtil'
+
 export { YTBindSheet } from './src/main/ets/utils/YTBindSheet'
 
 export { YTDate } from './src/main/ets/utils/YTDate'
 
 export * from './src/main/ets/constants'
 
-
 export * from '@ibestservices/ibest-ui'
 
 export { reviseImgHeaderBuilder } from './src/main/ets/components/generalComp/ReviseImgHeaderBuilder'
@@ -67,10 +75,10 @@ export * from "./src/main/ets/utils/YTBreakPoint"
 
 export { BasicType } from './src/main/ets/models/index'
 
-export {YTAddressSelectorDialog,DateOption} from './src/main/ets//datepicker/YTDataPickerSelector'
+export { YTAddressSelectorDialog, DateOption } from './src/main/ets//datepicker/YTDataPickerSelector'
 
 
-export {YTDateUtil,DateFormat} from './src/main/ets/utils/YTDateUtil'
+export { YTDateUtil, DateFormat } from './src/main/ets/utils/YTDateUtil'
 
 export * from '@mumu/crop'
 

+ 5 - 6
commons/basic/src/main/ets/apis/YTRequest.ets

@@ -7,16 +7,15 @@ import axios, {
   FormData,
   InternalAxiosRequestConfig
 } from '@ohos/axios';
-import { IBestToast, ReqString, YTLog } from '../../../../Index';
+import { ContextHelper, IBestToast, ReqString, YTLog } from '../../../../Index';
 import { AppStorageKeyCollect } from '../constants';
 import { userInfo } from '../models/UserInfo';
 import { yTRouter } from '../utils/YTRouter';
 
 
-export const baseURL: string = 'https://hm.ytpm.net/prod-warhouse'
+export const baseURL: string = 'https://hm.ytpm.net/prod-activity'
 
-//
-// export const baseURL: string = 'http://192.168.1.160:48098'
+// export const baseURL: string = 'http://192.168.1.160:48103'
 
 export const instance = axios.create({
   baseURL,
@@ -98,12 +97,12 @@ export class YTRequest {
   }
 
   //上传文件
-  static uploadFile(context: Context, fullpath: string, success?: (url: string) => void) {
+  static uploadFile(fullpath: string, success?: (url: string) => void) {
     const formData = new FormData()
     formData.append('file', fullpath)
     const promise = YTRequest.upPost<ReqString, FormData>('/common/upload', formData, {
       headers: { 'Content-Type': 'multipart/form-data' },
-      context,
+      context: ContextHelper.context,
       onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
         YTLog.info(progressEvent && progressEvent.loaded && progressEvent.total ?
           Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%', 'uploadFile');

+ 3 - 3
commons/basic/src/main/ets/apis/YTUserRequest.ets

@@ -5,7 +5,7 @@ import { LoginCollect } from '../models/LoginCollect'
 import { UserInfo, userInfo } from '../models/UserInfo'
 import { yTRouter } from '../utils/YTRouter'
 import { YTRequest } from './YTRequest'
-import { YTLog } from '../../../../Index'
+import { ContextHelper, YTLog } from '../../../../Index'
 import { AxiosProgressEvent, FormData } from '@ohos/axios'
 import { YTDate } from '../utils/YTDate'
 import { HuaweiAuthPlugin } from '../utils/HuaWeiAuthPlugin'
@@ -135,13 +135,13 @@ export class YTUserRequest extends YTRequest {
 
 
   // 修改用户头像
-  static uploadHeadImg(context: Context, fullpath: string, success: () => void) {
+  static uploadHeadImg(fullpath: string, success: () => void) {
     const formData = new FormData()
     formData.append('file', fullpath)
 
     YTUserRequest.upPost<ReqString, FormData>('/common/upload', formData, {
       headers: { 'Content-Type': 'multipart/form-data' },
-      context,
+      context: ContextHelper.context,
       onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
         YTLog.info(progressEvent && progressEvent.loaded && progressEvent.total ?
           Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%', 'uploadFile');

+ 50 - 0
commons/basic/src/main/ets/components/ToastBuilders/AgreePrivacy.ets

@@ -0,0 +1,50 @@
+import { BasicType } from '../../models';
+import { yTToast } from '../../utils/YTToast';
+import { YTButton } from '../generalComp/YTButton';
+
+@Builder
+export function agreePrivacy(item: BasicType<undefined>) {
+  Column() {
+    Text('温馨提示')
+      .fontSize(14)
+      .fontColor('Color.Black')
+      .margin({ top: 14, bottom: 8 })
+    Text('已阅读并同意《用户协议》和《隐私政策》')
+      .fontSize(13)
+      .fontColor($r('sys.color.mask_secondary'))
+      .margin({ bottom: 19 })
+
+
+    Column() {
+      YTButton({
+        btContent: '同意并登入',
+        btHeight: 37,
+        click: () => {
+          yTToast.hide()
+          
+          item.loginType!.isAgreePrivacy = true
+
+          item.loginType?.executeLogin()
+
+
+        }
+      })
+      YTButton({
+        btContent: '不同意',
+        btHeight: 37,
+        bgc: Color.White,
+        btFontColor: '#80000000',
+        click: () => {
+          yTToast.hide()
+        }
+      })
+    }
+    .padding({ left: 16, right: 16 })
+
+  }
+  .width(280)
+  .height(160)
+  .backgroundColor(Color.White)
+  .borderRadius(8)
+  .margin({ bottom: 28 })
+}

+ 44 - 0
commons/basic/src/main/ets/components/ToastBuilders/LoginToUse.ets

@@ -0,0 +1,44 @@
+import { BasicType } from '../../models';
+import { yTRouter } from '../../utils/YTRouter';
+import { YTButton } from '../generalComp/YTButton';
+
+@Builder
+export function loginToUse(_: BasicType) {
+  Column() {
+    Row() {
+      Text('登录使用所有功能')
+        .fontSize(16)
+        .fontWeight(400)
+        .fontColor('#B31C1C1C')
+
+      YTButton({
+        btHeight: 30,
+        btWidth: 80,
+        btContent: '马上登录',
+        btBorderRadius: 32,
+        btFontSize: 12,
+        click: () => {
+          yTRouter.router2LoginPage()
+        }
+      })
+    }
+    .justifyContent(FlexAlign.SpaceBetween)
+    .padding({
+      top: 13,
+      left: 20,
+      bottom: 13,
+      right: 20
+    })
+    .borderRadius(8)
+    .backgroundColor(Color.White)
+    .width('100%')
+    .height(56)
+    .shadow({
+      color: '#14000000',
+      radius: 32,
+      offsetX: 0,
+      offsetY: 4
+    })
+  }
+  .padding({ left: 20, right: 20 })
+}

+ 54 - 0
commons/basic/src/main/ets/components/ToastBuilders/YtDoubleConfirm.ets

@@ -0,0 +1,54 @@
+import { YTButton, yTToast, } from '../../../../../Index';
+import { BasicType } from '../../models';
+
+@Builder
+export function yTDoubleConfirm(item: BasicType<undefined>) {
+  Column() {
+    Text(item.text)
+      .fontSize(14)
+      .fontColor(Color.Black)
+      .margin({ bottom: 18 })
+    Text(item.message)
+      .fontColor($r('sys.color.mask_secondary'))
+      .lineHeight(18)
+      .fontSize(13)
+      .margin({ bottom: 18 })
+    Row() {
+      YTButton(
+        {
+          btContent: '确定',
+          btWidth: 108,
+          btHeight: 37,
+          btFontSize: 12,
+          click: item.click,
+          btLinearGradient: { angle: 92, colors: [['#FF4597F7', 0.023], ['#FF6B6DF7', 1.081]] },
+        }
+      )
+      YTButton(
+        {
+          btContent: '取消',
+          btWidth: 108,
+          btHeight: 37,
+          btFontColor: '#80000000',
+          btBorder: { width: 1, color: '#33000000' },
+          btFontSize: 12,
+          bgc: Color.White,
+          click: () => {
+            yTToast.hide()
+          }
+        }
+      )
+    }
+    .justifyContent(FlexAlign.SpaceBetween)
+    .width('100%')
+  }
+  .width(280)
+  .padding({
+    top: 14,
+    left: 24,
+    right: 24,
+    bottom: 24
+  })
+  .backgroundColor(Color.White)
+  .borderRadius(8)
+}

+ 43 - 9
commons/basic/src/main/ets/components/generalComp/YTButton.ets

@@ -3,30 +3,64 @@ export struct YTButton {
   btHeight: number = 37
   btWidth: Length = '100%'
   btContent: string = ''
-  btPadding?: Length | Padding
+  btPadding: Length | Padding = 0
   btFontSize: number = 12
-  bgc: ResourceColor = $r('app.color.main_ac_color_dark')
+  bgc?: ResourceColor
   btFontColor: ResourceColor = Color.White
   btBorder?: BorderOptions
   btState: boolean = true
-  btBorderRadius: Length | BorderRadiuses | LocalizedBorderRadiuses = this.btHeight / 2
-
+  btBorderRadius: Length | BorderRadiuses | LocalizedBorderRadiuses = 999
+  btLinearGradient?: LinearGradientOptions
+  btFontFamily?: ResourceStr
+  btFontWeight?: string | number | FontWeight
+  btShadow?: ShadowOptions | ShadowStyle
+  @State private isClick: boolean = true
   click = () => {
 
   }
 
+  @Styles
+  pressStyles() {
+    .opacity(0.9)
+  }
+
+  @Styles
+  normalStyles() {
+    .opacity(1)
+  }
+
+  aboutToAppear(): void {
+    if (!this.bgc) {
+      this.btLinearGradient = { angle: 92, colors: [['#FF4597F7', 0.023], ['#FF6B6DF7', 1.081]] }
+    }
+  }
+
   build() {
-    Button(this.btContent)
-      .buttonStyle(ButtonStyleMode.NORMAL)
-      .fontSize($r(`app.float.page_text_font_size_${this.btFontSize}`))
+    Text(this.btContent)
+      .fontSize(this.btFontSize)
       .fontColor(this.btFontColor)
       .backgroundColor(this.bgc)
       .height(this.btHeight)
       .width(this.btWidth)
-      .onClick(this.click)
+      .textAlign(TextAlign.Center)
+      .onClick(() => {
+        this.isClick = false
+        this.click()
+        setTimeout(() => {
+          this.isClick = true
+        }, 1000)
+      })
       .padding(this.btPadding ?? {})
       .border(this.btBorder)
-      .enabled(this.btState)
+      .shadow(this.btShadow)
+      .enabled(this.btState ?? this.isClick)
       .borderRadius(this.btBorderRadius)
+      .linearGradient(this.btLinearGradient)
+      .fontFamily(this.btFontFamily)
+      .fontWeight(this.btFontWeight)
+      .stateStyles({
+        pressed: this.pressStyles,
+        normal: this.normalStyles
+      })
   }
 }

+ 243 - 0
commons/basic/src/main/ets/components/generalComp/YTSwiper.ets

@@ -0,0 +1,243 @@
+
+@Component
+export struct YTSwiper {
+  //----整体swiper的宽高
+  @Prop swiperWidth: Length = '100%'
+  @Prop swiperHeight: Length = 200
+  @Prop swiperBackgroundColor: ResourceColor = Color.Yellow
+  @Prop swiperBorderRadius: Length | BorderRadiuses | LocalizedBorderRadiuses = 0
+  //---渲染的img数组
+  @Prop @Watch('imageListChange') imageList: ResourceStr[] = []
+  //---这个暂时还没扩展  只支持传7个
+  @Prop displayNumber: number = 7
+  //图片宽高圆角
+  @Prop imgWidth: Length = 109
+  @Prop imgHeight: Length = 153
+  @Prop imgBorderRadius: Length = 5
+  //获取当前选择的图片
+  @Require getCurrentImg: (_: ResourceStr) => void
+  //
+  @State private currentIndex: number = 0
+
+  aboutToAppear() {
+    this.getCurrentImg(this.imageList[this.currentIndex])
+  }
+
+  imageListChange() {
+    this.getCurrentImg(this.imageList[this.currentIndex])
+  }
+
+  build() {
+    RelativeContainer() {
+      // 创建一个扩展的列表,包含原始列表和前几项的副本,以支持视觉上的循环效果
+      ForEach(this.getExtendedList(), (item: ResourceStr, index: number) => {
+        Column() {
+          Image(item)
+            .width(109)
+            .height(153)
+            .borderRadius(12)
+        }
+        .scale({ x: this.calcScale(index), y: this.calcScale(index) })
+        .onClick(() => {
+          this.getUIContext().animateTo({ duration: 300 }, () => {
+            // 更新 currentIndex,确保其在原始列表范围内循环
+            this.currentIndex = index % this.imageList.length
+          })
+          this.getCurrentImg(this.imageList[this.currentIndex])
+        })
+        .alignRules(this.calcAlignRules(index))
+        .id(index.toString())
+        .zIndex(this.calcZIndex(index))
+
+      }, (_: ResourceStr, index: number) => index.toString() + _.toString()) // 提供唯一的键
+    }
+    .width(this.swiperWidth)
+    .height(this.swiperHeight)
+    .borderRadius(this.swiperBorderRadius)
+    .backgroundColor(this.swiperBackgroundColor)
+    .gesture(GestureGroup(GestureMode.Exclusive,
+      PanGesture(new PanGestureOptions({ direction: PanDirection.Horizontal, distance: 100 }))
+        .onActionEnd((event: GestureEvent) => {
+          this.getUIContext().animateTo({ duration: 300 }, () => {
+            if (event.offsetX > 100) {
+              // 向右滑动,显示前一张图片
+              this.currentIndex = this.modulo(this.currentIndex - 1, this.imageList.length);
+            } else if (event.offsetX < -100) {
+              // 向左滑动,显示后一张图片
+              this.currentIndex = this.modulo(this.currentIndex + 1, this.imageList.length);
+            }
+          })
+          this.getCurrentImg(this.imageList[this.currentIndex])
+        })
+    ))
+  }
+
+  /**
+   * 正确处理负数的取模运算
+   * @param dividend 被除数
+   * @param divisor 除数
+   * @returns 正确的模运算结果
+   */
+  private modulo(dividend: number, divisor: number): number {
+    return ((dividend % divisor) + divisor) % divisor;
+  }
+
+  /**
+   * 创建一个扩展的列表,用于视觉上的循环展示
+   * 在原始列表后追加前几项,这样在视觉上可以实现无缝循环
+   */
+  private getExtendedList(): ResourceStr[] {
+    // 确保显示数量为奇数,且至少为3
+    const displayCount = Math.max(3, this.displayNumber % 2 === 0 ? this.displayNumber + 1 : this.displayNumber);
+
+    // 计算需要扩展的数量(一半)
+    const extendCount = Math.floor(displayCount / 2);
+
+    // 实际应用中可能需要更复杂的逻辑来处理前后缓冲
+    return [...this.imageList, ...this.imageList.slice(0, extendCount)];
+  }
+
+  /**
+   * 计算每个项目相对于当前中心项目的对齐规则
+   * @param index 当前项目的索引(在扩展列表中的位置)
+   * @returns 对齐规则对象
+   */
+  private calcAlignRules(index: number): AlignRuleOption {
+    // 将索引映射回原始列表范围,以便计算相对位置
+    const actualIndex = index % this.imageList.length
+    const currentActualIndex = this.currentIndex % this.imageList.length
+
+    // 计算相对位置
+    let relativePosition = actualIndex - currentActualIndex;
+
+    // 处理循环情况
+    if (relativePosition > this.imageList.length / 2) {
+      relativePosition -= this.imageList.length;
+    } else if (relativePosition < -this.imageList.length / 2) {
+      relativePosition += this.imageList.length;
+    }
+
+    // 根据相对位置设置对齐规则
+    if (relativePosition === 0) {
+      // 中心图片
+      return {
+        center: { anchor: "__container__", align: VerticalAlign.Center },
+        middle: { anchor: "__container__", align: HorizontalAlign.Center },
+      }
+    } else if (relativePosition === -1) {
+      // 左侧第一张
+      return {
+        center: { anchor: "__container__", align: VerticalAlign.Center },
+        middle: { anchor: this.currentIndex.toString(), align: HorizontalAlign.Start },
+      }
+    } else if (relativePosition === 1) {
+      // 右侧第一张
+      return {
+        center: { anchor: "__container__", align: VerticalAlign.Center },
+        middle: { anchor: this.currentIndex.toString(), align: HorizontalAlign.End },
+      }
+    } else if (relativePosition === -2) {
+      // 左侧第二张
+      return {
+        center: { anchor: "__container__", align: VerticalAlign.Center },
+        middle: {
+          anchor: this.modulo(this.currentIndex - 1, this.imageList.length).toString(),
+          align: HorizontalAlign.Start
+        },
+      }
+    } else if (relativePosition === 2) {
+      // 右侧第二张
+      return {
+        center: { anchor: "__container__", align: VerticalAlign.Center },
+        middle: {
+          anchor: this.modulo(this.currentIndex + 1, this.imageList.length).toString(),
+          align: HorizontalAlign.End
+        },
+      }
+    } else if (relativePosition === -3) {
+      return {
+        center: { anchor: "__container__", align: VerticalAlign.Center },
+        middle: {
+          anchor: this.modulo(this.currentIndex - 2, this.imageList.length).toString(),
+          align: HorizontalAlign.Start
+        },
+      }
+    } else if (relativePosition === 3) {
+      return {
+        center: { anchor: "__container__", align: VerticalAlign.Center },
+        middle: {
+          anchor: this.modulo(this.currentIndex + 2, this.imageList.length).toString(),
+          align: HorizontalAlign.End
+        },
+      }
+    } else {
+      // 其他位置的图片,根据实际需求可以进一步扩展
+      return {
+        center: { anchor: "__container__", align: VerticalAlign.Center },
+        middle: { anchor: "__container__", align: HorizontalAlign.Center },
+      }
+    }
+  }
+
+  /**
+   * 计算每个项目的 Z 轴层级
+   * @param index 当前项目的索引(在扩展列表中的位置)
+   * @returns Z 轴层级值
+   */
+  private calcZIndex(index: number): number {
+    const actualIndex = index % this.imageList.length
+    const currentActualIndex = this.currentIndex % this.imageList.length
+
+    // 计算相对位置
+    let relativePosition = Math.abs(actualIndex - currentActualIndex);
+
+    // 处理循环情况
+    if (relativePosition > this.imageList.length / 2) {
+      relativePosition = this.imageList.length - relativePosition;
+    }
+
+    // 根据相对位置设置 zIndex
+    if (relativePosition === 0) {
+      return 999; // 中心图片
+    } else if (relativePosition === 1) {
+      return 500; // 第一层图片
+    } else if (relativePosition === 2) {
+      return 200; // 第二层图片
+    } else {
+      return 1; // 其他图片
+    }
+  }
+
+  /**
+   * 根据索引差值计算缩放比例
+   * @param index 当前项目的索引(在扩展列表中的位置)
+   * @returns 缩放比例值
+   */
+  private calcScale(index: number): number {
+    const actualIndex = index % this.imageList.length
+    const currentActualIndex = this.currentIndex % this.imageList.length
+
+    // 计算索引差值,考虑循环情况
+    let diff = actualIndex - currentActualIndex
+
+    // 处理循环边界情况
+    if (diff > this.imageList.length / 2) {
+      diff -= this.imageList.length
+    } else if (diff < -this.imageList.length / 2) {
+      diff += this.imageList.length
+    }
+
+    // 根据差值设置缩放比例
+    const absDiff = Math.abs(diff);
+
+    if (absDiff === 0) {
+      return 1.0; // 中心图片
+    } else if (absDiff === 1) {
+      return 0.83; // 第一层图片
+    } else if (absDiff === 2) {
+      return 0.64; // 第二层图片
+    } else {
+      return 0.49; // 更远的图片使用最小缩放
+    }
+  }
+}

+ 44 - 0
commons/basic/src/main/ets/models/index.ets

@@ -1,4 +1,5 @@
 import { LoginCollect } from './LoginCollect'
+import { display } from '@kit.ArkUI'
 
 export interface BasicType<T = undefined> {
   src?: ResourceStr,
@@ -53,6 +54,49 @@ export type ResultCallBack<T> = (res?: T, err?: Error) => void
  */
 export type BreakPointString = 'xs' | 'sm' | 'md' | 'lg'
 
+@ObservedV2
+export class Card {
+  param: Resource;
+  id: number
+  @Trace isSubmit: boolean = false
+  @Trace offsetX: number = 0
+  @Trace offsetY: number = 0
+  @Trace zIndex: number = 0
+  @Trace size: number = 0
+  @Trace opacity: number = 0
+
+  constructor(img: Resource, id: number, uiContext: UIContext) {
+    this.param = img
+    this.id = id
+    let displayClass: display.Display = display.getDefaultDisplaySync();
+    let windowWidth = uiContext.px2vp(displayClass.width)
+    let midCardOffsetX = 25
+    let rightCardOffsetX = windowWidth - 32 - (windowWidth * 0.7833 * 0.83)
+
+    if (id === 0) {
+      this.offsetX = 0
+      this.size = 0.83
+      this.zIndex = 1
+      this.opacity = 1
+    } else if (id === 1) {
+      this.offsetX = midCardOffsetX
+      this.size = 1
+      this.zIndex = 2
+      this.opacity = 1
+    } else if (id === 2) {
+      this.offsetX = rightCardOffsetX
+      this.size = 0.83
+      this.zIndex = 1
+      this.opacity = 1
+    } else {
+      this.offsetX = midCardOffsetX
+      this.size = 0.83
+      this.zIndex = 1
+      this.opacity = 0
+    }
+  }
+}
+
 // 日期信息接口定义
 export interface DateInfo {
   year: number;   // 年份

+ 112 - 0
commons/basic/src/main/ets/utils/ContextHelper.ets

@@ -0,0 +1,112 @@
+import { Context } from '@ohos.abilityAccessCtrl'
+import { common } from '@kit.AbilityKit'
+import { permissionController } from './PermissionControl'
+import { jHStartAd, pushMessageUtil, registerFontUtil, YTLog, yTPreferences, YTToast } from '../../../../Index'
+import { identifier } from '@kit.AdsKit'
+import { BusinessError } from '@kit.BasicServicesKit'
+
+export class ContextHelper {
+  private static declare _UIContext: UIContext
+
+  static get UIContext() {
+    if (!ContextHelper._UIContext) {
+      throw new Error('UIContext is not set')
+    }
+    return ContextHelper._UIContext
+  }
+
+  static set UIContext(value: UIContext) {
+    ContextHelper._UIContext = value
+    const context = value.getHostContext()
+    if (context && !ContextHelper._context) {
+      ContextHelper.context = context
+      ContextHelper.UIAbilityContext = context as common.UIAbilityContext
+    }
+  }
+
+  private static declare _UIAbilityContext: common.UIAbilityContext
+
+  static get UIAbilityContext() {
+    if (!ContextHelper._UIAbilityContext) {
+      throw new Error('UIAbilityContext is not set')
+    }
+    return ContextHelper._UIAbilityContext
+  }
+
+  static set UIAbilityContext(value: common.UIAbilityContext) {
+    ContextHelper._UIAbilityContext = value
+    if (!ContextHelper._context) {
+      ContextHelper.context = value
+    }
+
+  }
+
+  private static declare _context: Context
+
+  static get context() {
+    if (!ContextHelper._context) {
+      throw new Error('context is not set')
+    }
+    return ContextHelper._context
+  }
+
+  static set context(value: Context) {
+    ContextHelper._context = value
+  }
+
+  //依赖上下文的工具类初始化 需要在第一个页面中设置UIContext后调用
+  static init(context: UIContext) {
+    ContextHelper.UIContext = context
+    permissionController.init(ContextHelper.context)
+      .then(() => {
+        permissionController
+          .askPermissions(["ohos.permission.APP_TRACKING_CONSENT"], (res, err) => {
+            if (err) {
+              YTLog.error(err)
+            } else {
+              if (res?.authResults[0] === 0) {
+                YTLog.info('succeeded in requesting permission');
+                identifier.getOAID((err: BusinessError, data: string) => {
+                  if (err.code) {
+                    YTLog.error(`get oaid failed, error: ${err.code} ${err.message}`);
+                  } else {
+                    const oaid: string = data;
+                    jHStartAd.init(ContextHelper.UIAbilityContext, oaid)
+                    AppStorage.setOrCreate('OAID', oaid)
+                    YTLog.info(`succeeded in getting oaid by callback , oaid: ${oaid}`);
+                  }
+                });
+              } else {
+                YTLog.error('user rejected');
+              }
+            }
+          })
+      })
+    yTPreferences.init(ContextHelper.context)
+    pushMessageUtil.init(ContextHelper.UIAbilityContext)
+    registerFontUtil.registerFont([
+      {
+        familyName: 'MiSans VF',
+        familySrc: $rawfile('MiSansVF.ttf')
+      },
+      {
+        familyName: 'Source Han Sans SC',
+        familySrc: $rawfile('SourceHanSansSC.otf')
+      },
+      {
+        familyName: 'Source Han Sans CN',
+        familySrc: $rawfile('SourceHanSansSC.otf')
+      }
+    ])
+    new YTToast({
+      key: 'loginRemind',
+      options: {
+        autoCancel: false,
+        alignment: DialogAlignment.Bottom,
+        maskColor: Color.Transparent,
+        isModal: false,
+        offset: { dy: -84, dx: 0 }
+      }
+    })
+  }
+}

+ 29 - 0
commons/basic/src/main/ets/utils/RegisterFontUtil.ets

@@ -0,0 +1,29 @@
+import { font } from '@kit.ArkUI';
+import { ContextHelper } from './ContextHelper';
+
+class RegisterFontUtil {
+  //单例
+  private static instance: RegisterFontUtil;
+
+  private constructor() {
+  }
+
+  public static getInstance(): RegisterFontUtil {
+    if (!RegisterFontUtil.instance) {
+      RegisterFontUtil.instance = new RegisterFontUtil();
+    }
+    return RegisterFontUtil.instance;
+  }
+
+  registerFont(fontOption: font.FontOptions | font.FontOptions[]) {
+    if (Array.isArray(fontOption)) {
+      fontOption.forEach(item => {
+        ContextHelper.UIContext.getFont().registerFont(item)
+      })
+    } else {
+      ContextHelper.UIContext.getFont().registerFont(fontOption)
+    }
+  }
+}
+
+export const registerFontUtil = RegisterFontUtil.getInstance()

+ 78 - 15
commons/basic/src/main/ets/utils/YTPhotoHelper.ets

@@ -5,7 +5,10 @@ import { util } from '@kit.ArkTS';
 import { photoAccessHelper } from '@kit.MediaLibraryKit';
 import { image } from '@kit.ImageKit';
 import { BusinessError } from '@kit.BasicServicesKit';
-import { YTLog } from '../../../../Index';
+import { ContextHelper, ResultCallBack, YTLog } from '../../../../Index';
+import { componentSnapshot } from '@kit.ArkUI';
+import fs from '@ohos.file.fs';
+
 
 /**
  * @method cashPhotos 传入需要下载得url数组并下载文件,通过回调函数返回对应cashPaths数组
@@ -14,19 +17,16 @@ import { YTLog } from '../../../../Index';
  * @method saveByShowAssetsCreationDialog 通过ShowAssetsCreationDialog保存文件(弹窗)
  * @method getPhotoFileBuffer 将缓存的图片转化为流
  * @method saveImgToAssets 直接保存图片至相册 需要权限
+ * @method saveScreenshotToAlbum 截屏保存图片
+ * @method manualCompression压缩图片
  */
 export class YTPhotoHelper {
   private cashPaths: string[] = []
   private currentIndex: number = 0
-  private readonly context: Context
-
-  constructor(context: Context) {
-    this.context = context
-  }
 
   //传入需要下载得url数组并下载文件,通过回调函数返回对应cashPaths数组
   async cashPhotos(urls: string[], finishDownLoad: (cashPaths: string[]) => void, cashPhotoType: string = '.jpg') {
-    let filePath = this.context.cacheDir + '/' + util.generateRandomUUID() + cashPhotoType
+    let filePath = ContextHelper.context.cacheDir + '/' + util.generateRandomUUID() + cashPhotoType
     // Download the file. If the file already exists, delete the existing one first.
     try {
       fileIo.accessSync(filePath);
@@ -38,7 +38,7 @@ export class YTPhotoHelper {
     await axios({
       url: urls[this.currentIndex],
       method: 'get',
-      context: getContext(this),
+      context: ContextHelper.context,
       filePath: filePath,
       onDownloadProgress: (progressEvent: AxiosProgressEvent): void => {
         YTLog.info("progress: " + progressEvent && progressEvent.loaded && progressEvent.total ?
@@ -56,7 +56,7 @@ export class YTPhotoHelper {
 
   //拍照获取图片
   async takePicture() {
-    let pathDir = this.context.filesDir;
+    let pathDir = ContextHelper.context.filesDir;
     let fileName = `${new Date().getTime()}`
     let filePath = pathDir + `/${fileName}.png`
     fileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE);
@@ -67,7 +67,8 @@ export class YTPhotoHelper {
       saveUri: uri
     };
     let result: picker.PickerResult =
-      await picker.pick(this.context, [picker.PickerMediaType.PHOTO], //(如果需要录像可以添加) picker.PickerMediaType.VIDEO
+      await picker.pick(ContextHelper.context, [picker.PickerMediaType.PHOTO],
+        //(如果需要录像可以添加) picker.PickerMediaType.VIDEO
         pickerProfile);
     if (!result.resultUri) {
       return Promise.reject('用户未拍照')
@@ -85,7 +86,7 @@ export class YTPhotoHelper {
       .then(res => {
         const photoName = util.generateRandomUUID()
         const photoType = '.' + res.photoUris[0].split('.').pop()
-        const fullPath = this.context.cacheDir + '/' + photoName + photoType
+        const fullPath = ContextHelper.context.cacheDir + '/' + photoName + photoType
         const photo = fileIo.openSync(res.photoUris[0])
         try {
           fileIo.copyFile(photo.fd, fullPath)
@@ -99,10 +100,48 @@ export class YTPhotoHelper {
       })
   }
 
+  // 保存截图到相册的方法
+  async saveScreenshotToAlbum(activityId: string, result?: ResultCallBack<undefined>, clearCashPaths: boolean = false) {
+    try {
+      // 获取组件截图
+      const pixelMap = componentSnapshot.getSync(activityId)
+
+      if (!pixelMap) {
+        console.error('Failed to get screenshot')
+        return
+      }
+
+      // 创建临时文件路径
+      const tempDir = ContextHelper.context.tempDir
+      const filePath = tempDir + '/screenshot_' + util.generateRandomUUID() + '.jpg'
+
+      // 将PixelMap打包为JPEG格式
+      const imagePacker = image.createImagePacker()
+      const packOptions: image.PackingOption = {
+        format: 'image/jpeg',
+        quality: 90
+      }
+
+      const data = await imagePacker.packing(pixelMap, packOptions)
+
+      // 写入文件
+      const file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
+      fs.writeSync(file.fd, data)
+      fs.closeSync(file)
+      this.saveByShowAssetsCreationDialog([filePath], result, clearCashPaths)
+
+
+    } catch (error) {
+      console.error('Error saving screenshot: ' + JSON.stringify(error))
+    }
+  }
 
   //传入需要保存得cashPaths数组,并通过ShowAssetsCreationDialog保存文件
-  async saveByShowAssetsCreationDialog(cashPaths: string[], success?: () => void) {
-    const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
+  async saveByShowAssetsCreationDialog(
+    cashPaths: string[],
+    result?: ResultCallBack<undefined>,
+    clearCashPaths: boolean = false) {
+    const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(ContextHelper.context);
     const uris = cashPaths.map(item => fileUri.getUriFromPath(item))
     try {
       // 指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选。
@@ -129,9 +168,13 @@ export class YTPhotoHelper {
         await fileIo.close(file)
         index++
       }
-      success?.()
+      result?.()
+      if (clearCashPaths) {
+        cashPaths.forEach(cashPath => fileIo.unlink(cashPath))
+      }
     } catch (err) {
       YTLog.error(err)
+      result?.(undefined, err)
     }
   }
 
@@ -160,7 +203,7 @@ export class YTPhotoHelper {
       while (index < cashPaths.length) {
         //获取当前上下文
         //通过accessHelper模块获取accessHelper对象
-        let accessHelper = photoAccessHelper.getPhotoAccessHelper(getContext())
+        let accessHelper = photoAccessHelper.getPhotoAccessHelper(ContextHelper.context)
         //指定待创建的文件类型、后缀和创建选项,创建图片或视频资源 返回创建的图片和视频的uri
         let uri = await accessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg')
         //通过该uri打开图片
@@ -178,4 +221,24 @@ export class YTPhotoHelper {
       YTLog.error(e)
     }
   }
+
+  /**
+   * 手动压缩图片
+   * @param filePath 图片路径
+   * @param result 回调
+   * @param quality 压缩质量
+   */
+  async manualCompression(filePath: string, result: (imagePath: string) => void, quality: number = 20) {
+    const imageSourceApi: image.ImageSource = image.createImageSource(filePath);
+    const packOpts: image.PackingOption = { format: "image/jpeg", quality };
+    const imagePackerApi = image.createImagePacker()
+    const buffer = await imagePackerApi.packing(imageSourceApi, packOpts)
+    const imagePath = ContextHelper.context.cacheDir + '/' + util.generateRandomUUID() + '.jpeg'
+    const file = fileIo.openSync(imagePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
+    fileIo.writeSync(file.fd, buffer)
+    fileIo.closeSync(file)
+    fileIo.unlinkSync(filePath)
+    result(imagePath)
+    return imagePath
+  }
 }

+ 37 - 24
commons/basic/src/main/ets/utils/YTToast.ets

@@ -1,14 +1,16 @@
 import { BusinessError } from '@kit.BasicServicesKit';
 import { ComponentContent, promptAction } from '@kit.ArkUI';
 import { UIContext } from '@ohos.arkui.UIContext';
-import { BasicType, YTLog } from '../../../../Index';
-import { yTDoubleConfirm } from '../components/generalComp/YtDoubleConfirm';
-import { agreePrivacy } from '../components/generalComp/AgreePrivacy';
+import { BasicType, ContextHelper, YTLog } from '../../../../Index';
+import { yTDoubleConfirm } from '../components/ToastBuilders/YtDoubleConfirm';
+import { agreePrivacy } from '../components/ToastBuilders/AgreePrivacy';
 import { LoginCollect } from '../models/LoginCollect';
+import { loginToUse } from '../components/ToastBuilders/LoginToUse';
 
 interface InitOption {
-  context: UIContext;
-  options: promptAction.BaseDialogOptions;
+  context?: UIContext;
+  key: string;
+  options?: promptAction.BaseDialogOptions;
 }
 
 
@@ -35,29 +37,34 @@ export class Params<T> implements BasicType<T> {
 }
 
 export class YTToast {
-  private static declare instance: YTToast
-  private declare ctx: UIContext;
+  private static instanceMap: Map<string, YTToast> = new Map()
   private declare contentNode: ComponentContent<Object> | null;
   private declare options: promptAction.BaseDialogOptions;
   private maskColor: string = '#80000000'
 
-  static getInstance() {
-    if (!YTToast.instance) {
-      YTToast.instance = new YTToast()
+  constructor(initOption: InitOption) {
+    if (YTToast.instanceMap.get(initOption.key)) {
+      YTToast.getInstance(initOption.key).hide()
+    }
+    YTToast.instanceMap.set(initOption.key, this)
+    if (initOption.options) {
+      this.options = initOption.options;
+    } else {
+      this.options = { alignment: DialogAlignment.Center, maskColor: this.maskColor }
     }
-    return YTToast.instance
-  }
 
-  init(initOption: InitOption) {
-    this.ctx = initOption.context;
-    initOption.options.maskColor = this.maskColor
-    this.options = initOption.options;
   }
 
-  setContext(context: UIContext) {
-    this.ctx = context;
+  static getInstance(key: string = 'defaultKey') {
+    const instance = YTToast.instanceMap.get(key)
+    if (instance) {
+      return instance
+    } else {
+      return new YTToast({ key })
+    }
   }
 
+
   setContentNode(node: ComponentContent<Object>) {
     this.contentNode = node;
   }
@@ -70,8 +77,8 @@ export class YTToast {
     BasicType
   ]>, item: BasicType) {
     this.contentNode =
-      new ComponentContent(this.ctx, builder, new Params<undefined>(item));
-    this.ctx.getPromptAction()
+      new ComponentContent(ContextHelper.UIContext, builder, new Params<undefined>(item));
+    ContextHelper.UIContext.getPromptAction()
       .openCustomDialog(this.contentNode, this.options)
       .then(() => {
         console.info('OpenCustomDialog complete.')
@@ -91,11 +98,15 @@ export class YTToast {
     this.openToast(wrapBuilder(agreePrivacy), item)
   }
 
+  loginToUse(item: BasicType = {}) {
+    this.openToast(wrapBuilder(loginToUse), item)
+  }
+
 
   hide() {
     try {
       if (this.contentNode !== null) {
-        this.ctx.getPromptAction()
+        ContextHelper.UIContext.getPromptAction()
           .closeCustomDialog(this.contentNode)
           .then(() => {
             this.contentNode = null
@@ -114,7 +125,7 @@ export class YTToast {
 
   updateDialog(options: promptAction.BaseDialogOptions) {
     if (this.contentNode !== null) {
-      this.ctx.getPromptAction()
+      ContextHelper.UIContext.getPromptAction()
         .updateCustomDialog(this.contentNode, options)
         .then(() => {
           console.info('UpdateCustomDialog complete.')
@@ -128,11 +139,13 @@ export class YTToast {
   }
 
   confirmDeleteFolder(sure: () => void) {
-    yTToast.doubleConfirm({
+    this.doubleConfirm({
       message: '删除该分类将会同时删除分类下所\n有信息', click: sure
     })
   }
 }
 
-export const yTToast = YTToast.getInstance()
+
+export const yTToast: YTToast = new YTToast({ key: 'defaultKey' })
+
 

BIN
commons/basic/src/main/resources/rawfile/MiSansVF.ttf


BIN
commons/basic/src/main/resources/rawfile/SourceHanSansCN.otf


BIN
commons/basic/src/main/resources/rawfile/SourceHanSansSC.otf


+ 40 - 0
features/feature/src/main/ets/components/FloatingComp.ets

@@ -0,0 +1,40 @@
+import { UserInfo, userInfo } from 'basic';
+
+@Component
+export struct FloatingComp {
+  @Prop src: ResourceStr = $r('[basic].media.app_icon')
+  initPosition: Position | Edges | LocalizedEdges = { right: '50%', bottom: 20 }
+  imageWidth: number = 48
+  @State private cumulativeX: number = 0;
+  @State private cumulativeY: number = 0;
+  @StorageProp(UserInfo.KEY) private userInfo: UserInfo = userInfo
+  private startX: number = 0;
+  private startY: number = 0;
+  click = () => {
+  }
+
+  build() {
+    if (this.userInfo.checkLogin()) {
+      Image(this.src)
+        .width(this.imageWidth)
+        .aspectRatio(1)
+        .borderRadius(9999)
+        .gesture(
+          PanGesture({ distance: 1 })
+            .onActionStart(() => {
+              this.startX = this.cumulativeX;
+              this.startY = this.cumulativeY;
+            })
+            .onActionUpdate(event => {
+              // 记录起始位置
+              this.cumulativeX = this.startX + event.offsetX;
+              this.cumulativeY = this.startY + event.offsetY;
+            })
+        )
+        .translate({ x: this.cumulativeX, y: this.cumulativeY })
+        .position(this.initPosition)
+        .markAnchor({ x: -this.imageWidth / 2 })
+        .onClick(this.click)
+    }
+  }
+}

+ 2 - 1
features/feature/src/main/ets/view/SecondView.ets

@@ -1,6 +1,7 @@
+
 @Component
 export struct SecondView {
   build() {
-    Text('2')
+
   }
 }

+ 1 - 1
features/feature/src/main/ets/view/ThirdView.ets

@@ -1,6 +1,6 @@
 @Component
 export struct ThirdView {
   build() {
-    Text('3')
+
   }
 }

+ 22 - 9
features/user/src/main/ets/pages/DelPhotoPage.ets

@@ -1,4 +1,14 @@
-import { CropController, CropView, IBestToast, YTAvoid, YTLog, yTRouter, YTUserRequest } from 'basic'
+import {
+  CropController,
+  CropView,
+  IBestToast,
+  YTAvoid,
+  YTLog,
+  YTPhotoHelper,
+  YTRequest,
+  yTRouter,
+  YTUserRequest
+} from 'basic'
 import { fileIo } from '@kit.CoreFileKit'
 import { util } from '@kit.ArkTS'
 import { emitter } from '@kit.BasicServicesKit'
@@ -197,19 +207,22 @@ struct DelPhotoPage {
 
                   if (this.type == 'header') {
                     IBestToast.showLoading({ message: '上传中...' })
-                    YTUserRequest.uploadHeadImg(this.getUIContext().getHostContext()!, fullpath, () => {
-                      YTUserRequest.refreshUserInfo(() => {
-                        IBestToast.hide()
-                        setTimeout(() => {
-                          IBestToast.show({ message: '头像修改成功', type: 'success' })
-                        }, 100)
+                    new YTPhotoHelper().manualCompression(fullpath, (fullpath) => {
+                      YTUserRequest.uploadHeadImg(fullpath, () => {
+                        YTUserRequest.refreshUserInfo(() => {
+                          IBestToast.hide()
+                          setTimeout(() => {
+                            IBestToast.show({ message: '头像修改成功', type: 'success' })
+                          }, 100)
+                        })
                       })
+                      yTRouter.routerBack()
                     })
-                    yTRouter.routerBack()
+
                   }
                   if (this.type == 'image') {
                     IBestToast.showLoading({ message: '上传中...' })
-                    YTUserRequest.uploadFile(this.getUIContext().getHostContext()!, fullpath, (url) => {
+                    YTRequest.uploadFile(fullpath, (url) => {
                       emitter.emit('upLoadEnd', { data: url })
                       IBestToast.hide()
                       yTRouter.routerBack()

+ 1 - 1
features/user/src/main/ets/pages/SettingPage.ets

@@ -29,7 +29,7 @@ struct SettingPage {
   @StorageProp(YTAvoid.SAFE_BOTTOM_KEY) private safeBottom: number = 0
   @StorageProp(UserInfo.KEY) private userInfo: UserInfo = userInfo
   @State private value: string = ''
-  private yTPhotoHelper = new YTPhotoHelper(this.getUIContext().getHostContext()!)
+  private yTPhotoHelper = new YTPhotoHelper()
   private reviseBuilderArr: Array<BasicType> = [
     {
       text: '头像修改',

+ 1 - 0
features/user/src/main/ets/views/LoginView.ets

@@ -99,6 +99,7 @@ export struct LoginView {
             .fontSize(12)
             .onClick(() => {
               this.loginCollect.isPassword = false
+              this.loginCollect.password = ''
             })
           Blank()
           Text('忘记密码?')

+ 4 - 49
products/entry/src/main/ets/entryability/EntryAbility.ets

@@ -2,18 +2,8 @@ import { AbilityConstant, bundleManager, ConfigurationConstant, UIAbility, Want
 import { hilog } from '@kit.PerformanceAnalysisKit';
 import { window } from '@kit.ArkUI';
 import {
-  AppStorageKeyCollect,
-  IBestInit,
-  jHStartAd,
-  permissionController,
-  pushMessageUtil,
-  YTAvoid,
-  YTBreakPoint,
-  YTLog,
-  yTPreferences
+  AppStorageKeyCollect, IBestInit, YTAvoid, YTBreakPoint, YTLog
 } from 'basic';
-import { identifier } from '@kit.AdsKit';
-import { BusinessError } from '@kit.BasicServicesKit';
 
 const DOMAIN = 0x0000;
 
@@ -41,8 +31,6 @@ export default class EntryAbility extends UIAbility {
         logSize: 800
       })
 
-      PersistentStorage.persistProp<string>(AppStorageKeyCollect.TOKEN, '')
-
       IBestInit(windowStage, this.context)
       bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO)
         .then(res => {
@@ -51,35 +39,6 @@ export default class EntryAbility extends UIAbility {
         .catch((err: Error) => {
           YTLog.error(err)
         })
-      permissionController.init(this.context)
-        .then(() => {
-          permissionController
-            .askPermissions(["ohos.permission.APP_TRACKING_CONSENT"], (res, err) => {
-              if (err) {
-                YTLog.error(err)
-              } else {
-                if (res?.authResults[0] === 0) {
-                  YTLog.info('succeeded in requesting permission');
-                  identifier.getOAID((err: BusinessError, data: string) => {
-                    if (err.code) {
-                      YTLog.error(`get oaid failed, error: ${err.code} ${err.message}`);
-                    } else {
-                      const oaid: string = data;
-                      jHStartAd.init(this.context, oaid)
-                      AppStorage.setOrCreate('OAID', oaid)
-                      YTLog.info(`succeeded in getting oaid by callback , oaid: ${oaid}`);
-                    }
-                  });
-                } else {
-                  YTLog.error('user rejected');
-                }
-              }
-            })
-        })
-      // IBestSetGlobalConfig({
-      //   unit: "vp",
-      //   fontUnit: "vp"
-      // })
       const windowClass = windowStage.getMainWindowSync()
       windowClass.setWindowLayoutFullScreen(true)
       const top = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height
@@ -100,17 +59,13 @@ export default class EntryAbility extends UIAbility {
         }
       })
       const windowWidth = windowClass.getWindowProperties().windowRect.width
-      const windowHeight= windowClass.getWindowProperties().windowRect.height
-      YTBreakPoint.setBreakPoint(windowWidth,windowHeight)
+      const windowHeight = windowClass.getWindowProperties().windowRect.height
+      YTBreakPoint.setBreakPoint(windowWidth, windowHeight)
       windowClass.on('windowSizeChange', size => {
-        YTBreakPoint.setBreakPoint(size.width,size.height)
+        YTBreakPoint.setBreakPoint(size.width, size.height)
         AppStorage.setOrCreate(AppStorageKeyCollect.SCREEN_WIDTH, px2vp(size.width))
         AppStorage.setOrCreate(AppStorageKeyCollect.SCREEN_HEIGHT, px2vp(size.height))
       })
-      yTPreferences.init(this.context)
-      pushMessageUtil.init(this.context)
-      // const res = this.context.resourceManager.getRawFileContentSync('images/types.webp')
-
     });
 
   }

+ 3 - 15
products/entry/src/main/ets/pages/Index.ets

@@ -1,7 +1,6 @@
-import { BasicType, YTAvoid, yTRouter, yTToast, YTUserRequest } from 'basic';
+import { BasicType, ContextHelper, YTAvoid, yTRouter } from 'basic';
 import { Mine } from 'user/src/main/ets/views/Mine';
 import { MainView, SecondView, ThirdView } from 'feature';
-import { resourceManager } from '@kit.LocalizationKit';
 
 @Entry
 @Component
@@ -34,18 +33,7 @@ struct Index {
   tabsController: TabsController = new TabsController()
 
   aboutToAppear(): void {
-
-
-    yTToast.init({
-      context: this.getUIContext(),
-      options: { alignment: DialogAlignment.Center, maskColor: '#80000000' }
-    })
-
-    YTUserRequest.refreshUserInfo((res, err) => {
-      if (!err && res) {
-        //TODO 在此处发起需要登录的请求
-      }
-    })
+    ContextHelper.init(this.getUIContext())
   }
 
   build() {
@@ -72,6 +60,7 @@ struct Index {
         })
         .barHeight(0)
         .layoutWeight(1)
+        .scrollable(false)
 
         Row() {
           ForEach(this.contentList, (item: BasicType<undefined>, index) => {
@@ -105,7 +94,6 @@ struct Index {
         .lineHeight(16)
         .fontColor(this.currentIndex == item.index ? $r('[basic].color.main_ac_color_dark') :
         $r('[basic].color.main_na_color'))
-
     }
     .margin({ top: 5 })
     .onClick(() => {