mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 02:58:07 +00:00
Add recording player
This commit is contained in:
parent
b462657a77
commit
221e3cbb4b
8 changed files with 421 additions and 47 deletions
21
Linphone/Assets.xcassets/music-notes.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/music-notes.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "music-notes.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/music-notes.imageset/music-notes.svg
vendored
Normal file
1
Linphone/Assets.xcassets/music-notes.imageset/music-notes.svg
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="180" cy="164" r="28" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><circle cx="52" cy="196" r="28" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="208" y1="72" x2="80" y2="104" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><polyline points="80 196 80 56 208 24 208 164" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></svg>
|
||||
|
After Width: | Height: | Size: 664 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M176,160a39.89,39.89,0,0,0-28.62,12.09l-46.1-29.63a39.8,39.8,0,0,0,0-28.92l46.1-29.63a40,40,0,1,0-8.66-13.45l-46.1,29.63a40,40,0,1,0,0,55.82l46.1,29.63A40,40,0,1,0,176,160Zm0-128a24,24,0,1,1-24,24A24,24,0,0,1,176,32ZM64,152a24,24,0,1,1,24-24A24,24,0,0,1,64,152Zm112,72a24,24,0,1,1,24-24A24,24,0,0,1,176,224Z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M176,160a39.89,39.89,0,0,0-28.62,12.09l-46.1-29.63a39.8,39.8,0,0,0,0-28.92l46.1-29.63a40,40,0,1,0-8.66-13.45l-46.1,29.63a40,40,0,1,0,0,55.82l46.1,29.63A40,40,0,1,0,176,160Zm0-128a24,24,0,1,1-24,24A24,24,0,0,1,176,32ZM64,152a24,24,0,1,1,24-24A24,24,0,0,1,64,152Zm112,72a24,24,0,1,1,24-24A24,24,0,0,1,176,224Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 431 B After Width: | Height: | Size: 431 B |
|
|
@ -86,13 +86,3 @@ final class CustomHostingController<Content: View>: UIHostingController<Content>
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct LazyView<Content: View>: View {
|
||||
private let build: () -> Content
|
||||
public init(_ build: @autoclosure @escaping () -> Content) {
|
||||
self.build = build
|
||||
}
|
||||
public var body: Content {
|
||||
build()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-iphone
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct RecordingMediaPlayerFragment: View {
|
||||
|
||||
@StateObject private var recordingMediaPlayerViewModel: RecordingMediaPlayerViewModel
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@State private var showShareSheet: Bool = false
|
||||
@State private var showPicker: Bool = false
|
||||
@State private var value: Double = 40.0
|
||||
@State private var timer: Timer?
|
||||
|
||||
init(recording: RecordingModel) {
|
||||
_recordingMediaPlayerViewModel = StateObject(wrappedValue: RecordingMediaPlayerViewModel(recording: recording))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
GeometryReader { geometry in
|
||||
VStack(spacing: 1) {
|
||||
Rectangle()
|
||||
.foregroundColor(Color.orangeMain500)
|
||||
.edgesIgnoringSafeArea(.top)
|
||||
.frame(height: 0)
|
||||
|
||||
HStack {
|
||||
Image("caret-left")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
.padding(.top, 4)
|
||||
.padding(.leading, -10)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
VStack {
|
||||
Text(recordingMediaPlayerViewModel.recording.displayName)
|
||||
.default_text_style_700(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(recordingMediaPlayerViewModel.recording.dateTime)
|
||||
.default_text_style_300(styleSize: 12)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.padding(.top, 4)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
showShareSheet = true
|
||||
} label: {
|
||||
Image("share-network")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
}
|
||||
.padding(.all, 6)
|
||||
.padding(.top, 4)
|
||||
|
||||
|
||||
Button {
|
||||
showPicker = true
|
||||
} label: {
|
||||
Image("download-simple")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
}
|
||||
.padding(.all, 6)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 50)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 4)
|
||||
.background(.white)
|
||||
|
||||
VStack {
|
||||
Spacer()
|
||||
|
||||
Image("music-notes")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 80, height: 80)
|
||||
.foregroundStyle(.white)
|
||||
|
||||
Spacer()
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Button {
|
||||
if recordingMediaPlayerViewModel.isPlaying {
|
||||
recordingMediaPlayerViewModel.pauseVoiceRecordPlayer()
|
||||
} else {
|
||||
recordingMediaPlayerViewModel.startVoiceRecordPlayer()
|
||||
playProgress()
|
||||
}
|
||||
} label: {
|
||||
Image(recordingMediaPlayerViewModel.isPlaying ? "pause-fill" : "play-fill")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
.foregroundStyle(.white)
|
||||
}
|
||||
.frame(width: 50)
|
||||
|
||||
let radius = geometry.size.height * 0.5
|
||||
ZStack(alignment: .leading) {
|
||||
Rectangle()
|
||||
.foregroundColor(Color.orangeMain100)
|
||||
.frame(width: (geometry.size.width - 120), height: 5)
|
||||
.clipShape(RoundedRectangle(cornerRadius: radius))
|
||||
|
||||
Rectangle()
|
||||
.foregroundColor(Color.orangeMain500)
|
||||
.frame(width: self.value * (geometry.size.width - 120) / 100, height: 5)
|
||||
.animation(self.value > 0 ? .linear(duration: 0.1) : nil, value: self.value)
|
||||
.clipShape(RoundedRectangle(cornerRadius: radius))
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: radius))
|
||||
|
||||
Text(recordingMediaPlayerViewModel.recording.formattedDuration)
|
||||
.default_text_style_white_600(styleSize: 18)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.lineLimit(1)
|
||||
.frame(width: 70)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(.black)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showShareSheet) {
|
||||
if let url = URL(string: "file://" + recordingMediaPlayerViewModel.recording.filePath) {
|
||||
ShareAnySheet(items: [url])
|
||||
.edgesIgnoringSafeArea(.bottom)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showPicker) {
|
||||
if let url = URL(string: "file://" + recordingMediaPlayerViewModel.recording.filePath) {
|
||||
DocumentSaver(fileURL: url)
|
||||
.edgesIgnoringSafeArea(.bottom)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
playProgress()
|
||||
}
|
||||
.onDisappear {
|
||||
recordingMediaPlayerViewModel.stopVoiceRecordPlayer()
|
||||
}
|
||||
}
|
||||
.navigationTitle("")
|
||||
.navigationBarHidden(true)
|
||||
}
|
||||
|
||||
private func playProgress() {
|
||||
timer?.invalidate()
|
||||
|
||||
var lastValue = -1.0
|
||||
|
||||
value = recordingMediaPlayerViewModel.getPositionVoiceRecordPlayer()
|
||||
|
||||
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
|
||||
let current = recordingMediaPlayerViewModel.getPositionVoiceRecordPlayer()
|
||||
|
||||
if !recordingMediaPlayerViewModel.isPlaying {
|
||||
self.value = current
|
||||
lastValue = current
|
||||
return
|
||||
}
|
||||
|
||||
if current > lastValue {
|
||||
self.value = current
|
||||
lastValue = current
|
||||
return
|
||||
}
|
||||
|
||||
recordingMediaPlayerViewModel.stopVoiceRecordPlayer()
|
||||
self.timer?.invalidate()
|
||||
self.value = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SaveToFilesView: View {
|
||||
let fileURL: URL
|
||||
@State private var showPicker = false
|
||||
|
||||
var body: some View {
|
||||
Button("Enregistrer dans Fichiers") {
|
||||
showPicker = true
|
||||
}
|
||||
.sheet(isPresented: $showPicker) {
|
||||
DocumentSaver(fileURL: fileURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DocumentSaver: UIViewControllerRepresentable {
|
||||
let fileURL: URL
|
||||
|
||||
func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
|
||||
let picker = UIDocumentPickerViewController(
|
||||
forExporting: [fileURL], asCopy: true
|
||||
)
|
||||
return picker
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}
|
||||
}
|
||||
|
|
@ -72,48 +72,52 @@ struct RecordingsListFragment: View {
|
|||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
HStack {
|
||||
VStack {
|
||||
HStack {
|
||||
Image("phone")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
NavigationLink(destination: LazyView {
|
||||
RecordingMediaPlayerFragment(recording: recording)
|
||||
}) {
|
||||
HStack {
|
||||
VStack {
|
||||
HStack {
|
||||
Image("phone")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
|
||||
Text(recording.displayName)
|
||||
.default_text_style_700(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
Text(recording.displayName)
|
||||
.default_text_style_700(styleSize: 14)
|
||||
Spacer()
|
||||
|
||||
Text(recording.dateTime)
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(recording.dateTime)
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
VStack {
|
||||
Image("play-fill")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 30, height: 30)
|
||||
.padding(.leading, -6)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(recording.formattedDuration)
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(alignment: .center)
|
||||
}
|
||||
.padding(.trailing, 6)
|
||||
}
|
||||
|
||||
VStack {
|
||||
Image("play-fill")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 30, height: 30)
|
||||
.padding(.leading, -6)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(recording.formattedDuration)
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(alignment: .center)
|
||||
}
|
||||
.padding(.trailing, 6)
|
||||
.frame(height: 60)
|
||||
.padding(20)
|
||||
.background(.white)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.shadow(color: .gray.opacity(0.4), radius: 4)
|
||||
}
|
||||
.frame(height: 60)
|
||||
.padding(20)
|
||||
.background(.white)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.shadow(color: .gray.opacity(0.4), radius: 4)
|
||||
}
|
||||
}
|
||||
.padding(.all, 20)
|
||||
|
|
@ -140,3 +144,11 @@ struct RecordingsListFragment: View {
|
|||
.default_text_style_500(styleSize: 22)
|
||||
}
|
||||
}
|
||||
|
||||
struct LazyView<Content: View>: View {
|
||||
let build: () -> Content
|
||||
init(_ build: @escaping () -> Content) {
|
||||
self.build = build
|
||||
}
|
||||
var body: some View { build() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-iphone
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
class RecordingMediaPlayerViewModel: ObservableObject {
|
||||
private let TAG = "[RecordingMediaPlayerViewModel]"
|
||||
|
||||
private var coreContext = CoreContext.shared
|
||||
|
||||
@Published var recording: RecordingModel
|
||||
|
||||
@Published var isPlaying: Bool = false
|
||||
|
||||
var vrpManager: VoiceRecordPlayerManager?
|
||||
|
||||
init(recording: RecordingModel) {
|
||||
self.recording = recording
|
||||
if let url = URL(string: "file://" + recording.filePath) {
|
||||
startVoiceRecordPlayer(voiceRecordPath: url)
|
||||
}
|
||||
}
|
||||
|
||||
func startVoiceRecordPlayer(voiceRecordPath: URL) {
|
||||
coreContext.doOnCoreQueue { core in
|
||||
if self.vrpManager == nil || self.vrpManager!.voiceRecordPath != voiceRecordPath {
|
||||
self.vrpManager = VoiceRecordPlayerManager(core: core, voiceRecordPath: voiceRecordPath)
|
||||
}
|
||||
|
||||
if self.vrpManager != nil {
|
||||
self.vrpManager!.startVoiceRecordPlayer()
|
||||
DispatchQueue.main.async {
|
||||
self.isPlaying = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getPositionVoiceRecordPlayer() -> Double {
|
||||
if self.vrpManager != nil {
|
||||
return self.vrpManager!.positionVoiceRecordPlayer()
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func isPlayingVoiceRecordPlayer(voiceRecordPath: URL) -> Bool {
|
||||
if self.vrpManager != nil && self.vrpManager!.voiceRecordPath == voiceRecordPath {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func startVoiceRecordPlayer() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.vrpManager != nil {
|
||||
self.vrpManager!.startVoiceRecordPlayer()
|
||||
DispatchQueue.main.async {
|
||||
self.isPlaying = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pauseVoiceRecordPlayer() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.vrpManager != nil {
|
||||
self.vrpManager!.pauseVoiceRecordPlayer()
|
||||
DispatchQueue.main.async {
|
||||
self.isPlaying = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stopVoiceRecordPlayer() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.vrpManager != nil {
|
||||
self.vrpManager!.stopVoiceRecordPlayer()
|
||||
DispatchQueue.main.async {
|
||||
self.isPlaying = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,6 +178,8 @@
|
|||
D7CEE03B2B7A234200FD79B7 /* ConversationsFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CEE03A2B7A234200FD79B7 /* ConversationsFragment.swift */; };
|
||||
D7CEE03D2B7A23B200FD79B7 /* ConversationsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CEE03C2B7A23B200FD79B7 /* ConversationsListFragment.swift */; };
|
||||
D7D1698C2AE66FA500109A5C /* MagicSearchSingleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D1698B2AE66FA500109A5C /* MagicSearchSingleton.swift */; };
|
||||
D7D1F5262EDD91B30034EEB0 /* RecordingMediaPlayerFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D1F5252EDD91B10034EEB0 /* RecordingMediaPlayerFragment.swift */; };
|
||||
D7D1F5282EDD939E0034EEB0 /* RecordingMediaPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D1F5272EDD939D0034EEB0 /* RecordingMediaPlayerViewModel.swift */; };
|
||||
D7D24D132AC1B4E800C6F35B /* NotoSans-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D7D24D0D2AC1B4E800C6F35B /* NotoSans-Medium.ttf */; };
|
||||
D7D24D142AC1B4E800C6F35B /* NotoSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D7D24D0E2AC1B4E800C6F35B /* NotoSans-Regular.ttf */; };
|
||||
D7D24D152AC1B4E800C6F35B /* NotoSans-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D7D24D0F2AC1B4E800C6F35B /* NotoSans-Light.ttf */; };
|
||||
|
|
@ -414,6 +416,8 @@
|
|||
D7CEE03A2B7A234200FD79B7 /* ConversationsFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationsFragment.swift; sourceTree = "<group>"; };
|
||||
D7CEE03C2B7A23B200FD79B7 /* ConversationsListFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationsListFragment.swift; sourceTree = "<group>"; };
|
||||
D7D1698B2AE66FA500109A5C /* MagicSearchSingleton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicSearchSingleton.swift; sourceTree = "<group>"; };
|
||||
D7D1F5252EDD91B10034EEB0 /* RecordingMediaPlayerFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingMediaPlayerFragment.swift; sourceTree = "<group>"; };
|
||||
D7D1F5272EDD939D0034EEB0 /* RecordingMediaPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingMediaPlayerViewModel.swift; sourceTree = "<group>"; };
|
||||
D7D24D0D2AC1B4E800C6F35B /* NotoSans-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSans-Medium.ttf"; sourceTree = "<group>"; };
|
||||
D7D24D0E2AC1B4E800C6F35B /* NotoSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSans-Regular.ttf"; sourceTree = "<group>"; };
|
||||
D7D24D0F2AC1B4E800C6F35B /* NotoSans-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSans-Light.ttf"; sourceTree = "<group>"; };
|
||||
|
|
@ -915,6 +919,7 @@
|
|||
D795F57B2EC5F8FF0022C17D /* Fragments */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D7D1F5252EDD91B10034EEB0 /* RecordingMediaPlayerFragment.swift */,
|
||||
D795F57D2EC5F9480022C17D /* RecordingsListFragment.swift */,
|
||||
);
|
||||
path = Fragments;
|
||||
|
|
@ -923,6 +928,7 @@
|
|||
D795F57C2EC5F9090022C17D /* ViewModel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D7D1F5272EDD939D0034EEB0 /* RecordingMediaPlayerViewModel.swift */,
|
||||
D795F57F2EC5F95B0022C17D /* RecordingsListViewModel.swift */,
|
||||
);
|
||||
path = ViewModel;
|
||||
|
|
@ -1344,6 +1350,7 @@
|
|||
D7C2DA1D2CA44DE400A2441B /* EventModel.swift in Sources */,
|
||||
D719ABC92ABC6FD700B41C10 /* CoreContext.swift in Sources */,
|
||||
D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */,
|
||||
D7D1F5282EDD939E0034EEB0 /* RecordingMediaPlayerViewModel.swift in Sources */,
|
||||
D7DC096F2CFA1D7600A6D47C /* AccountProfileFragment.swift in Sources */,
|
||||
D717A10E2CEB772300849D92 /* ShareSheetController.swift in Sources */,
|
||||
66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */,
|
||||
|
|
@ -1367,6 +1374,7 @@
|
|||
C6A5A9452C10B6270070FEA4 /* OIDAuthStateExtension.swift in Sources */,
|
||||
D732A90F2B04C3B400DB42BA /* HistoryFragment.swift in Sources */,
|
||||
D79F1C162CD3D6AD00FF0A05 /* ConversationInfoFragment.swift in Sources */,
|
||||
D7D1F5262EDD91B30034EEB0 /* RecordingMediaPlayerFragment.swift in Sources */,
|
||||
D7C500422D2BE98100DD53EC /* AccountSettingsViewModel.swift in Sources */,
|
||||
D79622342B1DFE600037EACD /* DialerBottomSheet.swift in Sources */,
|
||||
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue