Skip to content

Commit

Permalink
Fixes (#338)
Browse files Browse the repository at this point in the history
* fixes

* cleanup
  • Loading branch information
martyu authored Nov 4, 2024
1 parent 6bb0ebe commit 847d99d
Show file tree
Hide file tree
Showing 46 changed files with 1,230 additions and 596 deletions.
34 changes: 34 additions & 0 deletions iosApp/GoogleService-Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>1074796601956-ibaf9r1sunn4tfm8c9og40ejuhkcvukf.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.1074796601956-ibaf9r1sunn4tfm8c9og40ejuhkcvukf</string>
<key>API_KEY</key>
<string>AIzaSyA-Fg5YNScjNlj_XPwBNeafUoqfZuuCyEk</string>
<key>GCM_SENDER_ID</key>
<string>1074796601956</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>io.newm.ios</string>
<key>PROJECT_ID</key>
<string>projectnewm-38b24</string>
<key>STORAGE_BUCKET</key>
<string>projectnewm-38b24.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:1074796601956:ios:68c857bcac45cfbd7db571</string>
</dict>
</plist>
5 changes: 4 additions & 1 deletion iosApp/Modules/AudioPlayer/PlayQueue/PlayQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Foundation
import shared
import Utilities

@MainActor
struct PlayQueue {
var originalTracks: Set<NFTTrack> = [] {
didSet {
Expand Down Expand Up @@ -204,5 +203,9 @@ extension PlayQueue {
case queueIsEmpty
case invalidIndex
case trackNotInQueue

var errorDescription: String? {
"There was an error playing the song."
}
}
}
28 changes: 28 additions & 0 deletions iosApp/Modules/AudioPlayer/UI/PlayButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import SwiftUI
import SharedUI
import Resolver
import ModuleLinker
import shared
import Analytics

public struct PlayButton: View {
@InjectedObject private var audioPlayer: VLCAudioPlayer
Expand All @@ -13,8 +15,10 @@ public struct PlayButton: View {
switch audioPlayer.state {
case .playing:
audioPlayer.pause()
logPauseTapped()
case .paused, .stopped:
audioPlayer.play()
logPlayTapped()
case .buffering:
break
}
Expand Down Expand Up @@ -47,6 +51,30 @@ public struct PlayButton: View {
}
}

extension PlayButton {
private func logPauseTapped() {
NEWMAnalytics.trackClickEvent(
buttonName: AppScreens.MusicPlayerScreen().PAUSE_BUTTON,
screenName: AppScreens.MusicPlayerScreen().name,
properties:
[
"song_id": audioPlayer.currentTrack?.id ?? "",
]
)
}

private func logPlayTapped() {
NEWMAnalytics.trackClickEvent(
buttonName: AppScreens.MusicPlayerScreen().PLAY_BUTTON,
screenName: AppScreens.MusicPlayerScreen().name,
properties:
[
"song_id": audioPlayer.currentTrack?.id ?? "",
]
)
}
}

#Preview {
PlayButton()
.preferredColorScheme(.dark)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import VLCKitSPM

extension VLCTime {
public extension VLCTime {
var seconds: Double? {
value.flatMap { $0.doubleValue / 1_000 }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ extension VLCAudioPlayer {
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = duration
}

if let currentTime {
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = currentTime
if let seconds = currentTime?.seconds {
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = seconds
}

MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,22 @@ class VLCAudioPlayerDelegate: NSObject, VLCMediaPlayerDelegate {
}

private var continuation: AsyncStream<Void>.Continuation!
private var lastYieldTime: Date?
private let throttleInterval: TimeInterval = 1.0// Throttle interval in seconds

func mediaPlayerStateChanged(_ aNotification: Foundation.Notification) {
continuation.yield()
}

func mediaPlayerTimeChanged(_ aNotification: Foundation.Notification) {
// Throttle timeChanged calls based on the last yield time
let now = Date()

if let lastTime = lastYieldTime, now.timeIntervalSince(lastTime) < throttleInterval {
return // Skip this event if it's within the throttle interval
}

lastYieldTime = now
continuation.yield()
}

Expand Down
88 changes: 45 additions & 43 deletions iosApp/Modules/AudioPlayer/VLCAudioPlayer/VLCAudioPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ public class VLCAudioPlayer: ObservableObject {
static let sharedPlayer = VLCAudioPlayer()

private var mediaPlayer: VLCMediaPlayer
@Published private var playQueue = PlayQueue()
private var playQueue = PlayQueue() {
didSet {
update()
}
}
@Published private var fileManager = FileManagerService()
lazy private var delegate: VLCAudioPlayerDelegate = VLCAudioPlayerDelegate()
private var cancels = Set<AnyCancellable>()
Expand All @@ -30,24 +34,16 @@ public class VLCAudioPlayer: ObservableObject {
private var _errors = PassthroughSubject<Error, Never>()
public var errors: AnyPublisher<Error, Never> { _errors.eraseToAnyPublisher() }

public var state: PlaybackState {
if mediaPlayer.isPlaying {
return .playing
} else if mediaPlayer.state == .buffering {
return .buffering
} else if mediaPlayer.state == .paused {
return .paused
} else {
return .stopped
}
}
public var duration: TimeInterval? { mediaPlayer.media?.length.seconds }
public var currentTime: TimeInterval? { mediaPlayer.time.seconds }
public var percentPlayed: Float? { mediaPlayer.position }
public var title: String? { mediaPlayer.media?.metaData.title }
public var artist: String? { mediaPlayer.media?.metaData.artist }
public var artworkUrl: URL? { mediaPlayer.media?.metaData.artworkURL }
public var willPlay: Bool { mediaPlayer.willPlay }
@Published public var state: PlaybackState = .stopped
@Published public var duration: TimeInterval?
@Published public var currentTime: VLCTime?
@Published public var percentPlayed: Float?
@Published public var title: String?
@Published public var artist: String?
@Published public var artworkUrl: URL?
@Published public var currentTrack: NFTTrack?
@Published public var isPlaying: Bool = false

@Injected var errorReporter: any ErrorReporting

public var textFilter: String? {
Expand Down Expand Up @@ -81,7 +77,7 @@ public class VLCAudioPlayer: ObservableObject {
fileManager.objectWillChange
.receive(on: DispatchQueue.main)
.sink { [weak self] in
self?.objectWillChange.send()
self?.update()
}.store(in: &cancels)

NotificationCenter.default.publisher(for: Notification.Name(Notification().walletConnectionStateChanged)).sink { [weak self] _ in
Expand All @@ -105,18 +101,36 @@ public class VLCAudioPlayer: ObservableObject {
playCurrentTrackInQueue()
} else if mediaPlayer.state == .error {
_errors.send("Unable to load \(currentTrack?.title ?? "song")")
}
DispatchQueue.main.async { [weak self] in
self?.objectWillChange.send()
} else if mediaPlayer.time != currentTime {
Task { @MainActor in
update()
}
}
}
}
}

public func setTracks(_ tracks: Set<NFTTrack>) {
playQueue.originalTracks = tracks
private func update() {
title = mediaPlayer.media?.metaData.title
duration = mediaPlayer.media?.length.seconds
currentTime = mediaPlayer.time
percentPlayed = mediaPlayer.position
title = mediaPlayer.media?.metaData.title
artist = mediaPlayer.media?.metaData.artist
artworkUrl = mediaPlayer.media?.metaData.artworkURL
currentTrack = try? playQueue.currentTrack()
isPlaying = state == .playing
state = if mediaPlayer.isPlaying {
.playing
} else if mediaPlayer.state == .buffering {
.buffering
} else if mediaPlayer.state == .paused {
.paused
} else {
.stopped
}
}

public var hasNextTrack: Bool {
playQueue.hasNextTrack
}
Expand Down Expand Up @@ -164,7 +178,7 @@ public class VLCAudioPlayer: ObservableObject {
try await fileManager.download(track: track) { [weak self] progress in
guard let self else { return }
print("progress for [\(track.title)]: \(progress)")
DispatchQueue.main.async {
Task { @MainActor in
self.loadingProgress[track] = progress
}
}
Expand Down Expand Up @@ -219,24 +233,12 @@ public class VLCAudioPlayer: ObservableObject {

public func setTracks(_ tracks: Set<NFTTrack>, playFirstTrack: Bool = true) {
playQueue.originalTracks = tracks
try! playQueue.seekToFirst()
if playFirstTrack {
if playFirstTrack, tracks.isEmpty == false {
try? playQueue.seekToFirst()
playCurrentTrackInQueue()
}
}

public var isPlaying: Bool {
state == .playing
}

public var currentTrack: NFTTrack? {
try? playQueue.currentTrack()
}

public func trackIsPlaying(_ track: NFTTrack) -> Bool {
currentTrack == track
}

public func trackIsDownloaded(_ track: NFTTrack) -> Bool {
fileManager.fileExists(for: URL(string: track.audioUrl)!)
}
Expand All @@ -249,8 +251,8 @@ public class VLCAudioPlayer: ObservableObject {
fileManager.clearFiles()
}

public func removeDownloadedSong(_ song: NFTTrack) {
fileManager.clearFile(at: URL(string: song.audioUrl)!)
public func removeDownloadedSong(_ song: NFTTrack) async {
await fileManager.clearFile(at: URL(string: song.audioUrl)!)
}

deinit {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

public protocol ErrorReporting {
public protocol ErrorReporting: Sendable {
func logError(_ error: String)
func logError(_ error: Error)
}
1 change: 1 addition & 0 deletions iosApp/Modules/DI/ModuleLinker/Protocols/Library.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ import Foundation
import SwiftUI

public protocol LibraryViewProviding {
@MainActor
func libraryView() -> AnyView
}
1 change: 1 addition & 0 deletions iosApp/Modules/DI/ModuleLinker/Protocols/NowPlaying.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public protocol NowPlayingViewProviding {
func nowPlayingView() -> AnyView
}

@MainActor
public protocol MiniNowPlayingViewProviding {
func miniNowPlayingView() -> AnyView
}
24 changes: 24 additions & 0 deletions iosApp/Modules/Helpers/Analytics/AnalyticsModule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import ModuleLinker
import Foundation
import Resolver
import FirebaseCore

final public class AnalyticsModule: Module {
public static var shared = AnalyticsModule()
private let newmAnalytics = NEWMAnalytics()

init() {
FirebaseApp.configure()
NEWMAnalytics().setup()
}

public func registerAllServices() {

}

#if DEBUG
public func registerAllMockedServices(mockResolver: Resolver) {

}
#endif
}
46 changes: 46 additions & 0 deletions iosApp/Modules/Helpers/Analytics/NEWMAnalytics.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@preconcurrency import shared
import FirebaseAnalytics
import Combine
import Resolver
import Foundation
import SharedExtensions

public class NEWMAnalytics {
private var cancels: Set<AnyCancellable> = []

func setup() {
NotificationCenter.default.publisher(for: shared.Notification().loginStateChanged)
.receive(on: DispatchQueue.main)
.sink { _ in
Task { @MainActor in
let user = Resolver.resolve(UserDetailsUseCase.self)
NEWMAnalytics.setUserId(userId: (try? await user.fetchLoggedInUserDetails().id) ?? "")
}
}
.store(in: &cancels)

Task { @MainActor in
let user = Resolver.resolve(UserDetailsUseCase.self)
NEWMAnalytics.setUserId(userId: (try? await user.fetchLoggedInUserDetails().id) ?? "")
}
}

static public func trackClickEvent(buttonName: String, screenName: String, properties: [String : Any]?) {
var properties = properties
properties?["button_name"] = buttonName
properties?["screen_name"] = screenName
Analytics.logEvent("button_click", parameters: properties)
}

static public func trackEvent(eventName: String, properties: [String : Any]?) {
Analytics.logEvent(eventName, parameters: properties)
}

static public func setUserId(userId: String) {
Analytics.setUserID(userId)
}

static public func setUserProperty(propertyName: String, value: String) {
Analytics.setUserProperty(value, forName: propertyName)
}
}
Loading

0 comments on commit 847d99d

Please sign in to comment.