BreakPointSystem.ets 3.8 KB
import mediaQuery from '@ohos.mediaquery';
import { Logger } from './Logger';

const TAG = 'BreakPointSystem';

interface Breakpoint {
  name: string
  size: number
  mediaQueryListener?: mediaQuery.MediaQueryListener
}

// 响应式布局:"phone","tablet","2in1"
// https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout.md/
declare interface BreakPointTypeOption<T> {
  xs: T; // [0, 320)       (最小宽度-类型设备)  // Wearable/可穿戴设备
  sm: T; // [320,600)        (小宽度-类型设备)  // Phone/折叠设备当前折叠状态为折叠FOLDED/手机(HUAWEI Mate 40 Pro & NOH-AN00)/折叠后345.6vp
  md: T; // [600,840)      (中等宽度-类型设备)  // Fold/折叠设备当前折叠状态为完全展开EXPANDED/折叠手机(HUAWEI Mate X5 & ALT-AL10)/展开后711.68vp
  lg: T; // [840,1080)      (大宽度-类型设备)  // Tablet/2in1(PC与Tablet二合一产品)/TV/Car/PC/laptop
  // xl?: T; // [1080,1440)    (特大宽度-类型设备)  // TV/如4K电视
  // xxl?:T; //[1440,+8)   (超大宽度-类型设备)  // TV/如8K以上(8K/16K)电视
}

export class BreakpointSystem {
  // 上次通知的断点
  private lastBreakpoint: string = ''
  private breakpoints: Breakpoint[] = [
    { name: 'xs', size: 0 },
    { name: 'sm', size: 320 },
    { name: 'md', size: 600 }, // 520vp
    { name: 'lg', size: 840 }
  ]

  private updateCurrentBreakpoint(breakpoint: string): void {
    Logger.info(TAG, 'updateCurrentBreakpoint lastBreakpoint: ' + this.lastBreakpoint + ", breakpoint:" + breakpoint)
    if (this.lastBreakpoint !== breakpoint) {
      this.lastBreakpoint = breakpoint
      AppStorage.setOrCreate<string>('currentBreakpoint', breakpoint)
      // AppStorage.setOrCreate<string>(BreakpointConstants.CURRENT_BREAKPOINT, this.currentBreakpoint);
      Logger.info(TAG, 'on current Breakpoint: ' + this.lastBreakpoint)
    }
  }

  public register() {
    this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
      let condition: string
      if (index === this.breakpoints.length - 1) {
        condition = '(' + breakpoint.size + 'vp<=width' + ')'
      } else {
        condition = '(' + breakpoint.size + 'vp<=width<' + this.breakpoints[index + 1].size + 'vp)'
      }
      Logger.info(TAG, "register matchMediaSync condition:" + condition);
      breakpoint.mediaQueryListener = mediaQuery.matchMediaSync(condition)
      breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => {
        // Logger.info(TAG, "register change mediaQueryResult:" + JSON.stringify(mediaQueryResult));
        if (mediaQueryResult.matches) {
          // Logger.info(TAG, "register breakpoint.name:" + JSON.stringify(breakpoint.name));
          this.updateCurrentBreakpoint(breakpoint.name)
        }
      })
    })
  }

  public unregister() {
    this.breakpoints.forEach((breakpoint: Breakpoint) => {
      if (breakpoint.mediaQueryListener) {
        breakpoint.mediaQueryListener.off('change')
      }
    })
  }
}

export class BreakPointType<T> {
  options: BreakPointTypeOption<T>

  constructor(option: BreakPointTypeOption<T>) {
    this.options = option
  }

  getValue(currentBreakPoint: string): T {
    // return this.options[currentBreakPoint] as T;
    // Logger.info(TAG, "getValue this.options:" + JSON.stringify(this.options));
    if (currentBreakPoint === 'xs') {
      return this.options.xs
    } else if (currentBreakPoint === 'sm') {
      return this.options.sm
    } else if (currentBreakPoint === 'md') {
      return this.options.md
    } else if (currentBreakPoint === 'lg') {
      return this.options.lg
      // } else if (currentBreakPoint === 'xl') {
      // return this.options.xl
      // } else if (currentBreakPoint === 'xxl') {
      //   return this.options.xxl
    } else {
      // return undefined
      return this.options.sm
    }
  }
}