Improvement on player UI

main
Laurent 3 years ago
parent 1fac7ff50b
commit a7bb2cf906
  1. 12
      LeCountdown.xcodeproj/project.pbxproj
  2. 1
      LeCountdown/AppDelegate.swift
  3. 82
      LeCountdown/Sound/StatePlayer.swift
  4. 58
      LeCountdown/Subscription/StoreView.swift

@ -112,6 +112,11 @@
C4A16D8F29C4A5BA00143D5E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C4A16D8B29C4A5BA00143D5E /* GoogleService-Info.plist */; };
C4A16D9029C4A5BA00143D5E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C4A16D8B29C4A5BA00143D5E /* GoogleService-Info.plist */; };
C4A16D9329C4A6DD00143D5E /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = C4A16D9229C4A6DD00143D5E /* FirebaseCrashlytics */; };
C4A16D9529C4B06400143D5E /* StatePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A16D9429C4B06400143D5E /* StatePlayer.swift */; };
C4A16D9629C4B06400143D5E /* StatePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A16D9429C4B06400143D5E /* StatePlayer.swift */; };
C4A16D9729C4B06400143D5E /* StatePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A16D9429C4B06400143D5E /* StatePlayer.swift */; };
C4A16D9829C4B06400143D5E /* StatePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A16D9429C4B06400143D5E /* StatePlayer.swift */; };
C4A16D9929C4B06400143D5E /* StatePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A16D9429C4B06400143D5E /* StatePlayer.swift */; };
C4BA2AD62993F62700CB4FBA /* SoundSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AD52993F62700CB4FBA /* SoundSelectionView.swift */; };
C4BA2ADB299549BC00CB4FBA /* TimerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2ADA299549BC00CB4FBA /* TimerModel.swift */; };
C4BA2ADE2995ABA800CB4FBA /* MatriarchFxs_Loop2_Collider.wav in Resources */ = {isa = PBXBuildFile; fileRef = C4BA2ADD2995ABA800CB4FBA /* MatriarchFxs_Loop2_Collider.wav */; };
@ -367,6 +372,7 @@
C498E5A2298D720600E90DE0 /* TestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestView.swift; sourceTree = "<group>"; };
C498E5A4299152B400E90DE0 /* GreenCheckmarkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GreenCheckmarkView.swift; sourceTree = "<group>"; };
C4A16D8B29C4A5BA00143D5E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
C4A16D9429C4B06400143D5E /* StatePlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatePlayer.swift; sourceTree = "<group>"; };
C4BA2AD52993F62700CB4FBA /* SoundSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundSelectionView.swift; sourceTree = "<group>"; };
C4BA2AD72993F7D200CB4FBA /* LeCountdown.0.5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.5.xcdatamodel; sourceTree = "<group>"; };
C4BA2ADA299549BC00CB4FBA /* TimerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerModel.swift; sourceTree = "<group>"; };
@ -716,6 +722,7 @@
C445FA912987CC8A0054D761 /* Sound.swift */,
C445FA8E2987B83B0054D761 /* SoundPlayer.swift */,
C4E5D67329B88734008E7465 /* DelaySoundPlayer.swift */,
C4A16D9429C4B06400143D5E /* StatePlayer.swift */,
);
path = Sound;
sourceTree = "<group>";
@ -1186,6 +1193,7 @@
C4742B5B298414B000D5D950 /* ImageSelectionView.swift in Sources */,
C438C7C5298024E900BF3EF9 /* NSManagedContext+Extensions.swift in Sources */,
C4F8B15F298961A7005C86A5 /* ReorderableForEach.swift in Sources */,
C4A16D9529C4B06400143D5E /* StatePlayer.swift in Sources */,
C4BA2B6129A3C02400CB4FBA /* ActivityView.swift in Sources */,
C4BA2B6A29A4BE1800CB4FBA /* Date+Extensions.swift in Sources */,
C4BA2B10299BE61E00CB4FBA /* Interval+CoreDataProperties.swift in Sources */,
@ -1202,6 +1210,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C4A16D9629C4B06400143D5E /* StatePlayer.swift in Sources */,
C4060DD7297AE73D003FAB80 /* LeCountdownTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1211,6 +1220,7 @@
buildActionMask = 2147483647;
files = (
C4060DE1297AE73D003FAB80 /* LeCountdownUITests.swift in Sources */,
C4A16D9729C4B06400143D5E /* StatePlayer.swift in Sources */,
C4060DE3297AE73D003FAB80 /* LeCountdownUITestsLaunchTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1219,6 +1229,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C4A16D9829C4B06400143D5E /* StatePlayer.swift in Sources */,
C4BA2B15299BE6A000CB4FBA /* Interval+CoreDataProperties.swift in Sources */,
C498E5A6299152C600E90DE0 /* GreenCheckmarkView.swift in Sources */,
C4BA2B3B299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */,
@ -1289,6 +1300,7 @@
C438C81A2982BFF100BF3EF9 /* NSManagedContext+Extensions.swift in Sources */,
C4F8B19D298AC288005C86A5 /* AbstractTimer+CoreDataClass.swift in Sources */,
C4BA2B3C299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */,
C4A16D9929C4B06400143D5E /* StatePlayer.swift in Sources */,
C4BA2AF82996A4F000CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */,
C4F8B199298AC288005C86A5 /* Record+CoreDataClass.swift in Sources */,
C438C8012981327600BF3EF9 /* Persistence.swift in Sources */,

