Skip to content

Commit

Permalink
Merge branch 'release/1.13.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
dhekra-rouatbi committed Jan 6, 2025
2 parents d143525 + 585d29c commit 482a497
Show file tree
Hide file tree
Showing 44 changed files with 1,364 additions and 284 deletions.
55 changes: 47 additions & 8 deletions Tella.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions Tella/Components/CustomThumbnailSlider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// CustomThumbnailSlider.swift
// Tella
//
// Created by RIMA on 15.11.24.
// Copyright © 2024 HORIZONTAL. All rights reserved.
//

import SwiftUI

struct CustomThumbnailSlider: View {

//MARK: - Private Attributes
@State private var isEditing = false
private let kOffset = 3.0

@Binding var value: Double
var range: ClosedRange<Double>

var sliderHeight = 200.0
var sliderWidth = 10.0
var sliderImage: String

var onEditingChanged: ((Bool) -> Void)?

var body: some View {
GeometryReader { geometry in
sliderImage(in: geometry)
.gesture(dragGesture(in: geometry))
}
}

// Extract slider image view with offset calculation
private func sliderImage(in geometry: GeometryProxy) -> some View {
ResizableImage(sliderImage)
.frame(width: sliderWidth)
.offset(x: calculateThumbOffset(in: geometry), y: -10)
}
// Drag gesture with adjusted conditions for limit scrolling
private func dragGesture(in geometry: GeometryProxy) -> some Gesture {
DragGesture(minimumDistance: 0)
.onChanged { dragValue in
let newValue = Double(dragValue.location.x / geometry.size.width) * (range.upperBound - range.lowerBound) + range.lowerBound
value = min(max(newValue, range.lowerBound), range.upperBound)
}
.onEnded { _ in
if isEditing {
onEditingChanged?(false) // Call closure when editing ends
isEditing = false
}
}
.onChanged { _ in
if !isEditing {
onEditingChanged?(true) // Call closure when editing starts
isEditing = true
}
}
}
// Calculate the offset for the thumb
private func calculateThumbOffset(in geometry: GeometryProxy) -> CGFloat {
CGFloat((value - range.lowerBound) / (range.upperBound - range.lowerBound)) * geometry.size.width - kOffset
}

}


23 changes: 23 additions & 0 deletions Tella/Components/ResizableImage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// ResizableImage.swift
// Tella
//
// Created by RIMA on 14.11.24.
// Copyright © 2024 HORIZONTAL. All rights reserved.
//

import SwiftUI

struct ResizableImage: View {
var name: String

init(_ name: String) {
self.name = name
}

var body: some View {
Image(name)
.resizable()
}
}

