Init voice broadcast playing service

This commit is contained in:
yostyle
2022-10-18 16:36:02 +02:00
parent 6a4ccaea5b
commit db461cf867
15 changed files with 222 additions and 13 deletions
@@ -51,8 +51,16 @@ final class TimelineVoiceBroadcastCoordinator: Coordinator, Presentable, VoiceBr
viewModel = TimelineVoiceBroadcastViewModel(timelineVoiceBroadcastDetails: buildTimelineVoiceBroadcastFrom(voiceBroadcastAggregator.voiceBroadcast))
// TODO: manage voicebroacast chunks
viewModel.completion = { }
viewModel.completion = { [weak self] result in
guard let self = self else { return }
switch result {
case .played:
MXLog.debug("click on play")
case .paused:
MXLog.debug("click on pause")
}
}
}
@@ -0,0 +1,36 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// Represents user live location
struct VoiceBroadcastChunk {
var userId: String {
avatarData.matrixItemId
}
var displayName: String {
avatarData.displayName ?? userId
}
let avatarData: AvatarInputProtocol
/// Chunk sequence number
let sequence: UInt
// TODO: add attachment here
let attachment: NSObject
}
@@ -0,0 +1,31 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Combine
import CoreLocation
import Foundation
protocol VoiceBroadcastPlaybackServiceProtocol {
/// All shared voice broadcast chunks
var voiceBroadcastChunks: [VoiceBroadcastChunk] { get }
/// Called when voice broadcast chunks are updated.
var didUpdateVoiceBroadcastChunks: (([VoiceBroadcastChunk]) -> Void)? { get set }
func startPlayingVoiceBroadcast()
func pausePlayingVoiceBroadcast()
}
@@ -17,10 +17,16 @@
import Foundation
import SwiftUI
typealias TimelineVoiceBroadcastViewModelCallback = () -> Void
// TODO: add play pause cases
enum TimelineVoiceBroadcastViewAction { }
enum TimelineVoiceBroadcastViewAction {
case play
case pause
}
enum TimelineVoiceBroadcastViewModelResult {
case played
case paused
}
enum TimelineVoiceBroadcastType {
case disclosed
@@ -0,0 +1,49 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
import SwiftUI
/// Using an enum for the screen allows you define the different state cases with
/// the relevant associated data for each case.
enum MockTimelineVoiceBroadcastScreenState: MockScreenState, CaseIterable {
// A case for each state you want to represent
// with specific, minimal associated data that will allow you
// mock that screen.
case animated
/// The associated screen
var screenType: Any.Type {
TimelineVoiceBroadcastView.self
}
/// A list of screen state definitions
static var allCases: [MockTimelineVoiceBroadcastScreenState] {
[.animated]
}
/// Generate the view struct for the screen state.
var screenView: ([Any], AnyView) {
let voiceBroadcast = TimelineVoiceBroadcastDetails(closed: false, type: TimelineVoiceBroadcastType.disclosed)
let viewModel = TimelineVoiceBroadcastViewModel(timelineVoiceBroadcastDetails: voiceBroadcast)
return (
[false, viewModel],
AnyView(TimelineVoiceBroadcastView(viewModel: viewModel.context))
)
}
}
@@ -20,13 +20,14 @@ import SwiftUI
typealias TimelineVoiceBroadcastViewModelType = StateStoreViewModel<TimelineVoiceBroadcastViewState, TimelineVoiceBroadcastViewAction>
class TimelineVoiceBroadcastViewModel: TimelineVoiceBroadcastViewModelType, TimelineVoiceBroadcastViewModelProtocol {
// MARK: - Properties
// MARK: Private
// MARK: Public
var completion: TimelineVoiceBroadcastViewModelCallback?
var completion: ((TimelineVoiceBroadcastViewModelResult) -> Void)?
// MARK: - Setup
@@ -37,7 +38,22 @@ class TimelineVoiceBroadcastViewModel: TimelineVoiceBroadcastViewModelType, Time
// MARK: - Public
override func process(viewAction: TimelineVoiceBroadcastViewAction) {
// TODO: add some actions as play pause
switch viewAction {
case .play:
play()
case .pause:
pause()
}
}
/// Listen voice broadcast
private func play() {
completion?(.played)
}
/// Stop voice broadcast
private func pause() {
completion?(.paused)
}
// MARK: - TimelineVoiceBroadcastViewModelProtocol
@@ -18,7 +18,7 @@ import Foundation
protocol TimelineVoiceBroadcastViewModelProtocol {
var context: TimelineVoiceBroadcastViewModelType.Context { get }
var completion: (() -> Void)? { get set }
var completion: ((TimelineVoiceBroadcastViewModelResult) -> Void)? { get set }
func updateWithVoiceBroadcastDetails(_ voiceBroadcastDetails: TimelineVoiceBroadcastDetails)
}
@@ -34,9 +34,25 @@ struct TimelineVoiceBroadcastView: View {
Text(VectorL10n.voiceBroadcastInTimelineTitle)
.font(theme.fonts.bodySB)
.foregroundColor(theme.colors.primaryContent)
Text(VectorL10n.voiceBroadcastInTimelineBody)
.font(theme.fonts.body)
.foregroundColor(theme.colors.primaryContent)
// Text(VectorL10n.voiceBroadcastInTimelineBody)
// .font(theme.fonts.body)
// .foregroundColor(theme.colors.primaryContent)
HStack(alignment: .top, spacing: 16.0) {
Button { viewModel.send(viewAction: .play) } label: {
Image("voice_broadcast_play")
.renderingMode(.original)
}
.accessibilityIdentifier("playButton")
Button { viewModel.send(viewAction: .pause) } label: {
Image("voice_broadcast_pause")
.renderingMode(.original)
}
.accessibilityIdentifier("pauseButton")
}
}
.padding([.horizontal, .top], 2.0)
.padding([.bottom])
@@ -48,4 +64,9 @@ struct TimelineVoiceBroadcastView: View {
// MARK: - Previews
// TODO: Add Voice broadcast preview
struct TimelineVoiceBroadcastView_Previews: PreviewProvider {
static let stateRenderer = MockTimelineVoiceBroadcastScreenState.stateRenderer
static var previews: some View {
stateRenderer.screenGroup()
}
}