@ -59,7 +59,6 @@ class AppDelegate : NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if userActivity.interaction == nil {
Logger.log("restorationHandler called! interaction is nil")
return false
}

@ -0,0 +1,82 @@
//
// StatePlayer.swift
// LeCountdown
//
// Created by Laurent Morvillier on 17/03/2023.
//
import Foundation
import AVFoundation
enum DemoError: Error {
case didNotFindDemoFile
}
class StatePlayer: NSObject, ObservableObject, AVAudioPlayerDelegate {
enum State {
case noResource
case playing
case paused
case none
var systemImage: String {
switch self {
case .paused, .none: return "play.circle"
case .playing: return "pause.circle"
case .noResource: return ""
}
}
}
@Published var audioPlayer: AVAudioPlayer? = nil
@Published var state: State = .noResource
@Published var completion: Double? = nil
var timer: Timer? = nil
override init() {
super.init()
self.timer = Timer(timeInterval: 1.0, repeats: true, block: { timer in
self.calculateCompletion()
})
}
func load(resource: String, ext: String) {
do {
guard let demoURL = Bundle.main.url(forResource: resource, withExtension: ext) else {
throw DemoError.didNotFindDemoFile
}
self.audioPlayer = try AVAudioPlayer(contentsOf: demoURL)
self.audioPlayer?.delegate = self
self.state = .none
} catch {
Logger.error(error)
}
}
func calculateCompletion() {
if let player = self.audioPlayer {
self.completion = player.currentTime / player.duration
}
self.completion = nil
}
func play() {
self.audioPlayer?.play()
self.state = .playing
}
func pause() {
self.audioPlayer?.pause()
self.state = .paused
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
self.state = .none
}
}

@ -113,6 +113,8 @@ struct PlanView: View {
.padding(.vertical, 2.0)
Spacer()
PlayerWrapperView()
Button {
self.actionHandler()
@ -134,6 +136,62 @@ struct PlanView: View {
}
struct PlayerWrapperView: View {
@StateObject var player: StatePlayer = StatePlayer()
var body: some View {
let state = self.player.state
Group {
switch state {
case .none, .paused:
Button {
self._pause()
} label: {
HStack {
Image(systemName: state.systemImage)
Spacer()
ProgressView(value: self.player.completion)
}.font(.title)
}.buttonStyle(.borderedProminent)
.fontWeight(.medium)
case .playing:
Button {
self._pause()
} label: {
HStack {
Image(systemName: state.systemImage)
Spacer()
ProgressView(value: self.player.completion)
// Slider(value: self.$player.completion)
}.font(.title)
}.buttonStyle(.borderedProminent)
.fontWeight(.medium)
case .noResource:
EmptyView()
}
}
.onAppear {
self.player.load(resource: "QP01 0118 Riparian Zone thrush", ext: "wav")
}
}
fileprivate func _play() {
self.player.play()
}
fileprivate func _pause() {
self.player.pause()
}
}
struct StoreView_Previews: PreviewProvider {
static var previews: some View {
PlanView(productName: "Pro version",

Loading…
Cancel
Save