1 change: 1 addition & 0 deletions Tella/Domain/Entity/ImportedFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ enum FileSource {
enum FileExtension : String {
case heic = "heic"
case mov = "mov"
case mp4 = "mp4"
}
24 changes: 23 additions & 1 deletion Tella/Domain/Entity/Report/Vault/VaultFileDB.swift
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,30 @@ extension Array where Element == Dictionary<String,Any>{
}
}
extension VaultFileDB {
var audioCanBeEdited: Bool {
var mediaCanBeEdited: Bool {
let minimumAudioDuration = 3.9
return duration ?? 0.0 >= minimumAudioDuration
}
}
extension VaultFileDB {
func getCopyName(from vaultFilesManager: VaultFilesManager?) -> String {

var baseName: String
var copyNumber = 0

// Check if the current name already has the "copy" suffix
if name.hasSuffix(LocalizableVault.copy.localized) {
baseName = name
} else {
baseName = name + LocalizableVault.copy.localized
}

// Generate the new filename and check if it exists
var newFileName = baseName
while vaultFilesManager?.vaultFileExists(name: newFileName) == true {
copyNumber += 1
newFileName = baseName + "-" + "\(copyNumber)"
}
return newFileName
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "edit.video.left.icon.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "edit.video.play.line.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "edit.video.right.icon.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
126 changes: 11 additions & 115 deletions Tella/Scenes/Audio/AudioPlayer/ViewModel/EditAudioViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,20 @@ import Foundation
import AVFoundation
import SwiftUI

class EditAudioViewModel: ObservableObject {
class EditAudioViewModel: EditMediaViewModel {

//MARK: - Published
@Published var startTime: Double = 0.0
@Published var endTime: Double = 0.0
@Published var timeDuration: Double = 0.0
@Published var currentTime : String = "00:00:00"
@Published var playingOffset: CGFloat = 0.0
@Published var isPlaying = false
@Published var trimState: ViewModelState<Bool> = .loaded(false)

//MARK: - AudioPlayerManager
private var audioPlayerManager: AudioPlayerManager = AudioPlayerManager()

//MARK: - Private attributes
private var audioUrl: URL?
private var currentData : Data?

//MARK: - View attributes
let minimumAudioDuration = 3.9 // this is the limit time of the audio duration
var timeSlots: [String] = []
var playButtonImageName: String {
isPlaying ? "mic.pause-audio" : "mic.play"
}
var file: VaultFileDB?
var rootFile: VaultFileDB?
var appModel: MainAppModel

//MARK: - cancellable
var cancellable: Set<AnyCancellable> = []
var shouldReloadVaultFiles: Binding<Bool> // Should be changed soon

init(file: VaultFileDB?, rootFile: VaultFileDB?, appModel: MainAppModel, shouldReloadVaultFiles: Binding<Bool>) {
self.file = file
self.rootFile = rootFile
self.appModel = appModel
self.shouldReloadVaultFiles = shouldReloadVaultFiles
override init(file: VaultFileDB?, rootFile: VaultFileDB?, appModel: MainAppModel, shouldReloadVaultFiles: Binding<Bool>) {
super.init(file: file, rootFile: rootFile, appModel: appModel, shouldReloadVaultFiles: shouldReloadVaultFiles)
if let currentFile = file {
self.currentData = appModel.vaultManager.loadFileData(file: currentFile)
}

headerTitle = LocalizableVault.editAudioTitle.localized
loadAudio()
listenToAudioPlayerUpdates()
}
Expand All @@ -62,99 +35,29 @@ class EditAudioViewModel: ObservableObject {
self.timeDuration = self.audioPlayerManager.audioPlayer.duration
self.generateTimeLabels()
self.endTime = self.timeDuration

}
}

private func listenToAudioPlayerUpdates() {
self.audioPlayerManager.audioPlayer.currentTime.sink { value in
self.currentTime = value.formattedAsHHMMSS()
self.updateOffset(time: Double(value) )
}.store(in: &self.cancellable)

}.store(in: &self.cancellables)
self.audioPlayerManager.audioPlayer.audioPlayerDidFinishPlaying.sink { [self] value in
isPlaying = false
}.store(in: &self.cancellable)
}

func onAppear() {
guard let fileExtension = file?.fileExtension else { return }
let url = appModel.vaultManager.saveDataToTempFile(data: currentData, pathExtension: fileExtension)
guard let url else { return }

self.audioUrl = url
}

func onDisappear() {
self.onPause()
}

func isDurationHasChanged() -> Bool {
return self.endTime != self.timeDuration || self.startTime != 0.0
}

func trimAudio() {
Task {
do {
guard let trimmedAudioUrl = try await audioUrl?.trimAudio(newName: "\(newFileName).m4a", startTime: startTime, endTime: endTime) else { return }
self.addEditedFile(urlFile: trimmedAudioUrl)
} catch {
self.trimState = .error(error.localizedDescription)
}
}
}

var newFileName: String {

guard let name = file?.name else {
return ""
}

var baseName: String
var copyNumber = 0

// Check if the current name already has the "copy" suffix
if name.hasSuffix(LocalizableVault.copy.localized) {
baseName = name
} else {
baseName = name + LocalizableVault.copy.localized
}

// Generate the new filename and check if it exists
var newFileName = baseName
while appModel.vaultFilesManager?.vaultFileExists(name: newFileName) == true {
copyNumber += 1
newFileName = baseName + "-" + "\(copyNumber)"
}

return newFileName
}.store(in: &self.cancellables)
}

private func onPlay() {
override func onPlay() {
audioPlayerManager.playRecord()
}

private func onPause() {
override func onPause() {
audioPlayerManager.pauseRecord()
}

func handlePlayButton() {
isPlaying.toggle()
self.isPlaying ? onPlay() : onPause()
}

private func addEditedFile(urlFile:URL) {
let importedFiles = ImportedFile(urlFile: urlFile,
parentId: rootFile?.id ,
fileSource: FileSource.files)
appModel.addVaultFile(importedFiles: [importedFiles],
shouldReloadVaultFiles: shouldReloadVaultFiles)

DispatchQueue.main.async {
self.trimState = .loaded(true)
}
}

private func generateTimeLabels() {
if timeDuration != 0.0 {
let kNumberOfLabels = 5 // This is for the sub-times labels
Expand All @@ -168,11 +71,4 @@ class EditAudioViewModel: ObservableObject {
}
}

private func updateOffset(time: Double) {
let totalOffsetDistance: CGFloat = 340
let progress = time / timeDuration
if !progress.isNaN {
playingOffset = CGFloat(progress) * totalOffsetDistance
}
}
}
Loading

0 comments on commit 482a497

Please sign in to comment.