added last.fm stats, fixed loading wheel states, added placeholder messages

This commit is contained in:
aj 2020-03-07 18:51:52 +00:00
parent d012566f04
commit 5d6a5cff1c
9 changed files with 187 additions and 56 deletions

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
E906F7F42414019C004E1E31 /* NetworkPersister.swift in Sources */ = {isa = PBXBuildFile; fileRef = E906F7F32414019C004E1E31 /* NetworkPersister.swift */; };
E92F94822401412100B6B721 /* SwiftUIRefresh in Frameworks */ = {isa = PBXBuildFile; productRef = E92F94812401412100B6B721 /* SwiftUIRefresh */; };
E934AC99240DD0E4009869F4 /* AddTagSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = E934AC98240DD0E4009869F4 /* AddTagSheet.swift */; };
E97AF45623FC4E7800635494 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = E97AF45523FC4E7800635494 /* User.swift */; };
@ -59,6 +60,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
E906F7F32414019C004E1E31 /* NetworkPersister.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkPersister.swift; sourceTree = "<group>"; };
E934AC98240DD0E4009869F4 /* AddTagSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTagSheet.swift; sourceTree = "<group>"; };
E97AF45523FC4E7800635494 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
E97AF45A23FC748D00635494 /* UserApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserApi.swift; sourceTree = "<group>"; };
@ -150,6 +152,7 @@
E97AF45F23FC85D600635494 /* PlaylistApi.swift */,
E97AF45A23FC748D00635494 /* UserApi.swift */,
E9E30C2523FEA4EF00574EEF /* TagApi.swift */,
E906F7F32414019C004E1E31 /* NetworkPersister.swift */,
);
path = Network;
sourceTree = "<group>";
@ -418,6 +421,7 @@
E9E30C3123FEAF2B00574EEF /* TagObjList.swift in Sources */,
E98254CA23FA26600056D9D3 /* PlaylistRow.swift in Sources */,
E9EA690B23F9A5430012C3E8 /* AppDelegate.swift in Sources */,
E906F7F42414019C004E1E31 /* NetworkPersister.swift in Sources */,
E9E30C3323FF255C00574EEF /* SettingsList.swift in Sources */,
E9EA690D23F9A5430012C3E8 /* SceneDelegate.swift in Sources */,
E98254DB23FB64740056D9D3 /* Network.swift in Sources */,

View File

