implemented codable for network json decoding and userdefault storage
This commit is contained in:
parent
43de19246e
commit
d012566f04
@ -30,7 +30,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
|
|
||||||
var controller: UIViewController
|
var controller: UIViewController
|
||||||
if keychain["username"] != nil && keychain["password"] != nil {
|
if keychain["username"] != nil && keychain["password"] != nil {
|
||||||
let liveUser = LiveUser(playlists: [], tags: [], username: keychain["username"]!)
|
let liveUser = LiveUser(playlists: [], tags: [], username: keychain["username"]!).loadUserDefaults()
|
||||||
controller = UIHostingController(rootView: contentView.environmentObject(liveUser))
|
controller = UIHostingController(rootView: contentView.environmentObject(liveUser))
|
||||||
} else {
|
} else {
|
||||||
let storyboard = UIStoryboard(name: "Main", bundle: nil)
|
let storyboard = UIStoryboard(name: "Main", bundle: nil)
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Alamofire
|
||||||
|
import SwiftyJSON
|
||||||
|
|
||||||
class LiveUser: ObservableObject {
|
class LiveUser: ObservableObject {
|
||||||
|
|
||||||
@ -26,4 +28,80 @@ class LiveUser: ObservableObject {
|
|||||||
}
|
}
|
||||||
self.playlists[index] = playlistIn
|
self.playlists[index] = playlistIn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func refreshPlaylists() {
|
||||||
|
let api = PlaylistApi.getPlaylists
|
||||||
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
|
|
||||||
|
guard let data = response.data else {
|
||||||
|
fatalError("error getting playlists")
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let json = try? JSON(data: data) else {
|
||||||
|
fatalError("error parsing reponse")
|
||||||
|
}
|
||||||
|
|
||||||
|
let playlists = json["playlists"].arrayValue
|
||||||
|
|
||||||
|
// update state
|
||||||
|
self.playlists = PlaylistApi.fromJSON(playlist: playlists).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
|
||||||
|
|
||||||
|
let encoder = JSONEncoder()
|
||||||
|
let defaults = UserDefaults.standard
|
||||||
|
do {
|
||||||
|
defaults.set(String(data: try encoder.encode(playlists), encoding: .utf8), forKey: "playlists")
|
||||||
|
} catch {
|
||||||
|
print("error encoding playlists: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func refreshTags() {
|
||||||
|
let api = TagApi.getTags
|
||||||
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
|
|
||||||
|
guard let data = response.data else {
|
||||||
|
fatalError("error getting tags")
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let json = try? JSON(data: data) else {
|
||||||
|
fatalError("error parsing reponse")
|
||||||
|
}
|
||||||
|
|
||||||
|
let tags = json["tags"].arrayValue
|
||||||
|
|
||||||
|
// update state
|
||||||
|
self.tags = TagApi.fromJSON(tag: tags).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
|
||||||
|
|
||||||
|
let encoder = JSONEncoder()
|
||||||
|
let defaults = UserDefaults.standard
|
||||||
|
do {
|
||||||
|
defaults.set(String(data: try encoder.encode(tags), encoding: .utf8), forKey: "tags")
|
||||||
|
} catch {
|
||||||
|
print("error encoding tags: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadUserDefaults() -> LiveUser {
|
||||||
|
let defaults = UserDefaults.standard
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
|
||||||
|
let _strPlaylists = defaults.string(forKey: "playlists")
|
||||||
|
let _strTags = defaults.string(forKey: "tags")
|
||||||
|
|
||||||
|
do {
|
||||||
|
if let _strPlaylists = _strPlaylists {
|
||||||
|
self.playlists = (try decoder.decode([Playlist].self, from: _strPlaylists.data(using: .utf8)!)).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
|
||||||
|
}
|
||||||
|
|
||||||
|
if let _strTags = _strTags {
|
||||||
|
self.tags = (try decoder.decode([Tag].self, from: _strTags.data(using: .utf8)!)).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("error decoding: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,17 @@
|
|||||||
// Copyright © 2020 Sarsoo. All rights reserved.
|
// Copyright © 2020 Sarsoo. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
|
||||||
class Playlist: Identifiable, Equatable {
|
class Playlist: Identifiable, Equatable, Codable {
|
||||||
|
|
||||||
//MARK: Properties
|
//MARK: Properties
|
||||||
|
|
||||||
var name: String
|
var name: String
|
||||||
var uri: String
|
var uri: String
|
||||||
var username: String
|
var username: String?
|
||||||
|
|
||||||
var include_recommendations: Bool
|
var include_recommendations: Bool
|
||||||
var recommendation_sample: Int
|
var recommendation_sample: Int
|
||||||
@ -23,89 +24,111 @@ class Playlist: Identifiable, Equatable {
|
|||||||
|
|
||||||
var parts: Array<String>
|
var parts: Array<String>
|
||||||
var playlist_references: Array<String>
|
var playlist_references: Array<String>
|
||||||
|
|
||||||
var shuffle: Bool
|
var shuffle: Bool
|
||||||
|
|
||||||
|
var sort: String
|
||||||
|
var description_overwrite: String?
|
||||||
|
var description_suffix: String?
|
||||||
|
|
||||||
|
var last_updated: String
|
||||||
|
|
||||||
|
var lastfm_stat_count: Int
|
||||||
|
var lastfm_stat_album_count: Int
|
||||||
|
var lastfm_stat_artist_count: Int
|
||||||
|
|
||||||
|
var lastfm_stat_percent: Float
|
||||||
|
var lastfm_stat_album_percent: Float
|
||||||
|
var lastfm_stat_artist_percent: Float
|
||||||
|
|
||||||
|
var lastfm_stat_last_refresh: String
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case name
|
||||||
|
case uri
|
||||||
|
case username
|
||||||
|
|
||||||
|
case include_recommendations
|
||||||
|
case recommendation_sample
|
||||||
|
case include_library_tracks
|
||||||
|
|
||||||
|
case parts
|
||||||
|
case playlist_references
|
||||||
|
case shuffle
|
||||||
|
|
||||||
|
case sort
|
||||||
|
case description_overwrite
|
||||||
|
case description_suffix
|
||||||
|
|
||||||
|
case last_updated
|
||||||
|
|
||||||
|
case lastfm_stat_count
|
||||||
|
case lastfm_stat_album_count
|
||||||
|
case lastfm_stat_artist_count
|
||||||
|
|
||||||
|
case lastfm_stat_percent
|
||||||
|
case lastfm_stat_album_percent
|
||||||
|
case lastfm_stat_artist_percent
|
||||||
|
|
||||||
|
case lastfm_stat_last_refresh
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: Initialization
|
//MARK: Initialization
|
||||||
|
|
||||||
init(name: String,
|
init(name: String,
|
||||||
uri: String,
|
uri: String = "spotify::",
|
||||||
username: String,
|
username: String = "NO USER",
|
||||||
|
|
||||||
|
include_recommendations: Bool = false,
|
||||||
|
recommendation_sample: Int = 0,
|
||||||
|
include_library_tracks: Bool = false,
|
||||||
|
|
||||||
|
parts: Array<String> = [],
|
||||||
|
playlist_references: Array<String> = [],
|
||||||
|
shuffle: Bool = false,
|
||||||
|
|
||||||
include_recommendations: Bool,
|
sort: String = "NO SORT",
|
||||||
recommendation_sample: Int,
|
description_overwrite: String? = nil,
|
||||||
include_library_tracks: Bool,
|
description_suffix: String? = nil,
|
||||||
|
|
||||||
parts: Array<String>,
|
last_updated: String = "",
|
||||||
playlist_references: Array<String>,
|
|
||||||
|
|
||||||
shuffle: Bool){
|
lastfm_stat_count: Int = 0,
|
||||||
|
lastfm_stat_album_count: Int = 0,
|
||||||
|
lastfm_stat_artist_count: Int = 0,
|
||||||
|
|
||||||
|
lastfm_stat_percent: Float = 0,
|
||||||
|
lastfm_stat_album_percent: Float = 0,
|
||||||
|
lastfm_stat_artist_percent: Float = 0,
|
||||||
|
|
||||||
|
lastfm_stat_last_refresh: String = ""){
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.uri = uri
|
self.uri = uri
|
||||||
self.username = username
|
self.username = username
|
||||||
|
|
||||||
self.include_recommendations = include_recommendations
|
self.include_recommendations = include_recommendations
|
||||||
self.recommendation_sample = recommendation_sample
|
self.recommendation_sample = recommendation_sample
|
||||||
self.include_library_tracks = include_library_tracks
|
self.include_library_tracks = include_library_tracks
|
||||||
|
|
||||||
self.parts = parts
|
self.parts = parts
|
||||||
self.playlist_references = playlist_references
|
self.playlist_references = playlist_references
|
||||||
|
|
||||||
self.shuffle = shuffle
|
self.shuffle = shuffle
|
||||||
}
|
|
||||||
|
|
||||||
static func fromDict(dictionary: JSON) -> Playlist? {
|
|
||||||
switch dictionary["type"].string {
|
|
||||||
case "default":
|
|
||||||
return Playlist(name: dictionary["name"].stringValue,
|
|
||||||
uri: dictionary["uri"].stringValue,
|
|
||||||
username: dictionary["username"].stringValue,
|
|
||||||
|
|
||||||
include_recommendations: dictionary["include_recommendations"].boolValue,
|
|
||||||
recommendation_sample: dictionary["recommendation_sample"].intValue,
|
|
||||||
include_library_tracks: dictionary["include_library_tracks"].boolValue,
|
|
||||||
|
|
||||||
parts: dictionary["parts"].arrayObject as! Array<String>,
|
self.sort = sort
|
||||||
playlist_references: dictionary["playlist_references"].arrayObject as! Array<String>,
|
self.description_overwrite = description_overwrite
|
||||||
|
self.description_suffix = description_suffix
|
||||||
shuffle: dictionary["shuffle"].boolValue)
|
|
||||||
case "recents":
|
|
||||||
return RecentsPlaylist(name: dictionary["name"].stringValue,
|
|
||||||
uri: dictionary["uri"].stringValue,
|
|
||||||
username: dictionary["username"].stringValue,
|
|
||||||
|
|
||||||
include_recommendations: dictionary["include_recommendations"].boolValue,
|
|
||||||
recommendation_sample: dictionary["recommendation_sample"].intValue,
|
|
||||||
include_library_tracks: dictionary["include_library_tracks"].boolValue,
|
|
||||||
|
|
||||||
parts: dictionary["parts"].arrayObject as! Array<String>,
|
self.last_updated = last_updated
|
||||||
playlist_references: dictionary["playlist_references"].arrayObject as! Array<String>,
|
|
||||||
|
|
||||||
shuffle: dictionary["shuffle"].boolValue,
|
|
||||||
|
|
||||||
add_last_month: dictionary["add_last_month"].boolValue,
|
|
||||||
add_this_month: dictionary["add_this_month"].boolValue,
|
|
||||||
day_boundary: dictionary["day_boundary"].intValue)
|
|
||||||
case "fmchart":
|
|
||||||
return LastFMChartPlaylist(name: dictionary["name"].stringValue,
|
|
||||||
uri: dictionary["uri"].stringValue,
|
|
||||||
username: dictionary["username"].stringValue,
|
|
||||||
|
|
||||||
include_recommendations: dictionary["include_recommendations"].boolValue,
|
|
||||||
recommendation_sample: dictionary["recommendation_sample"].intValue,
|
|
||||||
include_library_tracks: dictionary["include_library_tracks"].boolValue,
|
|
||||||
|
|
||||||
parts: dictionary["parts"].arrayObject as! Array<String>,
|
self.lastfm_stat_count = lastfm_stat_count
|
||||||
playlist_references: dictionary["playlist_references"].arrayObject as! Array<String>,
|
self.lastfm_stat_album_count = lastfm_stat_album_count
|
||||||
|
self.lastfm_stat_artist_count = lastfm_stat_artist_count
|
||||||
shuffle: dictionary["shuffle"].boolValue,
|
|
||||||
|
self.lastfm_stat_percent = lastfm_stat_percent
|
||||||
chart_range: LastFmRange(rawValue: dictionary["chart_range"].stringValue)!,
|
self.lastfm_stat_album_percent = lastfm_stat_album_percent
|
||||||
chart_limit: dictionary["chart_limit"].intValue)
|
self.lastfm_stat_artist_percent = lastfm_stat_artist_percent
|
||||||
default:
|
|
||||||
return nil
|
self.lastfm_stat_last_refresh = lastfm_stat_last_refresh
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var link: String {
|
var link: String {
|
||||||
@ -117,6 +140,38 @@ class Playlist: Identifiable, Equatable {
|
|||||||
return lhs.name == rhs.name
|
return lhs.name == rhs.name
|
||||||
// && lhs.username == rhs.username
|
// && lhs.username == rhs.username
|
||||||
}
|
}
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
name = try container.decode(String.self, forKey: .name)
|
||||||
|
uri = try container.decode(String.self, forKey: .uri)
|
||||||
|
// username = try container.decode(String.self, forKey: .username)
|
||||||
|
|
||||||
|
include_recommendations = try container.decode(Bool.self, forKey: .include_recommendations)
|
||||||
|
recommendation_sample = try container.decode(Int.self, forKey: .recommendation_sample)
|
||||||
|
include_library_tracks = try container.decode(Bool.self, forKey: .include_library_tracks)
|
||||||
|
|
||||||
|
parts = try container.decode([String].self, forKey: .parts)
|
||||||
|
playlist_references = try container.decode([String].self, forKey: .playlist_references)
|
||||||
|
shuffle = try container.decode(Bool.self, forKey: .shuffle)
|
||||||
|
|
||||||
|
sort = try container.decode(String.self, forKey: .sort)
|
||||||
|
// description_overwrite = try container.decode(String.self, forKey: .description_overwrite)
|
||||||
|
// description_suffix = try container.decode(String.self, forKey: .description_suffix)
|
||||||
|
|
||||||
|
last_updated = try container.decode(String.self, forKey: .last_updated)
|
||||||
|
|
||||||
|
lastfm_stat_count = try container.decode(Int.self, forKey: .lastfm_stat_count)
|
||||||
|
lastfm_stat_album_count = try container.decode(Int.self, forKey: .lastfm_stat_album_count)
|
||||||
|
lastfm_stat_artist_count = try container.decode(Int.self, forKey: .lastfm_stat_artist_count)
|
||||||
|
|
||||||
|
lastfm_stat_percent = try container.decode(Float.self, forKey: .lastfm_stat_percent)
|
||||||
|
lastfm_stat_album_percent = try container.decode(Float.self, forKey: .lastfm_stat_album_percent)
|
||||||
|
lastfm_stat_artist_percent = try container.decode(Float.self, forKey: .lastfm_stat_artist_percent)
|
||||||
|
|
||||||
|
lastfm_stat_last_refresh = try container.decode(String.self, forKey: .lastfm_stat_last_refresh)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,34 +183,36 @@ class RecentsPlaylist: Playlist {
|
|||||||
var add_this_month: Bool
|
var add_this_month: Bool
|
||||||
var day_boundary: Int
|
var day_boundary: Int
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey { case add_last_month; case add_this_month; case day_boundary }
|
||||||
|
|
||||||
//MARK: Initialization
|
//MARK: Initialization
|
||||||
|
|
||||||
init(name: String,
|
init(name: String,
|
||||||
uri: String,
|
username: String = "NO USER",
|
||||||
username: String,
|
|
||||||
|
|
||||||
include_recommendations: Bool,
|
add_last_month: Bool = false,
|
||||||
recommendation_sample: Int,
|
add_this_month: Bool = false,
|
||||||
include_library_tracks: Bool,
|
day_boundary: Int = 14){
|
||||||
|
|
||||||
parts: Array<String>,
|
|
||||||
playlist_references: Array<String>,
|
|
||||||
|
|
||||||
shuffle: Bool,
|
|
||||||
|
|
||||||
add_last_month: Bool,
|
|
||||||
add_this_month: Bool,
|
|
||||||
day_boundary: Int){
|
|
||||||
|
|
||||||
self.add_last_month = add_last_month
|
self.add_last_month = add_last_month
|
||||||
self.add_this_month = add_this_month
|
self.add_this_month = add_this_month
|
||||||
self.day_boundary = day_boundary
|
self.day_boundary = day_boundary
|
||||||
|
|
||||||
super.init(name: name, uri: uri, username: username, include_recommendations: include_recommendations, recommendation_sample: recommendation_sample, include_library_tracks: include_library_tracks, parts: parts, playlist_references: playlist_references, shuffle: shuffle)
|
super.init(name: name, username: username)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
add_last_month = try container.decode(Bool.self, forKey: .add_last_month)
|
||||||
|
add_this_month = try container.decode(Bool.self, forKey: .add_this_month)
|
||||||
|
day_boundary = try container.decode(Int.self, forKey: .day_boundary)
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LastFmRange: String {
|
enum LastFmRange: String, Decodable {
|
||||||
case overall = "OVERALL"
|
case overall = "OVERALL"
|
||||||
case week = "WEEK"
|
case week = "WEEK"
|
||||||
case month = "MONTH"
|
case month = "MONTH"
|
||||||
@ -171,27 +228,28 @@ class LastFMChartPlaylist: Playlist {
|
|||||||
var chart_range: LastFmRange
|
var chart_range: LastFmRange
|
||||||
var chart_limit: Int
|
var chart_limit: Int
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey { case chart_range; case chart_limit }
|
||||||
|
|
||||||
//MARK: Initialization
|
//MARK: Initialization
|
||||||
|
|
||||||
init(name: String,
|
init(name: String,
|
||||||
uri: String,
|
username: String = "NO USER",
|
||||||
username: String,
|
|
||||||
|
|
||||||
include_recommendations: Bool,
|
chart_range: LastFmRange = .overall,
|
||||||
recommendation_sample: Int,
|
chart_limit: Int = 10){
|
||||||
include_library_tracks: Bool,
|
|
||||||
|
|
||||||
parts: Array<String>,
|
|
||||||
playlist_references: Array<String>,
|
|
||||||
|
|
||||||
shuffle: Bool,
|
|
||||||
|
|
||||||
chart_range: LastFmRange,
|
|
||||||
chart_limit: Int){
|
|
||||||
|
|
||||||
self.chart_range = chart_range
|
self.chart_range = chart_range
|
||||||
self.chart_limit = chart_limit
|
self.chart_limit = chart_limit
|
||||||
|
|
||||||
super.init(name: name, uri: uri, username: username, include_recommendations: include_recommendations, recommendation_sample: recommendation_sample, include_library_tracks: include_library_tracks, parts: parts, playlist_references: playlist_references, shuffle: shuffle)
|
super.init(name: name, username: username)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
chart_range = try LastFmRange(rawValue: container.decode(String.self, forKey: .chart_range))!
|
||||||
|
chart_limit = try container.decode(Int.self, forKey: .chart_limit)
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
|
||||||
class Tag: Identifiable, Equatable {
|
class Tag: Identifiable, Equatable, Decodable {
|
||||||
|
|
||||||
//MARK: Properties
|
//MARK: Properties
|
||||||
|
|
||||||
@ -32,48 +32,32 @@ class Tag: Identifiable, Equatable {
|
|||||||
init(tag_id: String,
|
init(tag_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
username: String,
|
username: String,
|
||||||
|
|
||||||
tracks: [JSON],
|
tracks: [JSON],
|
||||||
albums: [JSON],
|
albums: [JSON],
|
||||||
artists: [JSON],
|
artists: [JSON],
|
||||||
|
|
||||||
count: Int,
|
count: Int,
|
||||||
proportion: Double,
|
proportion: Double,
|
||||||
total_user_scrobbles: Int,
|
total_user_scrobbles: Int,
|
||||||
|
|
||||||
last_updated: String){
|
last_updated: String){
|
||||||
|
|
||||||
self.tag_id = tag_id
|
self.tag_id = tag_id
|
||||||
self.name = name
|
self.name = name
|
||||||
self.username = username
|
self.username = username
|
||||||
|
|
||||||
self.tracks = tracks
|
self.tracks = tracks
|
||||||
self.albums = albums
|
self.albums = albums
|
||||||
self.artists = artists
|
self.artists = artists
|
||||||
|
|
||||||
self.count = count
|
self.count = count
|
||||||
self.proportion = proportion
|
self.proportion = proportion
|
||||||
self.total_user_scrobbles = total_user_scrobbles
|
self.total_user_scrobbles = total_user_scrobbles
|
||||||
|
|
||||||
self.last_updated = last_updated
|
self.last_updated = last_updated
|
||||||
}
|
}
|
||||||
|
|
||||||
static func fromDict(dictionary: JSON) -> Tag {
|
|
||||||
return Tag(tag_id: dictionary["tag_id"].stringValue,
|
|
||||||
name: dictionary["name"].stringValue,
|
|
||||||
username: dictionary["username"].stringValue,
|
|
||||||
|
|
||||||
tracks: dictionary["tracks"].arrayValue,
|
|
||||||
albums: dictionary["albums"].arrayValue,
|
|
||||||
artists: dictionary["artists"].arrayValue,
|
|
||||||
|
|
||||||
count: dictionary["count"].intValue,
|
|
||||||
proportion: dictionary["proportion"].doubleValue,
|
|
||||||
total_user_scrobbles: dictionary["total_user_scrobbles"].intValue,
|
|
||||||
|
|
||||||
last_updated: dictionary["last_updated"].stringValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func == (lhs: Tag, rhs: Tag) -> Bool {
|
static func == (lhs: Tag, rhs: Tag) -> Bool {
|
||||||
return lhs.tag_id == rhs.tag_id
|
return lhs.tag_id == rhs.tag_id
|
||||||
// && lhs.username == rhs.username
|
// && lhs.username == rhs.username
|
||||||
|
@ -9,12 +9,12 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
|
||||||
enum UserType: String {
|
enum UserType: String, Decodable {
|
||||||
case user = "user"
|
case user = "user"
|
||||||
case admin = "admin"
|
case admin = "admin"
|
||||||
}
|
}
|
||||||
|
|
||||||
class User: Identifiable {
|
class User: Identifiable, Decodable {
|
||||||
|
|
||||||
//MARK: Properties
|
//MARK: Properties
|
||||||
|
|
||||||
@ -43,16 +43,6 @@ class User: Identifiable {
|
|||||||
self.last_login = last_login
|
self.last_login = last_login
|
||||||
self.spotify_linked = spotify_linked
|
self.spotify_linked = spotify_linked
|
||||||
self.lastfm_username = lastfm_username
|
self.lastfm_username = lastfm_username
|
||||||
}
|
}
|
||||||
|
|
||||||
static func fromDict(dictionary: JSON) -> User {
|
|
||||||
return User(username: dictionary["username"].stringValue,
|
|
||||||
email: dictionary["username"].stringValue,
|
|
||||||
type: UserType(rawValue: dictionary["type"].stringValue) ?? .user,
|
|
||||||
last_login: dictionary["last_login"].stringValue,
|
|
||||||
spotify_linked: dictionary["spotify_linked"].boolValue,
|
|
||||||
lastfm_username: dictionary["lastfm_username"].stringValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,68 @@ extension PlaylistApi: ApiRequest {
|
|||||||
return ApiRequestDefaults.authMethod
|
return ApiRequestDefaults.authMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func fromJSON(playlist: Data) -> Playlist? {
|
||||||
|
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
do {
|
||||||
|
let json = try JSON(data: playlist)
|
||||||
|
switch json["type"].string {
|
||||||
|
case "default":
|
||||||
|
let playlist = try decoder.decode(Playlist.self, from: playlist)
|
||||||
|
return playlist
|
||||||
|
case "recents":
|
||||||
|
let playlist = try decoder.decode(RecentsPlaylist.self, from: playlist)
|
||||||
|
return playlist
|
||||||
|
case "fmchart":
|
||||||
|
let playlist = try decoder.decode(LastFMChartPlaylist.self, from: playlist)
|
||||||
|
return playlist
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
static func fromJSON(playlist: JSON) -> Playlist? {
|
||||||
|
|
||||||
|
let _json = playlist.rawString()?.data(using: .utf8)
|
||||||
|
|
||||||
|
if let data = _json {
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
do {
|
||||||
|
switch playlist["type"].string {
|
||||||
|
case "default":
|
||||||
|
let playlist = try decoder.decode(Playlist.self, from: data)
|
||||||
|
return playlist
|
||||||
|
case "recents":
|
||||||
|
let playlist = try decoder.decode(RecentsPlaylist.self, from: data)
|
||||||
|
return playlist
|
||||||
|
case "fmchart":
|
||||||
|
let playlist = try decoder.decode(LastFMChartPlaylist.self, from: data)
|
||||||
|
return playlist
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(playlist)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
static func fromJSON(playlist: [JSON]) -> [Playlist] {
|
||||||
|
var _playlists: [Playlist] = []
|
||||||
|
for dict in playlist {
|
||||||
|
let _iter = self.fromJSON(playlist: dict)
|
||||||
|
if let returned = _iter {
|
||||||
|
_playlists.append(returned)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _playlists
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +100,32 @@ extension TagApi: ApiRequest {
|
|||||||
return ApiRequestDefaults.authMethod
|
return ApiRequestDefaults.authMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func fromJSON(tag: JSON) -> Tag? {
|
||||||
|
|
||||||
|
let _json = tag.rawString()?.data(using: .utf8)
|
||||||
|
|
||||||
|
if let data = _json {
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
do {
|
||||||
|
let _tag = try decoder.decode(Tag.self, from: data)
|
||||||
|
return _tag
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO this loop could be condensed
|
||||||
|
static func fromJSON(tag: [JSON]) -> [Tag] {
|
||||||
|
var _tags: [Tag] = []
|
||||||
|
for dict in tag {
|
||||||
|
let _iter = self.fromJSON(tag: dict)
|
||||||
|
if let returned = _iter {
|
||||||
|
_tags.append(returned)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _tags
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,13 +77,13 @@ struct AddPlaylistSheet: View {
|
|||||||
var playlist: Playlist? = nil
|
var playlist: Playlist? = nil
|
||||||
switch PlaylistType(rawValue: selectedType) ?? .defaultPlaylist {
|
switch PlaylistType(rawValue: selectedType) ?? .defaultPlaylist {
|
||||||
case .defaultPlaylist:
|
case .defaultPlaylist:
|
||||||
playlist = Playlist(name: name, uri: "", username: username, include_recommendations: false, recommendation_sample: 10, include_library_tracks: false, parts: [], playlist_references: [], shuffle: false)
|
playlist = Playlist(name: name, username: username)
|
||||||
break
|
break
|
||||||
case .recents:
|
case .recents:
|
||||||
playlist = RecentsPlaylist(name: name, uri: "", username: username, include_recommendations: false, recommendation_sample: 10, include_library_tracks: false, parts: [], playlist_references: [], shuffle: false, add_last_month: false, add_this_month: false, day_boundary: 14)
|
playlist = RecentsPlaylist(name: name, username: username)
|
||||||
break
|
break
|
||||||
case .fmchart:
|
case .fmchart:
|
||||||
playlist = LastFMChartPlaylist(name: name, uri: "", username: username, include_recommendations: false, recommendation_sample: 10, include_library_tracks: false, parts: [], playlist_references: [], shuffle: false, chart_range: .month, chart_limit: 10)
|
playlist = LastFMChartPlaylist(name: name, username: username)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@ struct PlaylistRow: View {
|
|||||||
|
|
||||||
struct PlaylistRow_Previews: PreviewProvider {
|
struct PlaylistRow_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
PlaylistRow(playlist:
|
PlaylistView(playlist: .constant(
|
||||||
.constant(Playlist(name: "", uri: "", username: "", include_recommendations: true, recommendation_sample: 1, include_library_tracks: true, parts: [], playlist_references: [], shuffle: true))
|
Playlist(name: "playlist name", username: "username")
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,10 +180,7 @@ struct PlaylistView: View {
|
|||||||
fatalError("error getting playlist")
|
fatalError("error getting playlist")
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let json = try? JSON(data: data) else {
|
self.playlist = PlaylistApi.fromJSON(playlist: data)!
|
||||||
fatalError("error parsing reponse")
|
|
||||||
}
|
|
||||||
self.playlist = Playlist.fromDict(dictionary: json)!
|
|
||||||
self.isRefreshing = false
|
self.isRefreshing = false
|
||||||
}
|
}
|
||||||
//TODO: do better error checking
|
//TODO: do better error checking
|
||||||
@ -193,18 +190,7 @@ struct PlaylistView: View {
|
|||||||
struct PlaylistView_Previews: PreviewProvider {
|
struct PlaylistView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
PlaylistView(playlist: .constant(
|
PlaylistView(playlist: .constant(
|
||||||
Playlist(name: "playlist name",
|
Playlist(name: "playlist name", username: "username")
|
||||||
uri: "uri",
|
|
||||||
username: "username",
|
|
||||||
|
|
||||||
include_recommendations: true,
|
|
||||||
recommendation_sample: 5,
|
|
||||||
include_library_tracks: true,
|
|
||||||
|
|
||||||
parts: ["name"],
|
|
||||||
playlist_references: ["ref name"],
|
|
||||||
|
|
||||||
shuffle: true)
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@ struct RootView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pullToRefresh(isShowing: $isRefreshingPlaylists) {
|
.pullToRefresh(isShowing: $isRefreshingPlaylists) {
|
||||||
self.refreshPlaylists()
|
self.liveUser.refreshPlaylists()
|
||||||
|
self.isRefreshingPlaylists = false
|
||||||
}
|
}
|
||||||
.navigationBarTitle(Text("Playlists").font(.title))
|
.navigationBarTitle(Text("Playlists").font(.title))
|
||||||
|
|
||||||
@ -85,7 +86,8 @@ struct RootView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pullToRefresh(isShowing: $isRefreshingTags) {
|
.pullToRefresh(isShowing: $isRefreshingTags) {
|
||||||
self.refreshTags()
|
self.liveUser.refreshTags()
|
||||||
|
self.isRefreshingTags = false
|
||||||
}
|
}
|
||||||
.navigationBarTitle(Text("Tags").font(.title))
|
.navigationBarTitle(Text("Tags").font(.title))
|
||||||
|
|
||||||
@ -124,61 +126,8 @@ struct RootView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func fetchAll() {
|
private func fetchAll() {
|
||||||
refreshPlaylists()
|
self.liveUser.refreshPlaylists()
|
||||||
refreshTags()
|
self.liveUser.refreshTags()
|
||||||
}
|
|
||||||
|
|
||||||
public func refreshPlaylists() {
|
|
||||||
let api = PlaylistApi.getPlaylists
|
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
|
||||||
|
|
||||||
guard let data = response.data else {
|
|
||||||
fatalError("error getting playlists")
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let json = try? JSON(data: data) else {
|
|
||||||
fatalError("error parsing reponse")
|
|
||||||
}
|
|
||||||
|
|
||||||
let playlists = json["playlists"].arrayValue
|
|
||||||
// parse playlists
|
|
||||||
.map({ dict in
|
|
||||||
Playlist.fromDict(dictionary: dict)!
|
|
||||||
})
|
|
||||||
// sort
|
|
||||||
.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
|
|
||||||
|
|
||||||
// update state
|
|
||||||
self.liveUser.playlists = playlists
|
|
||||||
self.isRefreshingPlaylists = false
|
|
||||||
}
|
|
||||||
//TODO: do better error checking
|
|
||||||
}
|
|
||||||
|
|
||||||
public func refreshTags() {
|
|
||||||
let tagApi = TagApi.getTags
|
|
||||||
RequestBuilder.buildRequest(apiRequest: tagApi).responseJSON{ response in
|
|
||||||
|
|
||||||
guard let data = response.data else {
|
|
||||||
fatalError("error getting playlists")
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let json = try? JSON(data: data) else {
|
|
||||||
fatalError("error parsing reponse")
|
|
||||||
}
|
|
||||||
|
|
||||||
let tags = json["tags"].arrayValue
|
|
||||||
// parse playlists
|
|
||||||
.map({ dict in
|
|
||||||
Tag.fromDict(dictionary: dict)
|
|
||||||
})
|
|
||||||
// sort
|
|
||||||
.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
|
|
||||||
|
|
||||||
// update state
|
|
||||||
self.liveUser.tags = tags
|
|
||||||
self.isRefreshingTags = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,10 @@ struct TagView: View {
|
|||||||
guard let json = try? JSON(data: data) else {
|
guard let json = try? JSON(data: data) else {
|
||||||
fatalError("error parsing reponse")
|
fatalError("error parsing reponse")
|
||||||
}
|
}
|
||||||
self.tag = Tag.fromDict(dictionary: json["tag"])
|
let _tag = TagApi.fromJSON(tag: json["tag"])
|
||||||
|
if let tag = _tag {
|
||||||
|
self.tag = tag
|
||||||
|
}
|
||||||
self.isRefreshing = false
|
self.isRefreshing = false
|
||||||
}
|
}
|
||||||
//TODO: do better error checking
|
//TODO: do better error checking
|
||||||
|
Loading…
Reference in New Issue
Block a user