Hongmeng 4.0 development practice (ArkTS)-alarm clock production

Alarm clock function requirements

  1. Display analog dial or digital time.
  2. Add, modify and delete alarms.
  3. Displays a list of alarms and can turn individual alarms on and off.
  4. A reminder will pop up after the alarm clock reaches the set time.
  5. Save alarm clock timing data to a lightweight database.

Alarm clock main interface

The alarm clock interface includes the current time, alarm clock list, and add alarm clock subcomponent, specifically including the following modules:

  • Display the current time.
  • Displays a list of alarm clocks.
  • Add an alarm.
  • Background agent reminder.

Show current time

The current time is drawn using the Canvas component. The pointer dial is displayed by default. Click the dial area to switch to a digital clock. The effect is as shown in the figure:

Initialize the Canvas canvas in the ClockArea component of the home page, and bind the pointer dial and digital clock switching events.

// ClockArea.ets
@Component
export default struct ClockArea {
  build() {
    Canvas(this.renderContext)
      .width(this.canvasSize)
      .aspectRatio(CommonConstants.DEFAULT_LAYOUT_WEIGHT)
      .onReady(() => {
        if (this.drawInterval === CommonConstants.DEFAULT_NUMBER_NEGATIVE) {
          // 启动绘画任务    
          this.startDrawTask();
        }
      })
      .onClick(() => {
        this.showClock = !this.showClock;
      })
  }
  ...
  // 启动绘画任务
  private startDrawTask() {
    let that = this;
    that.renderContext.translate(
      this.canvasSize / CommonConstants.DEFAULT_DOUBLE,
      this.canvasSize / CommonConstants.DEFAULT_DOUBLE);
    that.drawClockArea();
    this.drawInterval = setInterval(() => {
      that.drawClockArea();
    }, MainConstant.DEFAULT_ONE_SECOND_MS);
  }
}

The painting task is to use the CanvasRenderingContext2D object to draw the pointer dial and digital clock on the Canvas canvas component.

// ClockArea.ets
// 开始绘制时钟区域
private drawClockArea(): void {
  this.renderContext.clearRect(
    -this.canvasSize,
    -this.canvasSize / CommonConstants.DEFAULT_DOUBLE,
    this.canvasSize * CommonConstants.DEFAULT_DOUBLE,
    this.canvasSize);
  let date = new Date();
  let hours = date.getHours();
  let minutes = date.getMinutes();
  let seconds = date.getSeconds();
  if (this.showClock) {
    // 绘制表盘时钟
    ...
  } else {
    // 绘制数字时钟
    ...
  }
}

Show alarm clock list

Displays the added alarm clock information. You can start and stop the alarm clock. Click the alarm clock to jump to the alarm clock operation interface (modify and delete the alarm clock). After the home page is started, the alarm clock timing data in the lightweight database is obtained and the database data changes are monitored.

// MainViewModel.ets
public queryAlarmsTasker(callback: (alarms: Array<AlarmItem>) => void) {
  let that = this;
  that.queryDatabaseAlarms(callback);
  let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler;
  preference.addPreferencesListener({
    onDataChanged() {
      that.queryDatabaseAlarms(callback);
    }
  } as PreferencesListener)
}

Add the alarm clock list subcomponent in AlarmList.ets and bind start, stop, and jump events.

// AlarmList.ets
@Component
export default struct AlarmList {
  @Link alarmItems: Array<AlarmItem>;

  build() {
    List({ space: DimensionUtil.getVp($r('app.float.alarm_list_space')) }) {
      ForEach(this.alarmItems, (item: AlarmItem) => {
        ListItem() {
          AlarmListItem({ alarmItem: item })
        }.onClick(() => {
          router.pushUrl({ url: 'pages/DetailIndex', params: { alarmItem: item } });
        })
      }, (item: AlarmItem) => JSON.stringify(item))
    }
    .padding({
      left: DimensionUtil.getVp($r('app.float.alarm_list_content_distance')),
      right: DimensionUtil.getVp($r('app.float.alarm_list_content_distance'))
    })
    .listDirection(Axis.Vertical)
    .layoutWeight(CommonConstants.DEFAULT_LAYOUT_WEIGHT)
    .margin({ top: DimensionUtil.getVp($r('app.float.alarm_list_content_distance')) })
  }
}

