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)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack {
|
NavigationLink(destination: LazyView {
|
||||||
VStack {
|
RecordingMediaPlayerFragment(recording: recording)
|
||||||
HStack {
|
}) {
|
||||||
Image("phone")
|
HStack {
|
||||||
.renderingMode(.template)
|
VStack {
|
||||||
.resizable()
|
HStack {
|
||||||
.frame(width: 25, height: 25)
|
Image("phone")
|
||||||
.foregroundStyle(Color.grayMain2c600)
|
.renderingMode(.template)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 25, height: 25)
|
||||||
|
.foregroundStyle(Color.grayMain2c600)
|
||||||
|
|
||||||
Text(recording.displayName)
|
Text(recording.displayName)
|
||||||
.default_text_style_700(styleSize: 14)
|
.default_text_style_700(styleSize: 14)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text(recording.dateTime)
|
||||||
|
.default_text_style(styleSize: 14)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
VStack {
|
||||||
|
Image("play-fill")
|
||||||
|
.renderingMode(.template)
|
||||||
|
.resizable()
|
||||||
|
.foregroundStyle(Color.orangeMain500)
|
||||||
|
.frame(width: 30, height: 30)
|
||||||
|
.padding(.leading, -6)
|
||||||
|
|
||||||
Text(recording.dateTime)
|
Spacer()
|
||||||
.default_text_style(styleSize: 14)
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
Text(recording.formattedDuration)
|
||||||
|
.default_text_style(styleSize: 14)
|
||||||
|
.frame(alignment: .center)
|
||||||
|
}
|
||||||
|
.padding(.trailing, 6)
|
||||||
}
|
}
|
||||||
|
.frame(height: 60)
|
||||||
VStack {
|
.padding(20)
|
||||||
Image("play-fill")
|
.background(.white)
|
||||||
.renderingMode(.template)
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
.resizable()
|
.shadow(color: .gray.opacity(0.4), radius: 4)
|
||||||
.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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.all, 20)
|
.padding(.all, 20)
|
||||||
|
|
@ -140,3 +144,11 @@ struct RecordingsListFragment: View {
|
||||||
.default_text_style_500(styleSize: 22)
|
.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 */; };
|
D7CEE03B2B7A234200FD79B7 /* ConversationsFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CEE03A2B7A234200FD79B7 /* ConversationsFragment.swift */; };
|
||||||
D7CEE03D2B7A23B200FD79B7 /* ConversationsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CEE03C2B7A23B200FD79B7 /* ConversationsListFragment.swift */; };
|
D7CEE03D2B7A23B200FD79B7 /* ConversationsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7CEE03C2B7A23B200FD79B7 /* ConversationsListFragment.swift */; };
|
||||||
D7D1698C2AE66FA500109A5C /* MagicSearchSingleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D1698B2AE66FA500109A5C /* MagicSearchSingleton.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 */; };
|
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 */; };
|
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 */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
D7D24D0F2AC1B4E800C6F35B /* NotoSans-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSans-Light.ttf"; sourceTree = "<group>"; };
|
||||||
|
|
@ -915,6 +919,7 @@
|
||||||
D795F57B2EC5F8FF0022C17D /* Fragments */ = {
|
D795F57B2EC5F8FF0022C17D /* Fragments */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D7D1F5252EDD91B10034EEB0 /* RecordingMediaPlayerFragment.swift */,
|
||||||
D795F57D2EC5F9480022C17D /* RecordingsListFragment.swift */,
|
D795F57D2EC5F9480022C17D /* RecordingsListFragment.swift */,
|
||||||
);
|
);
|
||||||
path = Fragments;
|
path = Fragments;
|
||||||
|
|
@ -923,6 +928,7 @@
|
||||||
D795F57C2EC5F9090022C17D /* ViewModel */ = {
|
D795F57C2EC5F9090022C17D /* ViewModel */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D7D1F5272EDD939D0034EEB0 /* RecordingMediaPlayerViewModel.swift */,
|
||||||
D795F57F2EC5F95B0022C17D /* RecordingsListViewModel.swift */,
|
D795F57F2EC5F95B0022C17D /* RecordingsListViewModel.swift */,
|
||||||
);
|
);
|
||||||
path = ViewModel;
|
path = ViewModel;
|
||||||
|
|
@ -1344,6 +1350,7 @@
|
||||||
D7C2DA1D2CA44DE400A2441B /* EventModel.swift in Sources */,
|
D7C2DA1D2CA44DE400A2441B /* EventModel.swift in Sources */,
|
||||||
D719ABC92ABC6FD700B41C10 /* CoreContext.swift in Sources */,
|
D719ABC92ABC6FD700B41C10 /* CoreContext.swift in Sources */,
|
||||||
D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */,
|
D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */,
|
||||||
|
D7D1F5282EDD939E0034EEB0 /* RecordingMediaPlayerViewModel.swift in Sources */,
|
||||||
D7DC096F2CFA1D7600A6D47C /* AccountProfileFragment.swift in Sources */,
|
D7DC096F2CFA1D7600A6D47C /* AccountProfileFragment.swift in Sources */,
|
||||||
D717A10E2CEB772300849D92 /* ShareSheetController.swift in Sources */,
|
D717A10E2CEB772300849D92 /* ShareSheetController.swift in Sources */,
|
||||||
66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */,
|
66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */,
|
||||||
|
|
@ -1367,6 +1374,7 @@
|
||||||
C6A5A9452C10B6270070FEA4 /* OIDAuthStateExtension.swift in Sources */,
|
C6A5A9452C10B6270070FEA4 /* OIDAuthStateExtension.swift in Sources */,
|
||||||
D732A90F2B04C3B400DB42BA /* HistoryFragment.swift in Sources */,
|
D732A90F2B04C3B400DB42BA /* HistoryFragment.swift in Sources */,
|
||||||
D79F1C162CD3D6AD00FF0A05 /* ConversationInfoFragment.swift in Sources */,
|
D79F1C162CD3D6AD00FF0A05 /* ConversationInfoFragment.swift in Sources */,
|
||||||
|
D7D1F5262EDD91B30034EEB0 /* RecordingMediaPlayerFragment.swift in Sources */,
|
||||||
D7C500422D2BE98100DD53EC /* AccountSettingsViewModel.swift in Sources */,
|
D7C500422D2BE98100DD53EC /* AccountSettingsViewModel.swift in Sources */,
|
||||||
D79622342B1DFE600037EACD /* DialerBottomSheet.swift in Sources */,
|
D79622342B1DFE600037EACD /* DialerBottomSheet.swift in Sources */,
|
||||||
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */,
|
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue