137 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Swift
		
	
	
	
		
		
			
		
	
	
			137 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Swift
		
	
	
	
|  | // | ||
|  | //  SpeechManager.swift | ||
|  | //  Crush | ||
|  | // | ||
|  | //  Created by Leon on 2025/8/1. | ||
|  | // | ||
|  | 
 | ||
|  | import Foundation | ||
|  | 
 | ||
|  | class SpeechManager { | ||
|  |     // MARK: - Properties | ||
|  |     static let shared = SpeechManager() | ||
|  |     private weak var currentModel: SpeechModel? | ||
|  |     private var timer: TimerModel? | ||
|  |     private var timerCount: Int = 0 | ||
|  |      | ||
|  |     private init() {} | ||
|  |      | ||
|  |     // MARK: - Private Methods | ||
|  |     private func model(withPath path: String) -> SpeechModel { | ||
|  |         let model = SpeechModel() | ||
|  |         model.path = path | ||
|  |         return model | ||
|  |     } | ||
|  |      | ||
|  |     private func timerAction() { | ||
|  |         timerCount -= 1 | ||
|  |         DispatchQueue.main.async {[weak self] in | ||
|  |             guard let `self` = self else { | ||
|  |                 return | ||
|  |             } | ||
|  |             currentModel?.timerChangedBlock?(TimeInterval(timerCount/10)) | ||
|  |         } | ||
|  |         if let model = currentModel, model.isPlaying { | ||
|  |             if timerCount <= 0 { | ||
|  |                 stopPlay(with: model) | ||
|  |             } | ||
|  |         } else { | ||
|  |             timer?.pauseTimer() | ||
|  |         } | ||
|  |         if timerCount < -10000 { | ||
|  |             timerCount = 0 | ||
|  |         } | ||
|  |         //dlog("SpeechManager timerAction___\(timerCount)") | ||
|  |     } | ||
|  |      | ||
|  |     // MARK: - Lazy Timer | ||
|  |     private var timerInstance: TimerModel { | ||
|  |         if timer == nil { | ||
|  |             timer = TimerModel() | ||
|  |             timer?.timerBlock = { [weak self] in | ||
|  |                 self?.timerAction() | ||
|  |             } | ||
|  |         } | ||
|  |         return timer! | ||
|  |     } | ||
|  |      | ||
|  |     // MARK: - Public Methods | ||
|  |     static func checkVoiceState() -> Bool { | ||
|  |         // 🔥 Assuming PhoneManager and ChatRoomRoute are external dependencies | ||
|  |         if PhoneManager.isInPhoneChannel() || ChatRoomRoute.isChatRoomOpen() { | ||
|  |             UIWindow.key?.makeToast("toast_voice_channel_is_occupied") | ||
|  |             dlog("toast_voice_channel_is_occupied") | ||
|  |             return false | ||
|  |         } | ||
|  |         return true | ||
|  |     } | ||
|  |      | ||
|  |     func modelWithFilePath(_ path: String) -> SpeechModel { | ||
|  |         let model = model(withPath: path) | ||
|  |         model.fileType = .file | ||
|  |         return model | ||
|  |     } | ||
|  |      | ||
|  |     func modelWithFileUrl(_ url: String) -> SpeechModel { | ||
|  |         let model = model(withPath: url) | ||
|  |         model.fileType = .url | ||
|  |         return model | ||
|  |     } | ||
|  |      | ||
|  |     func modelWithBase64String(_ base64String: String) -> SpeechModel { | ||
|  |         let model = model(withPath: base64String) | ||
|  |         model.fileType = .base64 | ||
|  |         return model | ||
|  |     } | ||
|  |      | ||
|  |     func startPlay(with model: SpeechModel) { | ||
|  |         guard model.loadState != .loading else { return } | ||
|  |          | ||
|  |         if currentModel === model { | ||
|  |             if currentModel?.isPlaying == true { | ||
|  |                 currentModel?.stopPlay() | ||
|  |                 return | ||
|  |             } | ||
|  |         } | ||
|  |          | ||
|  |         if let current = currentModel { | ||
|  |             stopPlay(with: current) | ||
|  |         } | ||
|  |          | ||
|  |         model.canAutoPlay = true | ||
|  |         if model.needLoadData() { | ||
|  |             model.loadSpeechFile() | ||
|  |             currentModel = model | ||
|  |         } else { | ||
|  |             currentModel = model | ||
|  |             timerCount = model.audioTime | ||
|  |             model.startPlay() | ||
|  |             timerInstance.startTimer() | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     func stopPlay(with model: SpeechModel) { | ||
|  |         model.canAutoPlay = false | ||
|  |         // model.stateChangedBlock = nil | ||
|  |         model.stopPlay() | ||
|  |         if model === currentModel { | ||
|  |             timerInstance.pauseTimer() | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     func stopPlayCurrent() { | ||
|  |         if let model = currentModel { | ||
|  |             stopPlay(with: model) | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | // 🔥 Placeholder for external dependencies | ||
|  | class PhoneManager { | ||
|  |     static func isInPhoneChannel() -> Bool { return false } // 🔥 Placeholder | ||
|  | } | ||
|  | 
 | ||
|  | class ChatRoomRoute { | ||
|  |     static func isChatRoomOpen() -> Bool { return false } // 🔥 Placeholder | ||
|  | } |