Add alarm

Click the alarm clock add button at the bottom of the interface to jump to the alarm clock operation interface (add alarm clock). The effect is as shown in the figure:

Bind the jump event to the add button in MainIndex.ets.

// MainIndex.ets
@Entry
@Component
struct MainIndex {
  ...
  build() {
    Column() {
      ...
      Button() {
        Image($r('app.media.ic_add')).objectFit(ImageFit.Fill)
      }
      ...
      .onClick(() => {
        router.pushUrl({ url: 'pages/DetailIndex' });
      })
    }
    ...
  }
}

Background agent reminder

Set (start and stop) the alarm instance based on the data in the alarm list.

// MainViewModel.ets
// 开启/关闭闹钟
public openAlarm(id: number, isOpen: boolean) {
  for (let i = 0; i < this.alarms.length; i++) {
    if (this.alarms[i].id === id) {
      this.alarms[i].isOpen = isOpen;
      if (isOpen) {
        this.reminderService.addReminder(this.alarms[i]);
      } else {
        this.reminderService.deleteReminder(this.alarms[i].id);
      }
      let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler;
      preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms));
      break;
    }
  }
}

Alarm clock details interface

The alarm clock operation interface is divided into new and modified interfaces, in which the alarm clock can be deleted in the modified interface. Specifically including the following modules:

  • Exit or save details.
  • Set alarm time.
  • Set alarm details.
  • Provide background agent reminder capabilities

Exit or save details

Click the "x" icon in the upper left corner to close the operation interface and close the alarm clock operation interface subcomponent. Click the "√" icon in the upper right corner to save the current settings and close the operation interface.

Introduce the header component BackContainer into the DetailIndex.ets entry page, customize the return button and return logic operations, add the OK ("√") subcomponent, and bind the click event.

// BackContainer.ets
build() {
  Row() {
    Button() {
      Image(this.backImgRes == null ? $r('app.media.ic_public_back') : this.backImgRes).objectFit(ImageFit.Fill)
    }
    .backgroundColor($r('app.color.trans_parent'))
    .width(DimensionUtil.getVp($r('app.float.title_button_size')))
    .height(DimensionUtil.getVp($r('app.float.title_button_size')))
    .onClick(() => {
        this.backFunc ? this.backFunc() : router.back();
    })

    Text(this.header)
      .fontSize(DimensionUtil.getFp($r('app.float.detail_title_font_size')))
      .lineHeight(DimensionUtil.getVp($r('app.float.title_line_height')))
      .margin({ left: DimensionUtil.getVp($r('app.float.title_margin')) })
      .fontColor($r('app.color.grey_divider'))
      .fontWeight(FontWeight.Bold)
    Blank()
    if (this.closer) {
      this.closer();
    }
  }
  .padding({
    left: DimensionUtil.getVp($r('app.float.title_horizon_margin')),
    right: DimensionUtil.getVp($r('app.float.title_horizon_margin'))
  })
  .height(DimensionUtil.getVp($r('app.float.page_title_height')))
  .width(CommonConstants.FULL_LENGTH)
}

Set alarm time

Set the alarm reminder time. In the alarm clock operation interface, you can set the alarm reminder time (including: period, hour, minute) by sliding the selector. Add the alarm time picker subcomponent DatePickArea.ets to the details page DetailIndex.ets.

// DatePickArea.ets
@Component
export default struct DatePickArea {
  build() {
    Stack({ alignContent: Alignment.Center }) {
      Row() {
        ForEach(DetailConstant.DAY_DATA, (item: DayDataItem) => {
          TextPicker({ range: item.data, selected: item.delSelect })
            .layoutWeight(CommonConstants.DEFAULT_LAYOUT_WEIGHT)
            .backgroundColor($r('app.color.grey_light'))
            .onChange((value: string, index: number) => {
              item.delSelect = index;
            })
        }, (item: DayDataItem) => JSON.stringify(item))
      }
    }
    .height(DimensionUtil.getVp($r('app.float.date_picker_height')))
    .padding({
      left: DimensionUtil.getVp($r('app.float.date_picker_padding_horizon')),
      right: DimensionUtil.getVp($r('app.float.date_picker_padding_horizon'))
    })
  }
}

