Przeglądaj źródła

feat(card): add music card snapshot model

onecold 4 miesięcy temu
rodzic
commit
6bc359a1e9

+ 2 - 0
entry/src/main/ets/common/player/MusicCardConstants.ets

@@ -0,0 +1,2 @@
+export const MUSIC_CARD_EMPTY_TITLE = '未在播放'
+export const MUSIC_CARD_EMPTY_ARTIST = '点击打开播放器'

+ 141 - 0
entry/src/main/ets/common/player/MusicCardSnapshot.ets

@@ -0,0 +1,141 @@
+import { MUSIC_CARD_EMPTY_ARTIST, MUSIC_CARD_EMPTY_TITLE } from './MusicCardConstants'
+
+export interface MusicCardSnapshot {
+  title: string
+  artist: string
+  lyricText: string
+  positionMs: number
+  hasSong: boolean
+}
+
+export interface MusicCardLyricLines {
+  line1: string
+  line2: string
+  hasLyric: boolean
+}
+
+export class MusicCardBindingData {
+  title: string
+  artist: string
+  hasSong: boolean
+  lyricLine1: string
+  lyricLine2: string
+
+  constructor(
+    title: string,
+    artist: string,
+    hasSong: boolean,
+    lyricLine1: string,
+    lyricLine2: string
+  ) {
+    this.title = title
+    this.artist = artist
+    this.hasSong = hasSong
+    this.lyricLine1 = lyricLine1
+    this.lyricLine2 = lyricLine2
+  }
+}
+
+const LYRIC_LINE_PATTERN = /^\[(\d{2}):(\d{2})\.(\d{2})\](.*)$/
+
+export function createEmptyMusicCardSnapshot(): MusicCardSnapshot {
+  return {
+    title: '',
+    artist: '',
+    lyricText: '',
+    positionMs: 0,
+    hasSong: false
+  }
+}
+
+export function resolveMusicCardLyricLines(
+  lyricText: string,
+  positionMs: number
+): MusicCardLyricLines {
+  const trimmedText = lyricText ? lyricText.trim() : ''
+  if (trimmedText === '') {
+    return {
+      line1: MUSIC_CARD_EMPTY_TITLE,
+      line2: MUSIC_CARD_EMPTY_ARTIST,
+      hasLyric: false
+    }
+  }
+
+  const entries: Array<{ timeMs: number; text: string }> = []
+  const rawLines = trimmedText.split(/\r?\n/)
+  for (let i = 0; i < rawLines.length; i++) {
+    const rawLine = rawLines[i].trim()
+    if (rawLine === '') {
+      continue
+    }
+
+    const match = rawLine.match(LYRIC_LINE_PATTERN)
+    if (!match) {
+      continue
+    }
+
+    const minutes = parseInt(match[1])
+    const seconds = parseInt(match[2])
+    const centiseconds = parseInt(match[3])
+    const text = match[4].trim()
+    const timeMs = minutes * 60 * 1000 + seconds * 1000 + centiseconds * 10
+
+    entries.push({
+      timeMs,
+      text
+    })
+  }
+
+  if (entries.length === 0) {
+    return {
+      line1: MUSIC_CARD_EMPTY_TITLE,
+      line2: MUSIC_CARD_EMPTY_ARTIST,
+      hasLyric: false
+    }
+  }
+
+  entries.sort((lhs, rhs) => lhs.timeMs - rhs.timeMs)
+
+  let currentIndex = -1
+  for (let i = 0; i < entries.length; i++) {
+    if (entries[i].timeMs <= positionMs) {
+      currentIndex = i
+    } else {
+      break
+    }
+  }
+
+  if (currentIndex === -1) {
+    currentIndex = 0
+  }
+
+  const currentLine = entries[currentIndex]
+  const nextLine = entries[currentIndex + 1]
+
+  return {
+    line1: currentLine.text,
+    line2: nextLine ? nextLine.text : '',
+    hasLyric: true
+  }
+}
+
+export function buildMusicCardBindingData(snapshot: MusicCardSnapshot): MusicCardBindingData {
+  const source = snapshot || createEmptyMusicCardSnapshot()
+  const hasSong = Boolean(source.hasSong)
+  const lyricLines = resolveMusicCardLyricLines(source.lyricText, source.positionMs)
+
+  const title =
+    hasSong && source.title && source.title.trim() !== ''
+      ? source.title
+      : MUSIC_CARD_EMPTY_TITLE
+  const artist =
+    hasSong && source.artist && source.artist.trim() !== ''
+      ? source.artist
+      : MUSIC_CARD_EMPTY_ARTIST
+  const lyricLine1 =
+    lyricLines.hasLyric && lyricLines.line1 ? lyricLines.line1 : MUSIC_CARD_EMPTY_TITLE
+  const lyricLine2 =
+    lyricLines.hasLyric && lyricLines.line2 ? lyricLines.line2 : MUSIC_CARD_EMPTY_ARTIST
+
+  return new MusicCardBindingData(title, artist, hasSong, lyricLine1, lyricLine2)
+}

+ 29 - 0
entry/src/ohosTest/ets/test/MusicCardSnapshot.test.ets

@@ -0,0 +1,29 @@
+import { describe, it, expect } from '@ohos/hypium'
+import {
+  buildMusicCardBindingData,
+  createEmptyMusicCardSnapshot,
+  resolveMusicCardLyricLines
+} from '../../../main/ets/common/player/MusicCardSnapshot'
+
+export default function musicCardSnapshotTest() {
+  describe('MusicCardSnapshotTest', () => {
+    it('resolveMusicCardLyricLinesReturnsCurrentAndNextLine', 0, () => {
+      const lyricText = '[00:00.00]第一句\n[00:05.00]第二句\n[00:10.00]第三句'
+      const lines = resolveMusicCardLyricLines(lyricText, 6000)
+
+      expect(lines.line1).assertEqual('第二句')
+      expect(lines.line2).assertEqual('第三句')
+      expect(lines.hasLyric).assertEqual(true)
+    })
+
+    it('buildMusicCardBindingDataForEmptySnapshot', 0, () => {
+      const binding = buildMusicCardBindingData(createEmptyMusicCardSnapshot())
+
+      expect(binding.title).assertEqual('未在播放')
+      expect(binding.artist).assertEqual('点击打开播放器')
+      expect(binding.hasSong).assertEqual(false)
+      expect(binding.lyricLine1).assertEqual('未在播放')
+      expect(binding.lyricLine2).assertEqual('点击打开播放器')
+    })
+  })
+}