polish iOS study flow
This commit is contained in:
@@ -1,13 +1,28 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
protocol AnalyticsTracking {
|
||||
func track(_ event: String, attributes: [String: String])
|
||||
}
|
||||
|
||||
final class HermesAnalyticsClient: AnalyticsTracking {
|
||||
struct HermesTrackedEvent: Identifiable, Equatable {
|
||||
let id = UUID()
|
||||
let event: String
|
||||
let attributes: [String: String]
|
||||
let timestamp: Date
|
||||
}
|
||||
|
||||
@MainActor
|
||||
final class HermesAnalyticsClient: ObservableObject, AnalyticsTracking {
|
||||
@Published private(set) var trackedEvents: [HermesTrackedEvent] = []
|
||||
|
||||
func track(_ event: String, attributes: [String: String]) {
|
||||
// Scaffold implementation.
|
||||
_ = event
|
||||
_ = attributes
|
||||
trackedEvents.append(
|
||||
HermesTrackedEvent(
|
||||
event: event,
|
||||
attributes: attributes,
|
||||
timestamp: Date()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ struct HermesMetricPill: View {
|
||||
struct HermesCountdownBadge: View {
|
||||
let label: String
|
||||
let value: String
|
||||
var warning: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
@@ -123,11 +124,11 @@ struct HermesCountdownBadge: View {
|
||||
.foregroundStyle(HermesTheme.textTertiary)
|
||||
Text(value)
|
||||
.font(.title3.weight(.bold))
|
||||
.foregroundStyle(HermesTheme.accent)
|
||||
.foregroundStyle(warning ? HermesTheme.warning : HermesTheme.accent)
|
||||
}
|
||||
.padding(.horizontal, 14)
|
||||
.padding(.vertical, 12)
|
||||
.background(HermesTheme.accentSoft)
|
||||
.background((warning ? HermesTheme.warning : HermesTheme.accent).opacity(0.16))
|
||||
.clipShape(RoundedRectangle(cornerRadius: HermesTheme.insetRadius, style: .continuous))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,37 @@
|
||||
import AVFoundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
final class PlayerCoordinator: ObservableObject {
|
||||
let player: AVPlayer
|
||||
|
||||
@Published var isPlaying = false
|
||||
@Published var playbackPositionMs: Int = 0
|
||||
|
||||
init(previewURL: URL = URL(string: "https://cdn.example.com/hermes/sample-event/master.m3u8")!) {
|
||||
self.player = AVPlayer(url: previewURL)
|
||||
self.player.actionAtItemEnd = .pause
|
||||
}
|
||||
|
||||
func prepareForPreview() {
|
||||
player.seek(to: .zero)
|
||||
player.play()
|
||||
isPlaying = true
|
||||
}
|
||||
|
||||
func play() {
|
||||
player.play()
|
||||
isPlaying = true
|
||||
}
|
||||
|
||||
func pause() {
|
||||
player.pause()
|
||||
isPlaying = false
|
||||
}
|
||||
|
||||
func restart() {
|
||||
player.seek(to: .zero)
|
||||
play()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import AVKit
|
||||
import SwiftUI
|
||||
|
||||
struct StudyVideoPlayerView: View {
|
||||
@ObservedObject var coordinator: PlayerCoordinator
|
||||
|
||||
var body: some View {
|
||||
VideoPlayer(player: coordinator.player)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 224)
|
||||
.clipShape(RoundedRectangle(cornerRadius: HermesTheme.cornerRadius, style: .continuous))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: HermesTheme.cornerRadius, style: .continuous)
|
||||
.stroke(HermesTheme.accent.opacity(0.12), lineWidth: 1)
|
||||
)
|
||||
.background(HermesTheme.surfaceElevated)
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,8 @@ struct HermesEventMedia: Codable {
|
||||
var id: UUID
|
||||
var eventId: UUID
|
||||
var mediaType: String
|
||||
var hlsMasterURL: URL
|
||||
var posterURL: URL?
|
||||
var hlsMasterUrl: URL
|
||||
var posterUrl: URL?
|
||||
var durationMs: Int
|
||||
var previewStartMs: Int
|
||||
var previewEndMs: Int
|
||||
|
||||
Reference in New Issue
Block a user