added tags, added delete caching for network response filtering
This commit is contained in:
parent
19526c2511
commit
2132e4d855
@ -23,6 +23,11 @@
|
||||
E98254D023FB00B60056D9D3 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98254CF23FB00B60056D9D3 /* LoginScreen.swift */; };
|
||||
E98254D923FB53780056D9D3 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = E98254D823FB53780056D9D3 /* Alamofire */; };
|
||||
E98254DB23FB64740056D9D3 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98254DA23FB64740056D9D3 /* Network.swift */; };
|
||||
E9E30C2623FEA4F000574EEF /* TagApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2523FEA4EF00574EEF /* TagApi.swift */; };
|
||||
E9E30C2823FEA6BD00574EEF /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2723FEA6BD00574EEF /* Tag.swift */; };
|
||||
E9E30C2A23FEAA3A00574EEF /* TagRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2923FEAA3A00574EEF /* TagRow.swift */; };
|
||||
E9E30C2D23FEAB0200574EEF /* TagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2C23FEAB0200574EEF /* TagView.swift */; };
|
||||
E9E30C3123FEAF2B00574EEF /* TagObjList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C3023FEAF2B00574EEF /* TagObjList.swift */; };
|
||||
E9EA690B23F9A5430012C3E8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9EA690A23F9A5430012C3E8 /* AppDelegate.swift */; };
|
||||
E9EA690D23F9A5430012C3E8 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9EA690C23F9A5430012C3E8 /* SceneDelegate.swift */; };
|
||||
E9EA690F23F9A5430012C3E8 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9EA690E23F9A5430012C3E8 /* RootView.swift */; };
|
||||
@ -64,6 +69,11 @@
|
||||
E98254C923FA26600056D9D3 /* PlaylistRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistRow.swift; sourceTree = "<group>"; };
|
||||
E98254CF23FB00B60056D9D3 /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreen.swift; sourceTree = "<group>"; };
|
||||
E98254DA23FB64740056D9D3 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = "<group>"; };
|
||||
E9E30C2523FEA4EF00574EEF /* TagApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagApi.swift; sourceTree = "<group>"; };
|
||||
E9E30C2723FEA6BD00574EEF /* Tag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = "<group>"; };
|
||||
E9E30C2923FEAA3A00574EEF /* TagRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagRow.swift; sourceTree = "<group>"; };
|
||||
E9E30C2C23FEAB0200574EEF /* TagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagView.swift; sourceTree = "<group>"; };
|
||||
E9E30C3023FEAF2B00574EEF /* TagObjList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagObjList.swift; sourceTree = "<group>"; };
|
||||
E9EA690723F9A5430012C3E8 /* Music Tools.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Music Tools.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E9EA690A23F9A5430012C3E8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
E9EA690C23F9A5430012C3E8 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
@ -122,6 +132,7 @@
|
||||
E98254BC23F9B7A90056D9D3 /* Playlist.swift */,
|
||||
E97AF45523FC4E7800635494 /* User.swift */,
|
||||
E97AF46323FD4EEF00635494 /* LiveUser.swift */,
|
||||
E9E30C2723FEA6BD00574EEF /* Tag.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@ -130,8 +141,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E98254DA23FB64740056D9D3 /* Network.swift */,
|
||||
E97AF45A23FC748D00635494 /* UserApi.swift */,
|
||||
E97AF45F23FC85D600635494 /* PlaylistApi.swift */,
|
||||
E97AF45A23FC748D00635494 /* UserApi.swift */,
|
||||
E9E30C2523FEA4EF00574EEF /* TagApi.swift */,
|
||||
);
|
||||
path = Network;
|
||||
sourceTree = "<group>";
|
||||
@ -139,12 +151,10 @@
|
||||
E98254C023F9FFDD0056D9D3 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E9E30C2F23FEACF700574EEF /* Tag */,
|
||||
E9E30C2E23FEACDE00574EEF /* Playlist */,
|
||||
E9EA690E23F9A5430012C3E8 /* RootView.swift */,
|
||||
E98254C123F9FFF90056D9D3 /* PlaylistView.swift */,
|
||||
E98254C923FA26600056D9D3 /* PlaylistRow.swift */,
|
||||
E98254CF23FB00B60056D9D3 /* LoginScreen.swift */,
|
||||
E97AF46623FD650800635494 /* AddPlaylistSheet.swift */,
|
||||
E97AF46823FD9E1B00635494 /* PlaylistInputList.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@ -160,6 +170,27 @@
|
||||
path = Application;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E9E30C2E23FEACDE00574EEF /* Playlist */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E98254C123F9FFF90056D9D3 /* PlaylistView.swift */,
|
||||
E98254C923FA26600056D9D3 /* PlaylistRow.swift */,
|
||||
E97AF46623FD650800635494 /* AddPlaylistSheet.swift */,
|
||||
E97AF46823FD9E1B00635494 /* PlaylistInputList.swift */,
|
||||
);
|
||||
path = Playlist;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E9E30C2F23FEACF700574EEF /* Tag */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E9E30C2923FEAA3A00574EEF /* TagRow.swift */,
|
||||
E9E30C2C23FEAB0200574EEF /* TagView.swift */,
|
||||
E9E30C3023FEAF2B00574EEF /* TagObjList.swift */,
|
||||
);
|
||||
path = Tag;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E9EA68FE23F9A5430012C3E8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -363,10 +394,14 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E9E30C2D23FEAB0200574EEF /* TagView.swift in Sources */,
|
||||
E9E30C2823FEA6BD00574EEF /* Tag.swift in Sources */,
|
||||
E9E30C3123FEAF2B00574EEF /* TagObjList.swift in Sources */,
|
||||
E98254CA23FA26600056D9D3 /* PlaylistRow.swift in Sources */,
|
||||
E9EA690B23F9A5430012C3E8 /* AppDelegate.swift in Sources */,
|
||||
E9EA690D23F9A5430012C3E8 /* SceneDelegate.swift in Sources */,
|
||||
E98254DB23FB64740056D9D3 /* Network.swift in Sources */,
|
||||
E9E30C2A23FEAA3A00574EEF /* TagRow.swift in Sources */,
|
||||
E97AF46C23FDA90900635494 /* LoginController.swift in Sources */,
|
||||
E97AF46023FC85D600635494 /* PlaylistApi.swift in Sources */,
|
||||
E9EA690F23F9A5430012C3E8 /* RootView.swift in Sources */,
|
||||
@ -376,6 +411,7 @@
|
||||
E97AF46423FD4EEF00635494 /* LiveUser.swift in Sources */,
|
||||
E97AF45623FC4E7800635494 /* User.swift in Sources */,
|
||||
E98254D023FB00B60056D9D3 /* LoginScreen.swift in Sources */,
|
||||
E9E30C2623FEA4F000574EEF /* TagApi.swift in Sources */,
|
||||
E97AF46923FD9E1B00635494 /* PlaylistInputList.swift in Sources */,
|
||||
E97AF45B23FC748D00635494 /* UserApi.swift in Sources */,
|
||||
);
|
||||
|
@ -24,7 +24,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
keychain["username"] = ""
|
||||
keychain["password"] = ""
|
||||
|
||||
liveUser = LiveUser(playlists: [])
|
||||
liveUser = LiveUser(playlists: [], tags: [])
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -15,9 +15,9 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" fixedFrame="YES" image="MusicToolsLogo" translatesAutoresizingMaskIntoConstraints="NO" id="NIx-qI-fR9">
|
||||
<rect key="frame" x="-59" y="184" width="512" height="512"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" image="MusicToolsLogo" id="NIx-qI-fR9">
|
||||
<rect key="frame" x="-49" y="192" width="512" height="512"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
|
@ -29,7 +29,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
// Use a UIHostingController as window root view controller.
|
||||
if let windowScene = scene as? UIWindowScene {
|
||||
let window = UIWindow(windowScene: windowScene)
|
||||
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(liveUser ?? LiveUser(playlists: [])))
|
||||
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(liveUser ?? LiveUser(playlists: [], tags: [])))
|
||||
self.window = window
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
|
@ -9,9 +9,11 @@
|
||||
import Foundation
|
||||
|
||||
class LiveUser: ObservableObject {
|
||||
var playlists: Array<Playlist>
|
||||
var playlists: [Playlist]
|
||||
var tags: [Tag]
|
||||
|
||||
init(playlists: Array<Playlist>) {
|
||||
init(playlists: [Playlist], tags: [Tag]) {
|
||||
self.playlists = playlists
|
||||
self.tags = tags
|
||||
}
|
||||
}
|
||||
|
82
Music Tools/Model/Tag.swift
Normal file
82
Music Tools/Model/Tag.swift
Normal file
@ -0,0 +1,82 @@
|
||||
//
|
||||
// Tag.swift
|
||||
// Music Tools
|
||||
//
|
||||
// Created by Andy Pack on 20/02/2020.
|
||||
// Copyright © 2020 Sarsoo. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftyJSON
|
||||
|
||||
class Tag: Identifiable, Equatable {
|
||||
|
||||
//MARK: Properties
|
||||
|
||||
var tag_id: String
|
||||
var name: String
|
||||
var username: String
|
||||
|
||||
var tracks: [JSON]
|
||||
var albums: [JSON]
|
||||
var artists: [JSON]
|
||||
|
||||
var count: Int
|
||||
var proportion: Double
|
||||
var total_user_scrobbles: Int
|
||||
|
||||
var last_updated: String
|
||||
|
||||
//MARK: Initialization
|
||||
|
||||
init(tag_id: String,
|
||||
name: String,
|
||||
username: String,
|
||||
|
||||
tracks: [JSON],
|
||||
albums: [JSON],
|
||||
artists: [JSON],
|
||||
|
||||
count: Int,
|
||||
proportion: Double,
|
||||
total_user_scrobbles: Int,
|
||||
|
||||
last_updated: String){
|
||||
|
||||
self.tag_id = tag_id
|
||||
self.name = name
|
||||
self.username = username
|
||||
|
||||
self.tracks = tracks
|
||||
self.albums = albums
|
||||
self.artists = artists
|
||||
|
||||
self.count = count
|
||||
self.proportion = proportion
|
||||
self.total_user_scrobbles = total_user_scrobbles
|
||||
|
||||
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 {
|
||||
return lhs.tag_id == rhs.tag_id
|
||||
// && lhs.username == rhs.username
|
||||
}
|
||||
|
||||
}
|
96
Music Tools/Network/TagApi.swift
Normal file
96
Music Tools/Network/TagApi.swift
Normal file
@ -0,0 +1,96 @@
|
||||
//
|
||||
// TagApi.swift
|
||||
// Music Tools
|
||||
//
|
||||
// Created by Andy Pack on 20/02/2020.
|
||||
// Copyright © 2020 Sarsoo. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
import SwiftyJSON
|
||||
|
||||
public enum TagApi {
|
||||
case getTags
|
||||
case runTag(tag_id: String)
|
||||
case updateTag(tag_id: String, updates: JSON)
|
||||
case deleteTag(tag_id: String)
|
||||
case newTag(tag_id: String)
|
||||
}
|
||||
|
||||
extension TagApi: ApiRequest {
|
||||
var domain: String {
|
||||
return ApiRequestDefaults.domain
|
||||
}
|
||||
|
||||
var path: String {
|
||||
switch self {
|
||||
case .getTags:
|
||||
return "api/tag"
|
||||
case .runTag(let tag_id):
|
||||
return "api/tag/\(tag_id)/update"
|
||||
case .updateTag(let tag_id):
|
||||
return "api/tag/\(tag_id)"
|
||||
case .deleteTag(let tag_id):
|
||||
return "api/tag/\(tag_id)"
|
||||
case .newTag(let tag_id):
|
||||
return "api/tag/\(tag_id)"
|
||||
}
|
||||
}
|
||||
|
||||
var httpMethod: Alamofire.HTTPMethod {
|
||||
switch self {
|
||||
case .getTags:
|
||||
return .get
|
||||
case .runTag:
|
||||
return .get
|
||||
case .updateTag:
|
||||
return .put
|
||||
case .deleteTag:
|
||||
return .delete
|
||||
case .newTag:
|
||||
return .post
|
||||
}
|
||||
}
|
||||
|
||||
var parameters: JSON? {
|
||||
switch self {
|
||||
case .getTags:
|
||||
return nil
|
||||
case .runTag:
|
||||
return nil
|
||||
case .updateTag(let tag_id, let updates):
|
||||
return updates
|
||||
case .deleteTag:
|
||||
return nil
|
||||
case .newTag:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var parameterType: ParameterEncoder? {
|
||||
switch self {
|
||||
case .getTags:
|
||||
return nil
|
||||
case .runTag:
|
||||
return nil
|
||||
case .updateTag:
|
||||
return JSONParameterEncoder.default
|
||||
case .deleteTag:
|
||||
return nil
|
||||
case .newTag:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var headers: HTTPHeaders? {
|
||||
return nil
|
||||
}
|
||||
|
||||
var authMethod: AuthMethod? {
|
||||
return ApiRequestDefaults.authMethod
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ struct PlaylistRow: View {
|
||||
HStack {
|
||||
Text(playlist.name)
|
||||
.contextMenu {
|
||||
|
||||
// run force touch
|
||||
Button(action: {
|
||||
let api = PlaylistApi.runPlaylist(name: self.playlist.name)
|
||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||
@ -29,6 +31,8 @@ struct PlaylistRow: View {
|
||||
Text("Refresh")
|
||||
Image(systemName: "arrow.clockwise.circle")
|
||||
}
|
||||
|
||||
// open force touch
|
||||
Button(action: {
|
||||
if let url = URL(string: self.playlist.link) {
|
||||
UIApplication.shared.open(url)
|
@ -13,6 +13,8 @@ struct PlaylistView: View {
|
||||
|
||||
init(playlist: Playlist) {
|
||||
self.playlist = playlist
|
||||
|
||||
// hide empty items below list
|
||||
UITableView.appearance().tableFooterView = UIView()
|
||||
}
|
||||
|
@ -14,25 +14,22 @@ struct RootView: View {
|
||||
|
||||
@EnvironmentObject var liveUser: LiveUser
|
||||
|
||||
@State private var selection = 0
|
||||
@State private var playlists: Array<Playlist> = []
|
||||
@State private var selection = 0 // Tab view selection
|
||||
@State private var playlists: Array<Playlist> = [] // Network pulled playlists
|
||||
@State private var tags: Array<Tag> = [] // Network pulled tags
|
||||
|
||||
@State private var isLoading = true
|
||||
@State private var showAdd = false
|
||||
@State private var showAdd = false // State for showing add modal view
|
||||
|
||||
@State private var onClose = onSheetClose
|
||||
|
||||
@State private var justDeleted: Array<Playlist> = []
|
||||
|
||||
func onSheetClose() {
|
||||
self.fetch()
|
||||
return
|
||||
}
|
||||
@State private var justDeletedPlaylists: Array<Playlist> = [] // Cache of recently deleted playlists for removing from next net request
|
||||
@State private var justDeletedTags: Array<Tag> = []
|
||||
|
||||
// refresh playlist list on interval
|
||||
let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
|
||||
|
||||
var body: some View {
|
||||
TabView {
|
||||
|
||||
// PLAYLISTS
|
||||
NavigationView {
|
||||
List{
|
||||
ForEach(playlists) { playlist in
|
||||
@ -41,7 +38,8 @@ struct RootView: View {
|
||||
.onDelete { indexSet in
|
||||
|
||||
indexSet.forEach { index in
|
||||
self.justDeleted.append(self.playlists[index])
|
||||
// add to recently deleted playlist cache
|
||||
self.justDeletedPlaylists.append(self.playlists[index])
|
||||
|
||||
let api = PlaylistApi.deletePlaylist(name: self.playlists[index].name)
|
||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||
@ -53,6 +51,8 @@ struct RootView: View {
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text("Playlists").font(.title))
|
||||
|
||||
// add playlist button
|
||||
.navigationBarItems(trailing:
|
||||
Button(
|
||||
action: { self.showAdd = true },
|
||||
@ -69,15 +69,39 @@ struct RootView: View {
|
||||
}
|
||||
}
|
||||
.tag(0)
|
||||
//
|
||||
//
|
||||
|
||||
// TAGS
|
||||
NavigationView {
|
||||
List(/*@START_MENU_TOKEN@*/0 ..< 5/*@END_MENU_TOKEN@*/) { item in
|
||||
Text("Tag")
|
||||
.font(.title)
|
||||
List{
|
||||
ForEach(tags) { tag in
|
||||
TagRow(tag: tag)
|
||||
}
|
||||
.onDelete { indexSet in
|
||||
|
||||
indexSet.forEach { index in
|
||||
// add to recently deleted playlist cache
|
||||
self.justDeletedTags.append(self.tags[index])
|
||||
|
||||
let api = TagApi.deleteTag(tag_id: self.tags[index].tag_id)
|
||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||
|
||||
}
|
||||
.navigationBarTitle(Text("Tags"))
|
||||
}
|
||||
|
||||
self.tags.remove(atOffsets: indexSet)
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text("Tags").font(.title))
|
||||
|
||||
// add playlist button
|
||||
.navigationBarItems(trailing:
|
||||
Button(
|
||||
action: { self.showAdd = true },
|
||||
label: { Text("Add") }
|
||||
).sheet(isPresented: $showAdd) {
|
||||
AddPlaylistSheet(state: self.$showAdd, playlists: self.$playlists)
|
||||
}
|
||||
)
|
||||
}
|
||||
.tabItem {
|
||||
VStack {
|
||||
@ -86,8 +110,8 @@ struct RootView: View {
|
||||
}
|
||||
}
|
||||
.tag(1)
|
||||
//
|
||||
//
|
||||
|
||||
// SETTINGS
|
||||
Text("Settings")
|
||||
.font(.title)
|
||||
.tabItem {
|
||||
@ -117,25 +141,69 @@ struct RootView: View {
|
||||
fatalError("error parsing reponse")
|
||||
}
|
||||
|
||||
let playlists = json["playlists"].arrayValue.map({ dict in
|
||||
let playlists = json["playlists"].arrayValue
|
||||
// parse playlists
|
||||
.map({ dict in
|
||||
Playlist.fromDict(dictionary: dict)
|
||||
}).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
|
||||
})
|
||||
// sort
|
||||
.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
|
||||
// filter playlists for those recently deleted
|
||||
.filter { (rxPlaylist) -> Bool in
|
||||
|
||||
var deleted = false
|
||||
for playlist in self.justDeleted {
|
||||
for playlist in self.justDeletedPlaylists {
|
||||
if playlist == rxPlaylist {
|
||||
deleted = true
|
||||
}
|
||||
}
|
||||
return !deleted
|
||||
}
|
||||
self.justDeleted = []
|
||||
// clear cache of recently deleted playlists
|
||||
self.justDeletedPlaylists = []
|
||||
|
||||
// update state
|
||||
self.liveUser.playlists = playlists
|
||||
self.playlists = self.liveUser.playlists
|
||||
}
|
||||
//TODO: do better error checking
|
||||
|
||||
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() })
|
||||
// filter playlists for those recently deleted
|
||||
.filter { (rxTag) -> Bool in
|
||||
|
||||
var deleted = false
|
||||
for tag in self.justDeletedTags {
|
||||
if tag == rxTag {
|
||||
deleted = true
|
||||
}
|
||||
}
|
||||
return !deleted
|
||||
}
|
||||
// clear cache of recently deleted playlists
|
||||
self.justDeletedTags = []
|
||||
|
||||
// update state
|
||||
self.liveUser.tags = tags
|
||||
self.tags = self.liveUser.tags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
72
Music Tools/Views/Tag/TagObjList.swift
Normal file
72
Music Tools/Views/Tag/TagObjList.swift
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// TagObjList.swift
|
||||
// Music Tools
|
||||
//
|
||||
// Created by Andy Pack on 20/02/2020.
|
||||
// Copyright © 2020 Sarsoo. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftyJSON
|
||||
|
||||
struct MusicObj: Identifiable {
|
||||
var id = UUID()
|
||||
var name: String
|
||||
var artist: String
|
||||
var count: Int
|
||||
}
|
||||
|
||||
struct TagObjList: View {
|
||||
|
||||
var objs: Array<MusicObj> = []
|
||||
var objType: String
|
||||
|
||||
init(objs: Array<JSON>, objType: String){
|
||||
self.objType = objType
|
||||
self.objs = objs.map { (obj) -> MusicObj in
|
||||
return MusicObj(name: obj["name"].stringValue,
|
||||
artist: obj["artist"].stringValue,
|
||||
count: obj["count"].intValue)
|
||||
}.sorted(by: { $0.count > $1.count })
|
||||
|
||||
}
|
||||
|
||||
init(musicObjs: [MusicObj], objType: String){
|
||||
self.objType = objType
|
||||
self.objs = objs.sorted(by: { $0.count > $1.count })
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
return List(objs) { obj in
|
||||
HStack {
|
||||
VStack(alignment: .leading){
|
||||
Text(obj.name)
|
||||
// .multilineTextAlignment(.leading)
|
||||
if obj.artist.count > 0 {
|
||||
Text(obj.artist)
|
||||
// .multilineTextAlignment(.leading)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
Text("\(obj.count)")
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text(objType))
|
||||
.navigationBarItems(trailing:
|
||||
Button(
|
||||
action: { },
|
||||
label: { Image(systemName: "plus.circle") }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct TagObjList_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TagObjList(musicObjs: [
|
||||
MusicObj(name: "To Pimp A Butterfly", artist: "Kendrick Lamar", count: 10)
|
||||
], objType: "Albums")
|
||||
}
|
||||
}
|
58
Music Tools/Views/Tag/TagRow.swift
Normal file
58
Music Tools/Views/Tag/TagRow.swift
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// TagRow.swift
|
||||
// Music Tools
|
||||
//
|
||||
// Created by Andy Pack on 20/02/2020.
|
||||
// Copyright © 2020 Sarsoo. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftyJSON
|
||||
|
||||
struct TagRow: View {
|
||||
|
||||
@EnvironmentObject var liveUser: LiveUser
|
||||
|
||||
var tag: Tag
|
||||
|
||||
var body: some View {
|
||||
NavigationLink(destination: TagView(tag: tag)){
|
||||
HStack {
|
||||
Text(tag.name)
|
||||
.contextMenu {
|
||||
|
||||
// run force touch
|
||||
Button(action: {
|
||||
let api = TagApi.runTag(tag_id: self.tag.tag_id)
|
||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||
|
||||
}
|
||||
}) {
|
||||
Text("Refresh")
|
||||
Image(systemName: "arrow.clockwise.circle")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TagRow_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TagRow(tag:
|
||||
Tag(tag_id: "tag_id",
|
||||
name: "tag name",
|
||||
username: "andy",
|
||||
|
||||
tracks: [],
|
||||
albums: [],
|
||||
artists: [],
|
||||
|
||||
count: 20,
|
||||
proportion: 0.5,
|
||||
total_user_scrobbles: 2000,
|
||||
|
||||
last_updated: "10th Feb")
|
||||
)
|
||||
}
|
||||
}
|
126
Music Tools/Views/Tag/TagView.swift
Normal file
126
Music Tools/Views/Tag/TagView.swift
Normal file
@ -0,0 +1,126 @@
|
||||
//
|
||||
// TagView.swift
|
||||
// Music Tools
|
||||
//
|
||||
// Created by Andy Pack on 20/02/2020.
|
||||
// Copyright © 2020 Sarsoo. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftyJSON
|
||||
|
||||
struct TagView: View {
|
||||
|
||||
init(tag: Tag) {
|
||||
self.tag = tag
|
||||
|
||||
// hide empty items below list
|
||||
UITableView.appearance().tableFooterView = UIView()
|
||||
}
|
||||
|
||||
var tag: Tag
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(header: Text("Stats")){
|
||||
HStack {
|
||||
Text("Count")
|
||||
Spacer()
|
||||
Text("\(self.tag.count)")
|
||||
.font(.title)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
HStack {
|
||||
Text("Proportion")
|
||||
Spacer()
|
||||
Text(String(format: "%.2f%%", self.tag.proportion))
|
||||
.font(.title)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
HStack {
|
||||
Text("User Total")
|
||||
Spacer()
|
||||
Text("\(self.tag.total_user_scrobbles)")
|
||||
.font(.title)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
Section(header: Text("Music")){
|
||||
NavigationLink(destination: TagObjList(objs: self.tag.artists,
|
||||
objType: "Artists")) {
|
||||
HStack {
|
||||
Text("Artists")
|
||||
Spacer()
|
||||
Text("\(self.tag.artists.count)")
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
|
||||
NavigationLink(destination: TagObjList(objs: self.tag.albums,
|
||||
objType: "Albums")) {
|
||||
HStack {
|
||||
Text("Albums")
|
||||
Spacer()
|
||||
Text("\(self.tag.albums.count)")
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
|
||||
NavigationLink(destination: TagObjList(objs: self.tag.tracks,
|
||||
objType: "Tracks")) {
|
||||
HStack {
|
||||
Text("Tracks")
|
||||
Spacer()
|
||||
Text("\(self.tag.tracks.count)")
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
Section(header: Text("Actions")){
|
||||
Button(action: { self.runTag() }) {
|
||||
Text("Update")
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text(tag.name))
|
||||
.onAppear {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func runTag() {
|
||||
let api = TagApi.runTag(tag_id: tag.tag_id)
|
||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||
|
||||
}
|
||||
//TODO: do better error checking
|
||||
}
|
||||
|
||||
func updateTag(updates: JSON) {
|
||||
let api = TagApi.updateTag(tag_id: tag.tag_id, updates: updates)
|
||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||
|
||||
}
|
||||
//TODO: do better error checking
|
||||
}
|
||||
}
|
||||
|
||||
struct TagView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TagView(tag:
|
||||
Tag(tag_id: "tag_id",
|
||||
name: "tag name",
|
||||
username: "andy",
|
||||
|
||||
tracks: [],
|
||||
albums: [],
|
||||
artists: [],
|
||||
|
||||
count: 20,
|
||||
proportion: 0.5,
|
||||
total_user_scrobbles: 2000,
|
||||
|
||||
last_updated: "10th Feb")
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user