restructured main views, added totals to rows
This commit is contained in:
parent
6d3929a173
commit
fced8c9fc3
@ -26,6 +26,8 @@
|
|||||||
E98254D023FB00B60056D9D3 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98254CF23FB00B60056D9D3 /* LoginScreen.swift */; };
|
E98254D023FB00B60056D9D3 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98254CF23FB00B60056D9D3 /* LoginScreen.swift */; };
|
||||||
E98254D923FB53780056D9D3 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = E98254D823FB53780056D9D3 /* Alamofire */; };
|
E98254D923FB53780056D9D3 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = E98254D823FB53780056D9D3 /* Alamofire */; };
|
||||||
E98254DB23FB64740056D9D3 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98254DA23FB64740056D9D3 /* Network.swift */; };
|
E98254DB23FB64740056D9D3 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98254DA23FB64740056D9D3 /* Network.swift */; };
|
||||||
|
E9CCD5BB2454C57300B5CD6C /* PlaylistList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9CCD5BA2454C57300B5CD6C /* PlaylistList.swift */; };
|
||||||
|
E9CCD5BD2454C64300B5CD6C /* TagList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9CCD5BC2454C64300B5CD6C /* TagList.swift */; };
|
||||||
E9E30C2623FEA4F000574EEF /* TagApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2523FEA4EF00574EEF /* TagApi.swift */; };
|
E9E30C2623FEA4F000574EEF /* TagApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2523FEA4EF00574EEF /* TagApi.swift */; };
|
||||||
E9E30C2823FEA6BD00574EEF /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2723FEA6BD00574EEF /* Tag.swift */; };
|
E9E30C2823FEA6BD00574EEF /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2723FEA6BD00574EEF /* Tag.swift */; };
|
||||||
E9E30C2A23FEAA3A00574EEF /* TagRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2923FEAA3A00574EEF /* TagRow.swift */; };
|
E9E30C2A23FEAA3A00574EEF /* TagRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E30C2923FEAA3A00574EEF /* TagRow.swift */; };
|
||||||
@ -74,6 +76,8 @@
|
|||||||
E98254C923FA26600056D9D3 /* PlaylistRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistRow.swift; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
E98254DA23FB64740056D9D3 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = "<group>"; };
|
||||||
|
E9CCD5BA2454C57300B5CD6C /* PlaylistList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistList.swift; sourceTree = "<group>"; };
|
||||||
|
E9CCD5BC2454C64300B5CD6C /* TagList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagList.swift; sourceTree = "<group>"; };
|
||||||
E9E30C2523FEA4EF00574EEF /* TagApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagApi.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>"; };
|
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>"; };
|
E9E30C2923FEAA3A00574EEF /* TagRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagRow.swift; sourceTree = "<group>"; };
|
||||||
@ -178,6 +182,7 @@
|
|||||||
E98254C923FA26600056D9D3 /* PlaylistRow.swift */,
|
E98254C923FA26600056D9D3 /* PlaylistRow.swift */,
|
||||||
E97AF46623FD650800635494 /* AddPlaylistSheet.swift */,
|
E97AF46623FD650800635494 /* AddPlaylistSheet.swift */,
|
||||||
E97AF46823FD9E1B00635494 /* PlaylistInputList.swift */,
|
E97AF46823FD9E1B00635494 /* PlaylistInputList.swift */,
|
||||||
|
E9CCD5BA2454C57300B5CD6C /* PlaylistList.swift */,
|
||||||
);
|
);
|
||||||
path = Playlist;
|
path = Playlist;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -189,6 +194,7 @@
|
|||||||
E9E30C2C23FEAB0200574EEF /* TagView.swift */,
|
E9E30C2C23FEAB0200574EEF /* TagView.swift */,
|
||||||
E9E30C3023FEAF2B00574EEF /* TagObjList.swift */,
|
E9E30C3023FEAF2B00574EEF /* TagObjList.swift */,
|
||||||
E934AC98240DD0E4009869F4 /* AddTagSheet.swift */,
|
E934AC98240DD0E4009869F4 /* AddTagSheet.swift */,
|
||||||
|
E9CCD5BC2454C64300B5CD6C /* TagList.swift */,
|
||||||
);
|
);
|
||||||
path = Tag;
|
path = Tag;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -417,7 +423,9 @@
|
|||||||
E9E30C3323FF255C00574EEF /* SettingsList.swift in Sources */,
|
E9E30C3323FF255C00574EEF /* SettingsList.swift in Sources */,
|
||||||
E9EA690D23F9A5430012C3E8 /* SceneDelegate.swift in Sources */,
|
E9EA690D23F9A5430012C3E8 /* SceneDelegate.swift in Sources */,
|
||||||
E98254DB23FB64740056D9D3 /* Network.swift in Sources */,
|
E98254DB23FB64740056D9D3 /* Network.swift in Sources */,
|
||||||
|
E9CCD5BD2454C64300B5CD6C /* TagList.swift in Sources */,
|
||||||
E9E30C2A23FEAA3A00574EEF /* TagRow.swift in Sources */,
|
E9E30C2A23FEAA3A00574EEF /* TagRow.swift in Sources */,
|
||||||
|
E9CCD5BB2454C57300B5CD6C /* PlaylistList.swift in Sources */,
|
||||||
E97AF46023FC85D600635494 /* PlaylistApi.swift in Sources */,
|
E97AF46023FC85D600635494 /* PlaylistApi.swift in Sources */,
|
||||||
E9EA690F23F9A5430012C3E8 /* AppSkeleton.swift in Sources */,
|
E9EA690F23F9A5430012C3E8 /* AppSkeleton.swift in Sources */,
|
||||||
E98254BD23F9B7A90056D9D3 /* Playlist.swift in Sources */,
|
E98254BD23F9B7A90056D9D3 /* Playlist.swift in Sources */,
|
||||||
|
@ -15,15 +15,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
|
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||||
// Override point for customization after application launch.
|
// Override point for customization after application launch.
|
||||||
|
|
||||||
let keychain = Keychain(service: "xyz.sarsoo.music.login")
|
|
||||||
// do {
|
|
||||||
// try keychain.remove("username")
|
|
||||||
// try keychain.remove("password")
|
|
||||||
// } catch let error {
|
|
||||||
// debugPrint("Could not clear keychain, \(error)")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,13 +27,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
// Use a UIHostingController as window root view controller.
|
// Use a UIHostingController as window root view controller.
|
||||||
if let windowScene = scene as? UIWindowScene {
|
if let windowScene = scene as? UIWindowScene {
|
||||||
let window = UIWindow(windowScene: windowScene)
|
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).loadUserDefaults()
|
||||||
|
|
||||||
|
|
||||||
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(liveUser))
|
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(liveUser))
|
||||||
// window.rootViewController = UIHostingController(rootView: contentView.environmentObject(liveUser))
|
|
||||||
// window.rootViewController = LoginController()
|
|
||||||
self.window = window
|
self.window = window
|
||||||
window.makeKeyAndVisible()
|
window.makeKeyAndVisible()
|
||||||
}
|
}
|
||||||
@ -66,7 +62,5 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
||||||
// to restore the scene back to its current state.
|
// to restore the scene back to its current state.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
// Root level view loaded by delegate to show either main app or login screen
|
||||||
struct Router: View {
|
struct Router: View {
|
||||||
|
|
||||||
@EnvironmentObject var liveUser: LiveUser
|
@EnvironmentObject var liveUser: LiveUser
|
||||||
|
@ -16,120 +16,37 @@ struct AppSkeleton: View {
|
|||||||
@EnvironmentObject var liveUser: LiveUser
|
@EnvironmentObject var liveUser: LiveUser
|
||||||
|
|
||||||
@State private var selection = 0 // Tab view selection
|
@State private var selection = 0 // Tab view selection
|
||||||
@State private var showAdd = false // State for showing add modal view
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TabView {
|
TabView {
|
||||||
|
|
||||||
// PLAYLISTS
|
PlaylistList()
|
||||||
NavigationView {
|
.tabItem {
|
||||||
List{
|
VStack {
|
||||||
if(liveUser.playlists.count > 0){
|
Image(systemName: "music.note.list")
|
||||||
ForEach(liveUser.playlists.indices, id:\.self) { idx in
|
Text("Playlists")
|
||||||
PlaylistRow(playlist: self.$liveUser.playlists[idx])
|
|
||||||
}
|
|
||||||
.onDelete { indexSet in
|
|
||||||
|
|
||||||
indexSet.forEach { index in
|
|
||||||
let api = PlaylistApi.deletePlaylist(name: self.liveUser.playlists[index].name)
|
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.liveUser.playlists.remove(atOffsets: indexSet)
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
HStack {
|
|
||||||
Text("No Playlists")
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pullToRefresh(isShowing: self.$liveUser.isRefreshingPlaylists) {
|
.tag(0)
|
||||||
self.liveUser.refreshPlaylists()
|
|
||||||
}
|
|
||||||
.navigationBarTitle(Text("Playlists").font(.title))
|
|
||||||
|
|
||||||
// add playlist button
|
TagList()
|
||||||
.navigationBarItems(trailing:
|
.tabItem {
|
||||||
Button(
|
VStack {
|
||||||
action: { self.showAdd = true },
|
Image(systemName: "tag")
|
||||||
label: { Text("Add") }
|
Text("Tags")
|
||||||
).sheet(isPresented: $showAdd) {
|
|
||||||
AddPlaylistSheet(playlists: self.$liveUser.playlists, username: self.$liveUser.username)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.tabItem {
|
|
||||||
VStack {
|
|
||||||
Image(systemName: "music.note.list")
|
|
||||||
Text("Playlists")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tag(0)
|
|
||||||
|
|
||||||
// TAGS
|
|
||||||
NavigationView {
|
|
||||||
List{
|
|
||||||
if(liveUser.tags.count > 0) {
|
|
||||||
ForEach(liveUser.tags.indices, id:\.self) { idx in
|
|
||||||
TagRow(tag: self.$liveUser.tags[idx])
|
|
||||||
}
|
|
||||||
.onDelete { indexSet in
|
|
||||||
|
|
||||||
indexSet.forEach { index in
|
|
||||||
let api = TagApi.deleteTag(tag_id: self.liveUser.tags[index].tag_id)
|
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.liveUser.tags.remove(atOffsets: indexSet)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
HStack {
|
|
||||||
Text("No Tags")
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pullToRefresh(isShowing: self.$liveUser.isRefreshingTags) {
|
.tag(1)
|
||||||
self.liveUser.refreshTags()
|
|
||||||
}
|
|
||||||
.navigationBarTitle(Text("Tags").font(.title))
|
|
||||||
|
|
||||||
// add playlist button
|
SettingsList()
|
||||||
.navigationBarItems(trailing:
|
.tabItem {
|
||||||
Button(
|
VStack {
|
||||||
action: { self.showAdd = true },
|
Image(systemName: "slider.horizontal.3")
|
||||||
label: { Text("Add") }
|
Text("Settings")
|
||||||
).sheet(isPresented: $showAdd) {
|
|
||||||
AddTagSheet(tags: self.$liveUser.tags, username: self.$liveUser.username)
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
|
||||||
.tabItem {
|
|
||||||
VStack {
|
|
||||||
Image(systemName: "tag")
|
|
||||||
Text("Tags")
|
|
||||||
}
|
}
|
||||||
}
|
.tag(2)
|
||||||
.tag(1)
|
|
||||||
|
|
||||||
// SETTINGS
|
|
||||||
NavigationView {
|
|
||||||
SettingsList()
|
|
||||||
.navigationBarTitle(Text("Settings").font(.title))
|
|
||||||
}.tabItem {
|
|
||||||
VStack {
|
|
||||||
Image(systemName: "slider.horizontal.3")
|
|
||||||
Text("Settings")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tag(2)
|
|
||||||
}.onAppear {
|
}.onAppear {
|
||||||
self.fetchAll()
|
self.fetchAll()
|
||||||
}
|
}
|
||||||
|
58
Music Tools/Views/Playlist/PlaylistList.swift
Normal file
58
Music Tools/Views/Playlist/PlaylistList.swift
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// PlaylistList.swift
|
||||||
|
// Music Tools
|
||||||
|
//
|
||||||
|
// Created by Andy Pack on 25/04/2020.
|
||||||
|
// Copyright © 2020 Sarsoo. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct PlaylistList: View {
|
||||||
|
|
||||||
|
@EnvironmentObject var liveUser: LiveUser
|
||||||
|
@State private var showAdd = false // State for showing add modal view
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationView {
|
||||||
|
List{
|
||||||
|
if(liveUser.playlists.count > 0){
|
||||||
|
ForEach(liveUser.playlists.indices, id:\.self) { idx in
|
||||||
|
PlaylistRow(playlist: self.$liveUser.playlists[idx])
|
||||||
|
}
|
||||||
|
.onDelete { indexSet in
|
||||||
|
|
||||||
|
indexSet.forEach { index in
|
||||||
|
let api = PlaylistApi.deletePlaylist(name: self.liveUser.playlists[index].name)
|
||||||
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.liveUser.playlists.remove(atOffsets: indexSet)
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
Text("No Playlists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pullToRefresh(isShowing: self.$liveUser.isRefreshingPlaylists) {
|
||||||
|
self.liveUser.refreshPlaylists()
|
||||||
|
}
|
||||||
|
.navigationBarTitle(Text("Playlists 📻"))
|
||||||
|
.navigationBarItems(trailing:
|
||||||
|
Button(
|
||||||
|
action: { self.showAdd = true },
|
||||||
|
label: { Text("Add") }
|
||||||
|
).sheet(isPresented: $showAdd) {
|
||||||
|
AddPlaylistSheet(playlists: self.$liveUser.playlists, username: self.$liveUser.username)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PlaylistList_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
PlaylistList()
|
||||||
|
}
|
||||||
|
}
|
@ -10,35 +10,47 @@ import SwiftUI
|
|||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
|
||||||
struct PlaylistRow: View {
|
struct PlaylistRow: View {
|
||||||
|
|
||||||
@Binding var playlist: Playlist
|
@Binding var playlist: Playlist
|
||||||
|
@State private var showingNetworkError = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationLink(destination: PlaylistView(playlist: $playlist)){
|
NavigationLink(destination: PlaylistView(playlist: $playlist)){
|
||||||
HStack {
|
HStack {
|
||||||
Text(playlist.name)
|
Text(playlist.name)
|
||||||
.contextMenu {
|
if playlist.lastfm_stat_count > 0 {
|
||||||
|
Spacer()
|
||||||
// run force touch
|
Text("\(playlist.lastfm_stat_count)")
|
||||||
Button(action: {
|
.foregroundColor(.gray)
|
||||||
let api = PlaylistApi.runPlaylist(name: self.playlist.name)
|
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
|
||||||
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Text("Refresh")
|
|
||||||
Image(systemName: "arrow.clockwise.circle")
|
|
||||||
}
|
|
||||||
|
|
||||||
// open force touch
|
|
||||||
Button(action: {
|
|
||||||
if let url = URL(string: self.playlist.link) {
|
|
||||||
UIApplication.shared.open(url)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Text("Open")
|
|
||||||
Image(systemName: "arrowshape.turn.up.right.circle")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}.contextMenu {
|
||||||
|
Button(action: {
|
||||||
|
let api = PlaylistApi.runPlaylist(name: self.playlist.name)
|
||||||
|
RequestBuilder.buildRequest(apiRequest: api)
|
||||||
|
.validate()
|
||||||
|
.responseJSON{ response in
|
||||||
|
switch response.result {
|
||||||
|
case .success:
|
||||||
|
break
|
||||||
|
case .failure:
|
||||||
|
self.showingNetworkError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Refresh")
|
||||||
|
Image(systemName: "arrow.clockwise.circle")
|
||||||
|
}
|
||||||
|
Button(action: {
|
||||||
|
if let url = URL(string: self.playlist.link) {
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Open")
|
||||||
|
Image(systemName: "arrowshape.turn.up.right.circle")
|
||||||
|
}
|
||||||
|
}.alert(isPresented: $showingNetworkError) {
|
||||||
|
Alert(title: Text("Network Error"),
|
||||||
|
message: Text("Could not refresh playlist"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ struct PlaylistView: View {
|
|||||||
|
|
||||||
@State private var showingSheet = false
|
@State private var showingSheet = false
|
||||||
@State private var isRefreshing = false
|
@State private var isRefreshing = false
|
||||||
|
@State private var showingNetworkError = false
|
||||||
|
|
||||||
var chartStyle: ChartStyle {
|
var chartStyle: ChartStyle {
|
||||||
get {
|
get {
|
||||||
@ -211,6 +212,10 @@ struct PlaylistView: View {
|
|||||||
self.$chart_limit.wrappedValue = playlist.chart_limit
|
self.$chart_limit.wrappedValue = playlist.chart_limit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.alert(isPresented: $showingNetworkError) {
|
||||||
|
Alert(title: Text("Network Error"),
|
||||||
|
message: Text("Could not refresh playlist"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func changeChartRange(newRange: LastFmRange) {
|
func changeChartRange(newRange: LastFmRange) {
|
||||||
@ -222,8 +227,15 @@ struct PlaylistView: View {
|
|||||||
|
|
||||||
func runPlaylist() {
|
func runPlaylist() {
|
||||||
let api = PlaylistApi.runPlaylist(name: playlist.name)
|
let api = PlaylistApi.runPlaylist(name: playlist.name)
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
RequestBuilder.buildRequest(apiRequest: api)
|
||||||
|
.validate()
|
||||||
|
.responseJSON{ response in
|
||||||
|
switch response.result {
|
||||||
|
case .success:
|
||||||
|
break
|
||||||
|
case .failure:
|
||||||
|
self.showingNetworkError = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//TODO: do better error checking
|
//TODO: do better error checking
|
||||||
}
|
}
|
||||||
|
@ -13,65 +13,63 @@ struct SettingsList: View {
|
|||||||
|
|
||||||
@EnvironmentObject var liveUser: LiveUser
|
@EnvironmentObject var liveUser: LiveUser
|
||||||
|
|
||||||
init(){
|
|
||||||
UITableView.appearance().tableFooterView = UIView()
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack{
|
NavigationView {
|
||||||
List{
|
List{
|
||||||
Section {
|
Section {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
if let url = URL(string: "https://music.sarsoo.xyz") {
|
if let url = URL(string: "https://music.sarsoo.xyz") {
|
||||||
UIApplication.shared.open(url)
|
UIApplication.shared.open(url)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Launch Web Version")
|
||||||
|
}
|
||||||
|
Button(action: {
|
||||||
|
let keychain = Keychain(service: "xyz.sarsoo.music.login")
|
||||||
|
do {
|
||||||
|
try keychain.remove("username")
|
||||||
|
try keychain.remove("password")
|
||||||
|
|
||||||
|
self.liveUser.loggedIn = false
|
||||||
|
|
||||||
|
} catch let error {
|
||||||
|
debugPrint("Could not clear keychain, \(error)")
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Log out")
|
||||||
}
|
}
|
||||||
}) {
|
|
||||||
Text("Launch Web Version")
|
|
||||||
}
|
}
|
||||||
Button(action: {
|
Section(
|
||||||
let keychain = Keychain(service: "xyz.sarsoo.music.login")
|
header:
|
||||||
do {
|
Text("Development"),
|
||||||
try keychain.remove("username")
|
footer:
|
||||||
try keychain.remove("password")
|
HStack{
|
||||||
|
Spacer()
|
||||||
self.liveUser.loggedIn = false
|
Image("APFooter")
|
||||||
|
.resizable()
|
||||||
} catch let error {
|
.aspectRatio(contentMode: .fit)
|
||||||
debugPrint("Could not clear keychain, \(error)")
|
.frame(width: 100.0)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Button(action: {
|
||||||
|
if let url = URL(string: "https://github.com/sarsoo/music-tools") {
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Server Source")
|
||||||
|
}
|
||||||
|
Button(action: {
|
||||||
|
if let url = URL(string: "https://github.com/sarsoo/music-tools-ios") {
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("iOS Source")
|
||||||
}
|
}
|
||||||
}) {
|
|
||||||
Text("Log out")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Section(
|
.listStyle(GroupedListStyle())
|
||||||
header:
|
.navigationBarTitle(Text("Settings ⚡️").font(.title))
|
||||||
Text("Development"),
|
|
||||||
footer:
|
|
||||||
HStack{
|
|
||||||
Spacer()
|
|
||||||
Image("APFooter")
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(width: 100.0)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Button(action: {
|
|
||||||
if let url = URL(string: "https://github.com/sarsoo/music-tools") {
|
|
||||||
UIApplication.shared.open(url)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Text("Server Source")
|
|
||||||
}
|
|
||||||
Button(action: {
|
|
||||||
if let url = URL(string: "https://github.com/sarsoo/music-tools-ios") {
|
|
||||||
UIApplication.shared.open(url)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Text("iOS Source")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.listStyle(GroupedListStyle())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
62
Music Tools/Views/Tag/TagList.swift
Normal file
62
Music Tools/Views/Tag/TagList.swift
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// TagList.swift
|
||||||
|
// Music Tools
|
||||||
|
//
|
||||||
|
// Created by Andy Pack on 25/04/2020.
|
||||||
|
// Copyright © 2020 Sarsoo. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct TagList: View {
|
||||||
|
|
||||||
|
@EnvironmentObject var liveUser: LiveUser
|
||||||
|
@State private var showAdd = false // State for showing add modal view
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationView {
|
||||||
|
List{
|
||||||
|
if(liveUser.tags.count > 0) {
|
||||||
|
ForEach(liveUser.tags.indices, id:\.self) { idx in
|
||||||
|
TagRow(tag: self.$liveUser.tags[idx])
|
||||||
|
}
|
||||||
|
.onDelete { indexSet in
|
||||||
|
|
||||||
|
indexSet.forEach { index in
|
||||||
|
let api = TagApi.deleteTag(tag_id: self.liveUser.tags[index].tag_id)
|
||||||
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.liveUser.tags.remove(atOffsets: indexSet)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Text("No Tags")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pullToRefresh(isShowing: self.$liveUser.isRefreshingTags) {
|
||||||
|
self.liveUser.refreshTags()
|
||||||
|
}
|
||||||
|
.navigationBarTitle(Text("Tags 🎷"))
|
||||||
|
.navigationBarItems(
|
||||||
|
leading:
|
||||||
|
EditButton(),
|
||||||
|
|
||||||
|
trailing:
|
||||||
|
Button(
|
||||||
|
action: { self.showAdd = true },
|
||||||
|
label: { Text("Add") }
|
||||||
|
).sheet(isPresented: $showAdd) {
|
||||||
|
AddTagSheet(tags: self.$liveUser.tags, username: self.$liveUser.username)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TagList_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
TagList()
|
||||||
|
}
|
||||||
|
}
|
@ -12,24 +12,37 @@ import SwiftyJSON
|
|||||||
struct TagRow: View {
|
struct TagRow: View {
|
||||||
|
|
||||||
@Binding var tag: Tag
|
@Binding var tag: Tag
|
||||||
|
@State private var showingNetworkError = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationLink(destination: TagView(tag: $tag)){
|
NavigationLink(destination: TagView(tag: $tag)){
|
||||||
HStack {
|
HStack {
|
||||||
Text(tag.name)
|
Text(tag.name)
|
||||||
.contextMenu {
|
if tag.count > 0 {
|
||||||
|
Spacer()
|
||||||
// run force touch
|
Text("\(tag.count)")
|
||||||
Button(action: {
|
.foregroundColor(.gray)
|
||||||
let api = TagApi.runTag(tag_id: self.tag.tag_id)
|
}
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
}.contextMenu {
|
||||||
|
Button(action: {
|
||||||
|
let api = TagApi.runTag(tag_id: self.tag.tag_id)
|
||||||
|
RequestBuilder.buildRequest(apiRequest: api)
|
||||||
|
.validate()
|
||||||
|
.responseJSON{ response in
|
||||||
|
switch response.result {
|
||||||
|
case .success:
|
||||||
|
break
|
||||||
|
case .failure:
|
||||||
|
self.showingNetworkError = true
|
||||||
}
|
}
|
||||||
}) {
|
|
||||||
Text("Refresh")
|
|
||||||
Image(systemName: "arrow.clockwise.circle")
|
|
||||||
}
|
}
|
||||||
}
|
}) {
|
||||||
|
Text("Refresh")
|
||||||
|
Image(systemName: "arrow.clockwise.circle")
|
||||||
|
}
|
||||||
|
}.alert(isPresented: $showingNetworkError) {
|
||||||
|
Alert(title: Text("Network Error"),
|
||||||
|
message: Text("Could not refresh tag"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ struct TagView: View {
|
|||||||
.foregroundColor(Color.gray)
|
.foregroundColor(Color.gray)
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Text("User Total")
|
Text("Total")
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("\(self.tag.total_user_scrobbles)")
|
Text("\(self.tag.total_user_scrobbles)")
|
||||||
.font(.title)
|
.font(.title)
|
||||||
|
Loading…
Reference in New Issue
Block a user