fixed some bugs on ios
This commit is contained in:
Binary file not shown.
@@ -318,21 +318,27 @@ final class PlayerController: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 只播放当前句子,播完自动暂停并回到句首(评测“播放原句”)。
|
/// 只播放当前句子,播完自动暂停并回到句首(评测“播放原句”)。
|
||||||
|
/// 必须先打上句尾标记再 seek,这样 completion 里的 forwardPlaybackEndTime
|
||||||
|
/// 会卡在当前句 endMs,而不是等 250ms 观察器才停。
|
||||||
func playCurrentSentenceAndStop() {
|
func playCurrentSentenceAndStop() {
|
||||||
guard let sentence = currentSentence else {
|
guard let sentence = currentSentence else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
performSeek(to: sentenceSeekPosition(sentence))
|
|
||||||
stopAtSentenceEnd = true
|
stopAtSentenceEnd = true
|
||||||
stopAtSentenceEndIndex = sentence.index
|
stopAtSentenceEndIndex = sentence.index
|
||||||
play()
|
lastSentenceIndex = sentence.index
|
||||||
|
playbackIntent = true
|
||||||
|
performSeek(to: sentenceSeekPosition(sentence), resumePlayback: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 设置
|
// MARK: - 设置
|
||||||
|
|
||||||
func setContinuousPlayback(_ enabled: Bool) {
|
func setContinuousPlayback(_ enabled: Bool) {
|
||||||
config.continuousPlayback = enabled
|
config.continuousPlayback = enabled
|
||||||
refreshSentenceBoundaryGuard()
|
if !enabled {
|
||||||
|
lastSentenceIndex = currentSentence?.index ?? lastSentenceIndex
|
||||||
|
}
|
||||||
|
refreshSentenceBoundaryGuard(force: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setSentenceMode(_ enabled: Bool) {
|
func setSentenceMode(_ enabled: Bool) {
|
||||||
@@ -783,6 +789,13 @@ final class PlayerController: ObservableObject {
|
|||||||
tick()
|
tick()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 评测“播放原句”即使处于连续播放,也要用当前句硬边界,不能滑进下一句。
|
||||||
|
if stopAtSentenceEnd,
|
||||||
|
let index = stopAtSentenceEndIndex,
|
||||||
|
let sentence = mediaItem?.sentences.first(where: { $0.index == index }) {
|
||||||
|
applySentenceEndAction(sentence)
|
||||||
|
return
|
||||||
|
}
|
||||||
// 若最后一个句子的 endMs 就是视频末尾,forwardPlaybackEndTime 和自然结束
|
// 若最后一个句子的 endMs 就是视频末尾,forwardPlaybackEndTime 和自然结束
|
||||||
// 是同一时间点。此时必须执行“当前句”的句尾动作,而不能整条视频回零。
|
// 是同一时间点。此时必须执行“当前句”的句尾动作,而不能整条视频回零。
|
||||||
if config.sentenceMode,
|
if config.sentenceMode,
|
||||||
|
|||||||
@@ -88,16 +88,20 @@ enum ImitationAssessor {
|
|||||||
appendFile(&body, boundary: boundary, name: "audio", filename: filename, mimeType: mimeType, data: recordingData)
|
appendFile(&body, boundary: boundary, name: "audio", filename: filename, mimeType: mimeType, data: recordingData)
|
||||||
body.append(Data("--\(boundary)--\r\n".utf8))
|
body.append(Data("--\(boundary)--\r\n".utf8))
|
||||||
|
|
||||||
|
var headers = [
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "multipart/form-data; boundary=\(boundary)",
|
||||||
|
"X-Client-Key": AppConfig.assessmentAPIKey,
|
||||||
|
]
|
||||||
|
if !AppConfig.authToken.isEmpty {
|
||||||
|
headers["Authorization"] = "Bearer \(AppConfig.authToken)"
|
||||||
|
}
|
||||||
let result = try await HTTPClient.execute(
|
let result = try await HTTPClient.execute(
|
||||||
baseURL: AppConfig.serverBaseURL,
|
baseURL: AppConfig.serverBaseURL,
|
||||||
path: path,
|
path: path,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
timeout: AppConfig.assessmentTimeout,
|
timeout: AppConfig.assessmentTimeout,
|
||||||
headers: [
|
headers: headers,
|
||||||
"Accept": "application/json",
|
|
||||||
"Content-Type": "multipart/form-data; boundary=\(boundary)",
|
|
||||||
"X-Client-Key": AppConfig.assessmentAPIKey,
|
|
||||||
],
|
|
||||||
body: body
|
body: body
|
||||||
)
|
)
|
||||||
guard (200...299).contains(result.statusCode) else {
|
guard (200...299).contains(result.statusCode) else {
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ struct RootView: View {
|
|||||||
.onChange(of: activeModule) { module in
|
.onChange(of: activeModule) { module in
|
||||||
if module == .train {
|
if module == .train {
|
||||||
controller.setContinuousPlayback(continuousPlayback)
|
controller.setContinuousPlayback(continuousPlayback)
|
||||||
|
} else if module == .test {
|
||||||
|
// 与安卓测试页一致:按当前句窗口播放,避免滑进下一句。
|
||||||
|
controller.setContinuousPlayback(false)
|
||||||
} else {
|
} else {
|
||||||
controller.setContinuousPlayback(true)
|
controller.setContinuousPlayback(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ struct TestView: View {
|
|||||||
PlayerSectionView(
|
PlayerSectionView(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
showsContinuousToggle: false,
|
showsContinuousToggle: false,
|
||||||
continuousPlayback: .constant(true),
|
continuousPlayback: .constant(false),
|
||||||
showsSubtitle: $testSubtitleVisible,
|
showsSubtitle: $testSubtitleVisible,
|
||||||
onFullscreen: onFullscreen
|
onFullscreen: onFullscreen
|
||||||
)
|
)
|
||||||
@@ -321,7 +321,7 @@ struct TestView: View {
|
|||||||
dubSegments[sentence.index] = audioURL
|
dubSegments[sentence.index] = audioURL
|
||||||
dubRawSegments[sentence.index] = rawPersistedURL
|
dubRawSegments[sentence.index] = rawPersistedURL
|
||||||
mergedDubURL = nil
|
mergedDubURL = nil
|
||||||
submitAssessment(recordingURL: url)
|
submitAssessment(recordingURL: audioURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func restorePlaybackAudioSession() {
|
private func restorePlaybackAudioSession() {
|
||||||
|
|||||||
Reference in New Issue
Block a user