diff --git a/Jukebox.xcodeproj/project.pbxproj b/Jukebox.xcodeproj/project.pbxproj index 104ad77..3af4571 100644 --- a/Jukebox.xcodeproj/project.pbxproj +++ b/Jukebox.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ E80E4CB52727F763000F9D74 /* Seeker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E80E4CB42727F763000F9D74 /* Seeker.swift */; }; E80E4CB827281297000F9D74 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E80E4CB727281297000F9D74 /* NetworkManager.swift */; }; E82271BC2735514400D1795D /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82271BB2735514400D1795D /* Constants.swift */; }; + E82271C3273567F000D1795D /* VisualizerStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82271C2273567F000D1795D /* VisualizerStyle.swift */; }; E84A17382728E6F1005F8CB4 /* PromiseKit in Frameworks */ = {isa = PBXBuildFile; productRef = E84A17372728E6F1005F8CB4 /* PromiseKit */; }; E84A173B2728EAC3005F8CB4 /* LyricsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E84A173A2728EAC3005F8CB4 /* LyricsView.swift */; }; E84A173D2728F490005F8CB4 /* SpotifyClientCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = E84A173C2728F490005F8CB4 /* SpotifyClientCredentials.swift */; }; @@ -62,6 +63,7 @@ E80E4CB42727F763000F9D74 /* Seeker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Seeker.swift; sourceTree = ""; }; E80E4CB727281297000F9D74 /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; E82271BB2735514400D1795D /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + E82271C2273567F000D1795D /* VisualizerStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisualizerStyle.swift; sourceTree = ""; }; E84A173A2728EAC3005F8CB4 /* LyricsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LyricsView.swift; sourceTree = ""; }; E84A173C2728F490005F8CB4 /* SpotifyClientCredentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpotifyClientCredentials.swift; sourceTree = ""; }; E84A173E2728F4CB005F8CB4 /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; }; @@ -222,6 +224,7 @@ isa = PBXGroup; children = ( E8F5724427167CAF00C5DF9C /* Track.swift */, + E82271C2273567F000D1795D /* VisualizerStyle.swift */, ); path = Models; sourceTree = ""; @@ -336,6 +339,7 @@ E892FE0D272E878600359A64 /* StatusBarAnimation.swift in Sources */, E8FB63F4272BB97C006F28B8 /* PreferencesView.swift in Sources */, E8FB63F8272BEF92006F28B8 /* AboutView.swift in Sources */, + E82271C3273567F000D1795D /* VisualizerStyle.swift in Sources */, E84A173D2728F490005F8CB4 /* SpotifyClientCredentials.swift in Sources */, E8AF5FC327290EFB00AACF65 /* Secrets.swift in Sources */, E8F57242271678C800C5DF9C /* PressButtonStyle.swift in Sources */, diff --git a/Jukebox/Models/VisualizerStyle.swift b/Jukebox/Models/VisualizerStyle.swift new file mode 100644 index 0000000..ee0e3bf --- /dev/null +++ b/Jukebox/Models/VisualizerStyle.swift @@ -0,0 +1,13 @@ +// +// VisualizerStyle.swift +// Jukebox +// +// Created by Sasindu Jayasinghe on 6/11/21. +// + +import Foundation + +enum VisualizerStyle: Int { + case none = 0 + case gradient = 1 +} diff --git a/Jukebox/Styles/ChipStyle.swift b/Jukebox/Styles/ChipStyle.swift index 1e8c438..e717125 100644 --- a/Jukebox/Styles/ChipStyle.swift +++ b/Jukebox/Styles/ChipStyle.swift @@ -9,13 +9,26 @@ import Foundation import SwiftUI struct ChipStyle: ViewModifier { + + @AppStorage("visualizerStyle") private var visualizerStyle: VisualizerStyle = .gradient + + // Constants + let primaryOpacity = 0.8 + let ternaryOpacity = 0.2 + func body(content: Content) -> some View { content .font(.caption) - .foregroundColor(.white.opacity(0.8)) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) .padding(.vertical, 3) .padding(.horizontal, 10) - .background(Color.white.opacity(0.2)) + .background( + visualizerStyle != .none + ? Color.white.opacity(ternaryOpacity) + : Color.primary.opacity(ternaryOpacity)) .cornerRadius(20) } } diff --git a/Jukebox/Views/ContentView.swift b/Jukebox/Views/ContentView.swift index 4f1f169..18c53bc 100644 --- a/Jukebox/Views/ContentView.swift +++ b/Jukebox/Views/ContentView.swift @@ -9,6 +9,9 @@ import SwiftUI struct ContentView: View { + // User Defaults + @AppStorage("visualizerStyle") private var visualizerStyle: VisualizerStyle = .gradient + // View Model @ObservedObject var contentViewVM: ContentViewModel @@ -17,11 +20,17 @@ struct ContentView: View { @State private var playbackScale = 1.0 @State private var lyricsScale = 1.2 + // Constants + let primaryOpacity = 0.8 + let secondaryOpacity = 0.4 + let ternaryOpacity = 0.2 + var body: some View { ZStack { - // TODO: Visualizer View - MetalView(popoverIsShown: contentViewVM.popoverIsShown).padding(-80) + if visualizerStyle == .gradient { + MetalView(popoverIsShown: contentViewVM.popoverIsShown).padding(-80) + } VStack(spacing: 16) { // Media details @@ -29,7 +38,10 @@ struct ContentView: View { // Album art image ZStack { Rectangle() - .foregroundColor(.white.opacity(0.2)) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(ternaryOpacity) + : .primary.opacity(ternaryOpacity)) .frame(width: 80, height: 80) .cornerRadius(8) @@ -43,13 +55,19 @@ struct ContentView: View { // Track details VStack(alignment: .leading) { Text(contentViewVM.track.title) - .foregroundColor(.white).opacity(0.8) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) .font(.system(size: 20, weight: .bold)) .lineLimit(1) Text(contentViewVM.track.artist) .font(.headline) .lineLimit(1) - .foregroundColor(.white).opacity(0.4) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(secondaryOpacity) + : .primary.opacity(secondaryOpacity)) Spacer() @@ -75,8 +93,9 @@ struct ContentView: View { } .pressButtonStyle() } + .padding(.bottom, 4) } - .padding(.vertical, 6) + .frame(width: .infinity, height: 80) Spacer() } @@ -97,7 +116,10 @@ struct ContentView: View { } label: { Image(systemName: "backward.fill") .font(.system(size: 20)) - .foregroundColor(.white).opacity(0.8) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) } .pressButtonStyle() @@ -106,7 +128,10 @@ struct ContentView: View { } label: { Image(systemName: contentViewVM.isPlaying ? "pause.fill" : "play.fill") .font(.system(size: 30)) - .foregroundColor(.white).opacity(0.8) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) .frame(width: 32, height: 32) } .pressButtonStyle() @@ -116,7 +141,10 @@ struct ContentView: View { } label: { Image(systemName: "forward.fill") .font(.system(size: 20)) - .foregroundColor(.white).opacity(0.8) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) } .pressButtonStyle() } diff --git a/Jukebox/Views/LyricsView.swift b/Jukebox/Views/LyricsView.swift index 89e32b4..918cd12 100644 --- a/Jukebox/Views/LyricsView.swift +++ b/Jukebox/Views/LyricsView.swift @@ -9,11 +9,18 @@ import SwiftUI struct LyricsView: View { + // User Defaults + @AppStorage("visualizerStyle") private var visualizerStyle: VisualizerStyle = .gradient + + // Properties let lyrics: String @Binding var showingLyrics: Bool @Binding var playbackScale: Double @Binding var lyricsScale: Double + // Constants + let primaryOpacity = 0.8 + var body: some View { ZStack { VStack { @@ -24,7 +31,10 @@ struct LyricsView: View { lyricsScale = 1.2 } label: { Image(systemName: "xmark.circle.fill") - .foregroundColor(.white.opacity(0.8)) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) } .pressButtonStyle() Spacer() @@ -34,7 +44,10 @@ struct LyricsView: View { VStack(alignment: .center) { Text(lyrics) .multilineTextAlignment(.center) - .foregroundColor(.white.opacity(0.8)) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) .font(.system(size: 20, weight: .bold)) } .padding(22) diff --git a/Jukebox/Views/PreferencesView.swift b/Jukebox/Views/PreferencesView.swift index 71e0a67..f8e188a 100644 --- a/Jukebox/Views/PreferencesView.swift +++ b/Jukebox/Views/PreferencesView.swift @@ -98,9 +98,12 @@ struct AppInfo: View { struct PreferencePanes: View { - private var visualizers = ["None", "Gradient", "Waves", "Abstract"] - @State private var launchAtLogin = false - @State private var selectedVisualization = 1 + @AppStorage("visualizerStyle") private var visualizerStyle = VisualizerStyle.gradient.rawValue + @AppStorage("swipeToSeek") private var swipeToSeek = false + + @State private var dummy = false + + private var visualizers = ["None", "Gradient"] var body: some View { VStack(alignment: .leading, spacing: 0) { @@ -111,7 +114,8 @@ struct PreferencePanes: View { .font(.title2) .fontWeight(.semibold) - Toggle("Launch Jukebox on login", isOn: $launchAtLogin) + Toggle("Launch Jukebox on login", isOn: $dummy) + Toggle("Swipe to seek on trackpad (Experimental)", isOn: $swipeToSeek) } .padding() .frame(width: geo.size.width, height: geo.size.height / 3, alignment: .topLeading) @@ -123,8 +127,8 @@ struct PreferencePanes: View { .font(.title2) .fontWeight(.semibold) - Toggle("Disable menu bar animation", isOn: $launchAtLogin) - Toggle("Disable menu bar marquee text", isOn: $launchAtLogin) + Toggle("Disable menu bar animation", isOn: $dummy) + Toggle("Disable menu bar marquee text", isOn: $dummy) } .padding() @@ -137,11 +141,14 @@ struct PreferencePanes: View { .font(.title2) .fontWeight(.semibold) - Picker("Style", selection: $selectedVisualization) { + Picker("Style", selection: $visualizerStyle) { ForEach(0.. Void + // States for animations @State private var seekerHeight: CGFloat = 4 + // Constants + let primaryOpacity = 0.6 + let ternaryOpacity = 0.2 + var body: some View { GeometryReader { geo in VStack { ZStack(alignment: .leading) { Rectangle() - .foregroundColor(.white.opacity(0.2)) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(ternaryOpacity) + : .primary.opacity(ternaryOpacity)) Rectangle() - .foregroundColor(.white.opacity(0.6)) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) .frame(width: geo.size.width * CGFloat(self.seekerPosition / trackDuration)) .animation(.easeInOut, value: self.seekerPosition) - SwipeView(seekerPosition: self.$seekerPosition, onEditingChanged: onEditingChanged) + if swipeToSeek { + SwipeView(seekerPosition: self.$seekerPosition, onEditingChanged: onEditingChanged) + } } .frame(width: geo.size.width, height: seekerHeight) .cornerRadius(6) @@ -40,11 +58,17 @@ struct Seeker: View { })) HStack { Text(formatSecondsForDisplay(seekerPosition)) - .foregroundColor(.white.opacity(0.6)) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) .font(.caption) Spacer() Text(formatSecondsForDisplay(trackDuration)) - .foregroundColor(.white.opacity(0.6)) + .foregroundColor( + visualizerStyle != .none + ? .white.opacity(primaryOpacity) + : .primary.opacity(primaryOpacity)) .font(.caption) } }