Set alarm time

Set the alarm reminder time. In the alarm clock operation interface, you can set the alarm reminder time (including: period, hour, minute) by sliding the selector. Add the alarm time picker subcomponent DatePickArea.ets to the details page DetailIndex.ets.

// DatePickArea.ets
@Component
export default struct DatePickArea {
  build() {
    Stack({ alignContent: Alignment.Center }) {
      Row() {
        ForEach(DetailConstant.DAY_DATA, (item: DayDataItem) => {
          TextPicker({ range: item.data, selected: item.delSelect })
            .layoutWeight(CommonConstants.DEFAULT_LAYOUT_WEIGHT)
            .backgroundColor($r('app.color.grey_light'))
            .onChange((value: string, index: number) => {
              item.delSelect = index;
            })
        }, (item: DayDataItem) => JSON.stringify(item))
      }
    }
    .height(DimensionUtil.getVp($r('app.float.date_picker_height')))
    .padding({
      left: DimensionUtil.getVp($r('app.float.date_picker_padding_horizon')),
      right: DimensionUtil.getVp($r('app.float.date_picker_padding_horizon'))
    })
  }
}

Set alarm details

// SettingItem.ets
build() {
  Column() {
    ForEach(this.settingInfo, (item: AlarmSettingItem, index: number | undefined) => {
      Divider()
      ...
      Row() {
        Text(item.title)
          ...
        Text(item.content)
          ...
        Image($r('app.media.ic_right'))
        ...
      }
      ...
      .onClick(() => {
        this.showSettingDialog(item.sType);
      })
    }, (item: AlarmSettingItem, index: number | undefined) => JSON.stringify(item) + index)
  }
  ...
}

Provide background agent reminder capabilities

Import the system reminder service class ReminderService.ets, which is encapsulated by the system background agent reminder capability and supports adding, modifying, and deleting system alarm clock functions. After setting or deleting the alarm clock, it is synchronously updated to the lightweight database and refreshes the home page.

// DetailViewModel.ets
public async setAlarmRemind(alarmItem: AlarmItem) {
  alarmItem.hour = this.getAlarmTime(CommonConstants.DEFAULT_SINGLE);
  alarmItem.minute = this.getAlarmTime(CommonConstants.DEFAULT_DATA_PICKER_HOUR_SELECTION);
  let index = await this.findAlarmWithId(alarmItem.id);
  if (index !== CommonConstants.DEFAULT_NUMBER_NEGATIVE) { 
    // 已存在,删除原有提醒
    this.reminderService.deleteReminder(alarmItem.id);
  } else { 
    // 不存在,以数据长度为notificationId新增闹钟数据
    index = this.alarms.length;
    alarmItem.notificationId = index;
    this.alarms.push(alarmItem);
  }
  this.reminderService.addReminder(alarmItem, (newId: number) => {
    alarmItem.id = newId;
    alarmItem.isOpen = true;
    this.alarms[index] = alarmItem;
    let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler;
    preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms));
  })
}

public async removeAlarmRemind(id: number) {
  this.reminderService.deleteReminder(id);
  let index = await this.findAlarmWithId(id);
  if (index !== CommonConstants.DEFAULT_NUMBER_NEGATIVE) {
    this.alarms.splice(index, CommonConstants.DEFAULT_SINGLE);
  }
  let preference = GlobalContext.getContext().getObject('preference') as PreferencesHandler;
  preference.set(CommonConstants.ALARM_KEY, JSON.stringify(this.alarms));
}

The full text is about the application of technology developed by Hongmeng. For more practical technologies developed by Hongmeng, you can go to the homepage to view more information. Share a copy of Hongmeng’s learning roadmap (abbreviated version). Find the full high-definition version on the homepage and save it with me.

at last

Implement a simple alarm clock rendering:

Guess you like

Origin blog.csdn.net/m0_70748845/article/details/135250620