diff --git a/Mixonomer/Application/SceneDelegate.swift b/Mixonomer/Application/SceneDelegate.swift index a6e70c8..bc3d54f 100644 --- a/Mixonomer/Application/SceneDelegate.swift +++ b/Mixonomer/Application/SceneDelegate.swift @@ -27,7 +27,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) - let liveUser = LiveUser(playlists: [], tags: [], username: keychain["username"] ?? "", loggedIn: false).loadUserDefaults() + let liveUser = LiveUser(playlists: [], tags: [], username: keychain["username"] ?? "", loggedIn: false).load_user_defaults() window.rootViewController = UIHostingController(rootView: contentView.environmentObject(liveUser)) self.window = window diff --git a/Mixonomer/Model/LiveUser.swift b/Mixonomer/Model/LiveUser.swift index 3a5d774..c9face2 100644 --- a/Mixonomer/Model/LiveUser.swift +++ b/Mixonomer/Model/LiveUser.swift @@ -43,6 +43,16 @@ class LiveUser: ObservableObject { self.user = user } + func lastfm_connected() -> Bool { + if let username = user?.lastfm_username { + if username.count > 0 { + return true + } + } + + return false + } + func logout() { let keychain = Keychain(service: "xyz.sarsoo.music.login") @@ -65,20 +75,20 @@ class LiveUser: ObservableObject { } } - func updatePlaylist(playlistIn: Playlist) { + func update_playlist(playlistIn: Playlist) { guard let index = self.playlists.firstIndex(of: playlistIn) else { fatalError("\(playlistIn) not found") } self.playlists[index] = playlistIn } - func refreshUser(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) { + func refresh_user(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) { self.isRefreshingUser = true let api = UserApi.getUser RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.checkNetworkResponse(response: response) { + if self.check_network_response(response: response) { guard let data = response.data else { fatalError("error getting user") @@ -106,13 +116,13 @@ class LiveUser: ObservableObject { } } - func refreshPlaylists(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) { + func refresh_playlists(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) { self.isRefreshingPlaylists = true let api = PlaylistApi.getPlaylists RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.checkNetworkResponse(response: response) { + if self.check_network_response(response: response) { guard let data = response.data else { fatalError("error getting playlists") @@ -149,13 +159,13 @@ class LiveUser: ObservableObject { } } - func refreshTags(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) { + func refresh_tags(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) { self.isRefreshingTags = true let api = TagApi.getTags RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.checkNetworkResponse(response: response) { + if self.check_network_response(response: response) { guard let data = response.data else { fatalError("error getting tags") @@ -192,7 +202,7 @@ class LiveUser: ObservableObject { } } - func checkNetworkResponse(response: AFDataResponse) -> Bool { + func check_network_response(response: AFDataResponse) -> Bool { if let statusCode = response.response?.statusCode { switch statusCode { @@ -211,7 +221,7 @@ class LiveUser: ObservableObject { return false } - func loadUserDefaults() -> LiveUser { + func load_user_defaults() -> LiveUser { let defaults = UserDefaults.standard let decoder = JSONDecoder() diff --git a/Mixonomer/Model/User.swift b/Mixonomer/Model/User.swift index 5ea1f2d..4c890e9 100644 --- a/Mixonomer/Model/User.swift +++ b/Mixonomer/Model/User.swift @@ -26,7 +26,7 @@ class User: Identifiable, Decodable { var last_keygen: String var spotify_linked: Bool - var lastfm_username: String? + @Published var lastfm_username: String? //MARK: Initialization @@ -47,6 +47,52 @@ class User: Identifiable, Decodable { self.last_keygen = last_keygen self.spotify_linked = spotify_linked self.lastfm_username = lastfm_username - } + } + + private enum CodingKeys: String, CodingKey { + case username + case email + case type + + case last_login + case last_keygen + + case spotify_linked + case lastfm_username + } + + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + username = try container.decode(String.self, forKey: .username) + do{ + email = try container.decode(String.self, forKey: .email) + }catch { + email = nil + debugPrint("failed to parse email") + } + + type = try container.decode(UserType.self, forKey: .type) + + last_login = try container.decode(String.self, forKey: .last_login) + last_keygen = try container.decode(String.self, forKey: .last_keygen) + + spotify_linked = try container.decode(Bool.self, forKey: .spotify_linked) + lastfm_username = try container.decode(String.self, forKey: .lastfm_username) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.username, forKey: .username) + try container.encode(self.email, forKey: .email) + try container.encode(self.type.rawValue, forKey: .type) + + try container.encode(self.last_login, forKey: .last_login) + try container.encode(self.last_keygen, forKey: .last_keygen) + + try container.encode(self.spotify_linked, forKey: .spotify_linked) + try container.encode(self.lastfm_username, forKey: .lastfm_username) + } } diff --git a/Mixonomer/Views/AppSkeleton.swift b/Mixonomer/Views/AppSkeleton.swift index 1e0d20f..6c95c3c 100644 --- a/Mixonomer/Views/AppSkeleton.swift +++ b/Mixonomer/Views/AppSkeleton.swift @@ -69,9 +69,9 @@ struct AppSkeleton: View { } private func fetchAll() { - self.liveUser.refreshUser() - self.liveUser.refreshPlaylists() - self.liveUser.refreshTags() + self.liveUser.refresh_user() + self.liveUser.refresh_playlists() + self.liveUser.refresh_tags() } } diff --git a/Mixonomer/Views/Playlist/AddPlaylistSheet.swift b/Mixonomer/Views/Playlist/AddPlaylistSheet.swift index 1ebb1ad..2bd4043 100644 --- a/Mixonomer/Views/Playlist/AddPlaylistSheet.swift +++ b/Mixonomer/Views/Playlist/AddPlaylistSheet.swift @@ -94,7 +94,7 @@ struct AddPlaylistSheet: View { type: PlaylistType(rawValue: selectedType) ?? .defaultPlaylist) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { self.playlists.append(playlist) self.playlists = self.playlists.sorted(by: { $0.name.lowercased() < $1.name.lowercased() }) diff --git a/Mixonomer/Views/Playlist/PlaylistInputList.swift b/Mixonomer/Views/Playlist/PlaylistInputList.swift index 2153de6..9d9f032 100644 --- a/Mixonomer/Views/Playlist/PlaylistInputList.swift +++ b/Mixonomer/Views/Playlist/PlaylistInputList.swift @@ -13,14 +13,21 @@ struct Name: Identifiable, Hashable { var name: String } +enum PlaylistInputType { + case MixonomerPlaylists + case SpotifyPlaylists +} + struct PlaylistInputList: View { @Binding var names: [String] var nameType: String + var type: PlaylistInputType - init(names: Binding<[String]>, nameType: String){ + init(names: Binding<[String]>, nameType: String, type: PlaylistInputType){ self.nameType = nameType self._names = names + self.type = type } var body: some View { @@ -41,12 +48,14 @@ struct PlaylistInputList: View { } // .id(UUID()) .navigationBarTitle(nameType) - .navigationBarItems(trailing: - Button( - action: { }, - label: { Image(systemName: "plus.circle") } - ) - ) +// .navigationBarItems(trailing: +// Button( +// action: { +// +// }, +// label: { Image(systemName: "plus.circle") } +// ) +// ) } } @@ -54,6 +63,6 @@ struct PlaylistInputList_Previews: PreviewProvider { static var previews: some View { PlaylistInputList(names: .constant([ "name" - ]), nameType: "Spotify Playlists") + ]), nameType: "Spotify Playlists", type: .MixonomerPlaylists) } } diff --git a/Mixonomer/Views/Playlist/PlaylistList.swift b/Mixonomer/Views/Playlist/PlaylistList.swift index b8a7228..bc00fcf 100644 --- a/Mixonomer/Views/Playlist/PlaylistList.swift +++ b/Mixonomer/Views/Playlist/PlaylistList.swift @@ -42,7 +42,7 @@ struct PlaylistList: View { let api = PlaylistApi.deletePlaylist(name: self.liveUser.playlists[index].name) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { } else { @@ -58,7 +58,7 @@ struct PlaylistList: View { } .refreshable { - self.liveUser.refreshPlaylists(onSuccess: { + self.liveUser.refresh_playlists(onSuccess: { toastText = "Refreshed!" toastSuccess = true diff --git a/Mixonomer/Views/Playlist/PlaylistRow.swift b/Mixonomer/Views/Playlist/PlaylistRow.swift index 36da480..b3942ef 100644 --- a/Mixonomer/Views/Playlist/PlaylistRow.swift +++ b/Mixonomer/Views/Playlist/PlaylistRow.swift @@ -31,7 +31,7 @@ struct PlaylistRow: View { .validate() .responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { } else { diff --git a/Mixonomer/Views/Playlist/PlaylistView.swift b/Mixonomer/Views/Playlist/PlaylistView.swift index bef332c..240cb78 100644 --- a/Mixonomer/Views/Playlist/PlaylistView.swift +++ b/Mixonomer/Views/Playlist/PlaylistView.swift @@ -24,9 +24,23 @@ struct PlaylistView: View { @State private var toastText = "" @State private var toastSuccess = true - var chartStyle: ChartStyle { + var trackChartStyle: ChartStyle { get { - let _style = ChartStyle(backgroundColor: .white, accentColor: .red, gradientColor: GradientColors.bluPurpl, textColor: .black, legendTextColor: .gray) + let _style = ChartStyle(backgroundColor: .white, accentColor: Color(red: 0.4765, green: 0.5976, blue: 0.7578), gradientColor: GradientColors.bluPurpl, textColor: .black, legendTextColor: .gray) + return _style + } + } + + var albumChartStyle: ChartStyle { + get { + let _style = ChartStyle(backgroundColor: .white, accentColor: Color(red: 0.6367, green: 0.2968, blue: 0.4648), gradientColor: GradientColors.bluPurpl, textColor: .black, legendTextColor: .gray) + return _style + } + } + + var artistChartStyle: ChartStyle { + get { + let _style = ChartStyle(backgroundColor: .white, accentColor: Color(red: 0.3476, green: 0.5195, blue: 0.3359), gradientColor: GradientColors.bluPurpl, textColor: .black, legendTextColor: .gray) return _style } } @@ -35,71 +49,76 @@ struct PlaylistView: View { var body: some View { Form { - Section(header: Text("Stats")){ - HStack { - Text("Track Count") - Spacer() - Text("\(self.playlist.lastfm_stat_count)") - .font(.title) - .foregroundColor(Color.gray) - Text("\(self.playlist.lastfm_stat_percent_str)") - .font(.body) - .foregroundColor(Color.gray) + + if liveUser.lastfm_connected() { + + Section(header: Text("Stats")){ + HStack { + Text("Track Count") + Spacer() + Text("\(self.playlist.lastfm_stat_count)") + .font(.title) + .foregroundColor(Color.gray) + Text("\(self.playlist.lastfm_stat_percent_str)") + .font(.body) + .foregroundColor(Color.gray) + } + HStack { + Text("Album Count") + Spacer() + Text("\(self.playlist.lastfm_stat_album_count)") + .font(.title) + .foregroundColor(Color.gray) + Text("\(self.playlist.lastfm_stat_album_percent_str)") + .font(.body) + .foregroundColor(Color.gray) + } + HStack { + Text("Artist Count") + Spacer() + Text("\(self.playlist.lastfm_stat_artist_count)") + .font(.title) + .foregroundColor(Color.gray) + Text("\(self.playlist.lastfm_stat_artist_percent_str)") + .font(.body) + .foregroundColor(Color.gray) + } + Button(action: { + self.refreshStats() + }){ + Text("Refresh") + } } - HStack { - Text("Album Count") - Spacer() - Text("\(self.playlist.lastfm_stat_album_count)") - .font(.title) - .foregroundColor(Color.gray) - Text("\(self.playlist.lastfm_stat_album_percent_str)") - .font(.body) - .foregroundColor(Color.gray) - } - HStack { - Text("Artist Count") - Spacer() - Text("\(self.playlist.lastfm_stat_artist_count)") - .font(.title) - .foregroundColor(Color.gray) - Text("\(self.playlist.lastfm_stat_artist_percent_str)") - .font(.body) - .foregroundColor(Color.gray) - } - Button(action: { - self.refreshStats() - }){ - Text("Refresh") - } - } - ScrollView(.horizontal){ - HStack { - Spacer() - PieChartView( - data: [Double(self.playlist.lastfm_stat_percent), Double(100 - self.playlist.lastfm_stat_percent)], - title: "Tracks", - legend:"Listening", - style: chartStyle, - form: chartSize) - Spacer(minLength: 20) - PieChartView( - data: [Double(self.playlist.lastfm_stat_album_percent), Double(100 - self.playlist.lastfm_stat_album_percent)], - title: "Albums", - legend:"Listening", - style: chartStyle, - form: chartSize) - Spacer(minLength: 20) - PieChartView( - data: [Double(self.playlist.lastfm_stat_artist_percent), Double(100 - self.playlist.lastfm_stat_artist_percent)], - title: "Artists", - legend:"Listening", - style: chartStyle, - form: chartSize) - Spacer() + ScrollView(.horizontal){ + HStack { + Spacer() + PieChartView( + data: [Double(self.playlist.lastfm_stat_percent), Double(100 - self.playlist.lastfm_stat_percent)], + title: "Tracks", + legend:"Listening", + style: trackChartStyle, + form: chartSize) + Spacer(minLength: 20) + PieChartView( + data: [Double(self.playlist.lastfm_stat_album_percent), Double(100 - self.playlist.lastfm_stat_album_percent)], + title: "Albums", + legend:"Listening", + style: albumChartStyle, + form: chartSize) + Spacer(minLength: 20) + PieChartView( + data: [Double(self.playlist.lastfm_stat_artist_percent), Double(100 - self.playlist.lastfm_stat_artist_percent)], + title: "Artists", + legend:"Listening", + style: artistChartStyle, + form: chartSize) + Spacer() + } + .padding([.vertical], 20) + .padding([.horizontal], 10) } - .padding([.vertical], 20) - .padding([.horizontal], 10) + .listRowInsets(EdgeInsets()) } Section(header: Text("Options")){ @@ -168,7 +187,7 @@ struct PlaylistView: View { } } Section(header: Text("Inputs")){ - NavigationLink(destination: PlaylistInputList(names: self.$playlist.playlist_references, nameType: "Managed Playlists")) { + NavigationLink(destination: PlaylistInputList(names: self.$playlist.playlist_references, nameType: "Managed Playlists", type: .MixonomerPlaylists)) { HStack { Text("Managed Playlists") Spacer() @@ -177,7 +196,7 @@ struct PlaylistView: View { } } - NavigationLink(destination: PlaylistInputList(names: self.$playlist.parts, nameType: "Spotify Playlists")) { + NavigationLink(destination: PlaylistInputList(names: self.$playlist.parts, nameType: "Spotify Playlists", type: .SpotifyPlaylists)) { HStack { Text("Spotify Playlists") Spacer() @@ -225,7 +244,7 @@ struct PlaylistView: View { .validate() .responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { toastText = "Running!" toastSuccess = true @@ -244,7 +263,7 @@ struct PlaylistView: View { let api = PlaylistApi.refreshStats(name: playlist.name) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { toastText = "Refreshing Stats!" toastSuccess = true @@ -270,7 +289,7 @@ struct PlaylistView: View { let api = PlaylistApi.updatePlaylist(name: playlist.name, updates: updates) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { debugPrint("success") } else { debugPrint("error") @@ -283,7 +302,7 @@ struct PlaylistView: View { let api = PlaylistApi.getPlaylist(name: self.playlist.name) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { guard let data = response.data else { fatalError("error getting playlist") diff --git a/Mixonomer/Views/Settings/SettingsList.swift b/Mixonomer/Views/Settings/SettingsList.swift index 94ffe26..1209ab0 100644 --- a/Mixonomer/Views/Settings/SettingsList.swift +++ b/Mixonomer/Views/Settings/SettingsList.swift @@ -53,7 +53,7 @@ struct SettingsList: View { let api = UserApi.deleteUser RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { self.liveUser.logout() } diff --git a/Mixonomer/Views/Tag/AddTagSheet.swift b/Mixonomer/Views/Tag/AddTagSheet.swift index 235989d..99611e0 100644 --- a/Mixonomer/Views/Tag/AddTagSheet.swift +++ b/Mixonomer/Views/Tag/AddTagSheet.swift @@ -76,7 +76,7 @@ struct AddTagSheet: View { let api = TagApi.newTag(tag_id: tag_id) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { self.tags.append(tag) self.tags = self.tags.sorted(by: { $0.name.lowercased() < $1.name.lowercased() }) diff --git a/Mixonomer/Views/Tag/TagList.swift b/Mixonomer/Views/Tag/TagList.swift index ab294c9..0c27fff 100644 --- a/Mixonomer/Views/Tag/TagList.swift +++ b/Mixonomer/Views/Tag/TagList.swift @@ -31,7 +31,7 @@ struct TagList: View { let api = TagApi.deleteTag(tag_id: self.liveUser.tags[index].tag_id) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { } else { @@ -47,7 +47,7 @@ struct TagList: View { } } .refreshable { - self.liveUser.refreshTags(onSuccess: { + self.liveUser.refresh_tags(onSuccess: { toastText = "Refreshed!" toastSuccess = true diff --git a/Mixonomer/Views/Tag/TagObjList.swift b/Mixonomer/Views/Tag/TagObjList.swift index 32a68d7..8b88728 100644 --- a/Mixonomer/Views/Tag/TagObjList.swift +++ b/Mixonomer/Views/Tag/TagObjList.swift @@ -64,12 +64,12 @@ struct TagObjList: View { } } .navigationBarTitle(Text(objType)) - .navigationBarItems(trailing: - Button( - action: { }, - label: { Image(systemName: "plus.circle") } - ) - ) +// .navigationBarItems(trailing: +// Button( +// action: { }, +// label: { Image(systemName: "plus.circle") } +// ) +// ) } } diff --git a/Mixonomer/Views/Tag/TagRow.swift b/Mixonomer/Views/Tag/TagRow.swift index be3b91f..6b8cef0 100644 --- a/Mixonomer/Views/Tag/TagRow.swift +++ b/Mixonomer/Views/Tag/TagRow.swift @@ -31,7 +31,7 @@ struct TagRow: View { .validate() .responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { } else { self.showingNetworkError = true diff --git a/Mixonomer/Views/Tag/TagView.swift b/Mixonomer/Views/Tag/TagView.swift index ca6017a..e87e8c6 100644 --- a/Mixonomer/Views/Tag/TagView.swift +++ b/Mixonomer/Views/Tag/TagView.swift @@ -120,7 +120,7 @@ struct TagView: View { let api = TagApi.runTag(tag_id: tag.tag_id) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { } else { @@ -133,7 +133,7 @@ struct TagView: View { let api = TagApi.updateTag(tag_id: tag.tag_id, updates: updates) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { } else { @@ -146,7 +146,7 @@ struct TagView: View { let api = TagApi.getTag(tag_id: self.tag.tag_id) RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in - if self.liveUser.checkNetworkResponse(response: response) { + if self.liveUser.check_network_response(response: response) { guard let data = response.data else { fatalError("error getting tag")