@ -16,6 +16,9 @@ class LiveUser: ObservableObject {
@Published var tags: [Tag]
@Published var username: String
@Published var isRefreshingPlaylists = false
@Published var isRefreshingTags = false
init(playlists: [Playlist], tags: [Tag], username: String) {
self.playlists = playlists
self.tags = tags
@ -30,6 +33,8 @@ class LiveUser: ObservableObject {
}
func refreshPlaylists() {
self.isRefreshingPlaylists = true
let api = PlaylistApi.getPlaylists
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
@ -46,6 +51,8 @@ class LiveUser: ObservableObject {
// update state
self.playlists = PlaylistApi.fromJSON(playlist: playlists).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
self.isRefreshingPlaylists = false
let encoder = JSONEncoder()
let defaults = UserDefaults.standard
do {
@ -57,6 +64,8 @@ class LiveUser: ObservableObject {
}
func refreshTags() {
self.isRefreshingTags = true
let api = TagApi.getTags
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
@ -73,6 +82,8 @@ class LiveUser: ObservableObject {
// update state
self.tags = TagApi.fromJSON(tag: tags).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
self.isRefreshingTags = false
let encoder = JSONEncoder()
let defaults = UserDefaults.standard
do {

View File

@ -37,8 +37,23 @@ class Playlist: Identifiable, Equatable, Codable {
var lastfm_stat_artist_count: Int
var lastfm_stat_percent: Float
var lastfm_stat_percent_str: String {
get {
return String(format: "%.2f%%", lastfm_stat_percent)
}
}
var lastfm_stat_album_percent: Float
var lastfm_stat_album_percent_str: String {
get {
return String(format: "%.2f%%", lastfm_stat_album_percent)
}
}
var lastfm_stat_artist_percent: Float
var lastfm_stat_artist_percent_str: String {
get {
return String(format: "%.2f%%", lastfm_stat_artist_percent)
}
}
var lastfm_stat_last_refresh: String

View File

@ -0,0 +1,34 @@
//
// NetWorkPersister.swift
// Music Tools
//
// Created by Andy Pack on 07/03/2020.
// Copyright © 2020 Sarsoo. All rights reserved.
//
import Foundation
@propertyWrapper
struct NetworkPersister<Value: Codable>: Codable {
enum ObjectType: String, Codable {
case playlist
case tag
case user
}
var objType: ObjectType
var key: String
//
// init(_ objType: ObjectType, key: String) {
// self.objType = objType
// self.key = key
// }
var wrappedValue: Value {
didSet {
print("set")
}
}
}

View File

@ -8,29 +8,39 @@
import SwiftUI
struct Name: Identifiable {
struct Name: Identifiable, Hashable {
var id = UUID()
var name: String
}
struct PlaylistInputList: View {
var names: Array<Name> = []
var names: Array<String> = []
var nameType: String
init(names: Array<String>, nameType: String){
self.nameType = nameType
self.names = names.map { (name) -> Name in
return Name(name: name)
}.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
self.names = names.sorted(by: { $0.lowercased() < $1.lowercased() })
}
var body: some View {
return List(names) { name in
Text(name.name)
List{
Section(header: Image(systemName: "music.note")){ // Weird? added empty header as list renders with space for header then jumps up, not nice
if self.names.count > 0 {
ForEach(self.names, id: \.self){ name in
Text(name)
}
}else {
HStack {
Text("No Playlists")
.multilineTextAlignment(.center)
Spacer()
}
}
}
}
.navigationBarTitle(Text(nameType))
// .id(UUID())
.navigationBarTitle(nameType)
.navigationBarItems(trailing:
Button(
action: { },

View File

@ -27,6 +27,38 @@ struct PlaylistView: View {
var body: some View {
List {
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)
}
}
Section(header: Text("Options")){
Toggle(isOn: self.$playlist.include_recommendations) {
Text("Spotify Recommendations")
@ -110,7 +142,11 @@ struct PlaylistView: View {
}
}
}
Section(header: Text("Actions")){
Section(header: Text("Actions"),
footer: VStack(alignment: .leading) {
Text("Last Updated \(self.playlist.last_updated)")
Text("Stats Updated \(self.playlist.lastfm_stat_last_refresh)")
}){
Button(action: { self.runPlaylist() }) {
Text("Update")
}
@ -119,11 +155,11 @@ struct PlaylistView: View {
Text("Open")
}
}
}
}.listStyle(GroupedListStyle())
.pullToRefresh(isShowing: $isRefreshing) {
self.refreshPlaylist()
}
.navigationBarTitle(Text(playlist.name))
.navigationBarTitle(playlist.name)
.onAppear {
// TODO are these binding properly?

View File

@ -19,33 +19,37 @@ struct RootView: View {
@State private var showAdd = false // State for showing add modal view
@State private var isRefreshingPlaylists = false
@State private var isRefreshingTags = false
var body: some View {
TabView {
// PLAYLISTS
NavigationView {
List{
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
}
if(liveUser.playlists.count > 0){
ForEach(liveUser.playlists.indices, id:\.self) { idx in
PlaylistRow(playlist: self.$liveUser.playlists[idx])
}
.onDelete { indexSet in
self.liveUser.playlists.remove(atOffsets: indexSet)
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: $isRefreshingPlaylists) {
.pullToRefresh(isShowing: self.$liveUser.isRefreshingPlaylists) {
self.liveUser.refreshPlaylists()
self.isRefreshingPlaylists = false
}
.navigationBarTitle(Text("Playlists").font(.title))
@ -70,24 +74,31 @@ struct RootView: View {
// TAGS
NavigationView {
List{
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
}
if(liveUser.tags.count > 0) {
ForEach(liveUser.tags.indices, id:\.self) { idx in
TagRow(tag: self.$liveUser.tags[idx])
}
.onDelete { indexSet in
self.liveUser.tags.remove(atOffsets: indexSet)
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: $isRefreshingTags) {
.pullToRefresh(isShowing: self.$liveUser.isRefreshingTags) {
self.liveUser.refreshTags()
self.isRefreshingTags = false
}
.navigationBarTitle(Text("Tags").font(.title))

View File

@ -37,20 +37,30 @@ struct TagObjList: View {
}
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)
List {
Section(header: Image(systemName: "music.note")) {
if self.objs.count > 0 {
ForEach(objs) { obj in
HStack {
VStack(alignment: .leading){
Text(obj.name)
if obj.artist.count > 0 {
Text(obj.artist)
.foregroundColor(Color.gray)
}
}
Spacer()
Text("\(obj.count)")
.foregroundColor(Color.gray)
}
}
}else {
HStack {
Text("No Entries")
.multilineTextAlignment(.center)
Spacer()
}
}
Spacer()
Text("\(obj.count)")
.foregroundColor(Color.gray)
}
}
.navigationBarTitle(Text(objType))

View File

@ -77,7 +77,7 @@ struct TagView: View {
Text("Update")
}
}
}
}.listStyle(GroupedListStyle())
.pullToRefresh(isShowing: $isRefreshing) {
self.refreshTag()
}