no chart padding, no charts when no last.fm, rename, closes #20

This commit is contained in:
andy 2022-08-13 22:07:59 +01:00
parent 702d9b1733
commit a8842eefc7
15 changed files with 195 additions and 111 deletions

View File

@ -27,7 +27,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let liveUser = LiveUser(playlists: [], tags: [], username: keychain["username"] ?? "", loggedIn: false).loadUserDefaults()
let liveUser = LiveUser(playlists: [], tags: [], username: keychain["username"] ?? "", loggedIn: false).load_user_defaults()
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(liveUser))
self.window = window

View File

@ -43,6 +43,16 @@ class LiveUser: ObservableObject {
self.user = user
}
func lastfm_connected() -> Bool {
if let username = user?.lastfm_username {
if username.count > 0 {
return true
}
}
return false
}
func logout() {
let keychain = Keychain(service: "xyz.sarsoo.music.login")
@ -65,20 +75,20 @@ class LiveUser: ObservableObject {
}
}
func updatePlaylist(playlistIn: Playlist) {
func update_playlist(playlistIn: Playlist) {
guard let index = self.playlists.firstIndex(of: playlistIn) else {
fatalError("\(playlistIn) not found")
}
self.playlists[index] = playlistIn
}
func refreshUser(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
func refresh_user(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
self.isRefreshingUser = true
let api = UserApi.getUser
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.checkNetworkResponse(response: response) {
if self.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting user")
@ -106,13 +116,13 @@ class LiveUser: ObservableObject {
}
}
func refreshPlaylists(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
func refresh_playlists(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
self.isRefreshingPlaylists = true
let api = PlaylistApi.getPlaylists
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.checkNetworkResponse(response: response) {
if self.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting playlists")
@ -149,13 +159,13 @@ class LiveUser: ObservableObject {
}
}
func refreshTags(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
func refresh_tags(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
self.isRefreshingTags = true
let api = TagApi.getTags
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.checkNetworkResponse(response: response) {
if self.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting tags")
@ -192,7 +202,7 @@ class LiveUser: ObservableObject {
}
}
func checkNetworkResponse(response: AFDataResponse<Any>) -> Bool {
func check_network_response(response: AFDataResponse<Any>) -> Bool {
if let statusCode = response.response?.statusCode {
switch statusCode {
@ -211,7 +221,7 @@ class LiveUser: ObservableObject {
return false
}
func loadUserDefaults() -> LiveUser {
func load_user_defaults() -> LiveUser {
let defaults = UserDefaults.standard
let decoder = JSONDecoder()

View File

@ -26,7 +26,7 @@ class User: Identifiable, Decodable {
var last_keygen: String
var spotify_linked: Bool
var lastfm_username: String?
@Published var lastfm_username: String?
//MARK: Initialization
@ -47,6 +47,52 @@ class User: Identifiable, Decodable {
self.last_keygen = last_keygen
self.spotify_linked = spotify_linked
self.lastfm_username = lastfm_username
}
}
private enum CodingKeys: String, CodingKey {
case username
case email
case type
case last_login
case last_keygen
case spotify_linked
case lastfm_username
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
username = try container.decode(String.self, forKey: .username)
do{
email = try container.decode(String.self, forKey: .email)
}catch {
email = nil
debugPrint("failed to parse email")
}
type = try container.decode(UserType.self, forKey: .type)
last_login = try container.decode(String.self, forKey: .last_login)
last_keygen = try container.decode(String.self, forKey: .last_keygen)
spotify_linked = try container.decode(Bool.self, forKey: .spotify_linked)
lastfm_username = try container.decode(String.self, forKey: .lastfm_username)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.username, forKey: .username)
try container.encode(self.email, forKey: .email)
try container.encode(self.type.rawValue, forKey: .type)
try container.encode(self.last_login, forKey: .last_login)
try container.encode(self.last_keygen, forKey: .last_keygen)
try container.encode(self.spotify_linked, forKey: .spotify_linked)
try container.encode(self.lastfm_username, forKey: .lastfm_username)
}
}

View File

@ -69,9 +69,9 @@ struct AppSkeleton: View {
}
private func fetchAll() {
self.liveUser.refreshUser()
self.liveUser.refreshPlaylists()
self.liveUser.refreshTags()
self.liveUser.refresh_user()
self.liveUser.refresh_playlists()
self.liveUser.refresh_tags()
}
}

View File

@ -94,7 +94,7 @@ struct AddPlaylistSheet: View {
type: PlaylistType(rawValue: selectedType) ?? .defaultPlaylist)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
self.playlists.append(playlist)
self.playlists = self.playlists.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })

View File

@ -13,14 +13,21 @@ struct Name: Identifiable, Hashable {
var name: String
}
enum PlaylistInputType {
case MixonomerPlaylists
case SpotifyPlaylists
}
struct PlaylistInputList: View {
@Binding var names: [String]
var nameType: String
var type: PlaylistInputType
init(names: Binding<[String]>, nameType: String){
init(names: Binding<[String]>, nameType: String, type: PlaylistInputType){
self.nameType = nameType
self._names = names
self.type = type
}
var body: some View {
@ -41,12 +48,14 @@ struct PlaylistInputList: View {
}
// .id(UUID())
.navigationBarTitle(nameType)
.navigationBarItems(trailing:
Button(
action: { },
label: { Image(systemName: "plus.circle") }
)
)
// .navigationBarItems(trailing:
// Button(
// action: {
//
// },
// label: { Image(systemName: "plus.circle") }
// )
// )
}
}
@ -54,6 +63,6 @@ struct PlaylistInputList_Previews: PreviewProvider {
static var previews: some View {
PlaylistInputList(names: .constant([
"name"
]), nameType: "Spotify Playlists")
]), nameType: "Spotify Playlists", type: .MixonomerPlaylists)
}
}

View File

@ -42,7 +42,7 @@ struct PlaylistList: View {
let api = PlaylistApi.deletePlaylist(name: self.liveUser.playlists[index].name)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
} else {
@ -58,7 +58,7 @@ struct PlaylistList: View {
}
.refreshable
{
self.liveUser.refreshPlaylists(onSuccess: {
self.liveUser.refresh_playlists(onSuccess: {
toastText = "Refreshed!"
toastSuccess = true

View File

@ -31,7 +31,7 @@ struct PlaylistRow: View {
.validate()
.responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
}
else {

View File

@ -24,9 +24,23 @@ struct PlaylistView: View {
@State private var toastText = ""
@State private var toastSuccess = true
var chartStyle: ChartStyle {
var trackChartStyle: ChartStyle {
get {
let _style = ChartStyle(backgroundColor: .white, accentColor: .red, gradientColor: GradientColors.bluPurpl, textColor: .black, legendTextColor: .gray)
let _style = ChartStyle(backgroundColor: .white, accentColor: Color(red: 0.4765, green: 0.5976, blue: 0.7578), gradientColor: GradientColors.bluPurpl, textColor: .black, legendTextColor: .gray)
return _style
}
}
var albumChartStyle: ChartStyle {
get {
let _style = ChartStyle(backgroundColor: .white, accentColor: Color(red: 0.6367, green: 0.2968, blue: 0.4648), gradientColor: GradientColors.bluPurpl, textColor: .black, legendTextColor: .gray)
return _style
}
}
var artistChartStyle: ChartStyle {
get {
let _style = ChartStyle(backgroundColor: .white, accentColor: Color(red: 0.3476, green: 0.5195, blue: 0.3359), gradientColor: GradientColors.bluPurpl, textColor: .black, legendTextColor: .gray)
return _style
}
}
@ -35,71 +49,76 @@ struct PlaylistView: View {
var body: some View {
Form {
Section(header: Text("Stats")){
HStack {
Text("Track Count")
Spacer()
Text("\(self.playlist.lastfm_stat_count)")
.font(.title)
.foregroundColor(Color.gray)
Text("\(self.playlist.lastfm_stat_percent_str)")
.font(.body)
.foregroundColor(Color.gray)
if liveUser.lastfm_connected() {
Section(header: Text("Stats")){
HStack {
Text("Track Count")
Spacer()
Text("\(self.playlist.lastfm_stat_count)")
.font(.title)
.foregroundColor(Color.gray)
Text("\(self.playlist.lastfm_stat_percent_str)")
.font(.body)
.foregroundColor(Color.gray)
}
HStack {
Text("Album Count")
Spacer()
Text("\(self.playlist.lastfm_stat_album_count)")
.font(.title)
.foregroundColor(Color.gray)
Text("\(self.playlist.lastfm_stat_album_percent_str)")
.font(.body)
.foregroundColor(Color.gray)
}
HStack {
Text("Artist Count")
Spacer()
Text("\(self.playlist.lastfm_stat_artist_count)")
.font(.title)
.foregroundColor(Color.gray)
Text("\(self.playlist.lastfm_stat_artist_percent_str)")
.font(.body)
.foregroundColor(Color.gray)
}
Button(action: {
self.refreshStats()
}){
Text("Refresh")
}
}
HStack {
Text("Album Count")
Spacer()
Text("\(self.playlist.lastfm_stat_album_count)")
.font(.title)
.foregroundColor(Color.gray)
Text("\(self.playlist.lastfm_stat_album_percent_str)")
.font(.body)
.foregroundColor(Color.gray)
}
HStack {
Text("Artist Count")
Spacer()
Text("\(self.playlist.lastfm_stat_artist_count)")
.font(.title)
.foregroundColor(Color.gray)
Text("\(self.playlist.lastfm_stat_artist_percent_str)")
.font(.body)
.foregroundColor(Color.gray)
}
Button(action: {
self.refreshStats()
}){
Text("Refresh")
}
}
ScrollView(.horizontal){
HStack {
Spacer()
PieChartView(
data: [Double(self.playlist.lastfm_stat_percent), Double(100 - self.playlist.lastfm_stat_percent)],
title: "Tracks",
legend:"Listening",
style: chartStyle,
form: chartSize)
Spacer(minLength: 20)
PieChartView(
data: [Double(self.playlist.lastfm_stat_album_percent), Double(100 - self.playlist.lastfm_stat_album_percent)],
title: "Albums",
legend:"Listening",
style: chartStyle,
form: chartSize)
Spacer(minLength: 20)
PieChartView(
data: [Double(self.playlist.lastfm_stat_artist_percent), Double(100 - self.playlist.lastfm_stat_artist_percent)],
title: "Artists",
legend:"Listening",
style: chartStyle,
form: chartSize)
Spacer()
ScrollView(.horizontal){
HStack {
Spacer()
PieChartView(
data: [Double(self.playlist.lastfm_stat_percent), Double(100 - self.playlist.lastfm_stat_percent)],
title: "Tracks",
legend:"Listening",
style: trackChartStyle,
form: chartSize)
Spacer(minLength: 20)
PieChartView(
data: [Double(self.playlist.lastfm_stat_album_percent), Double(100 - self.playlist.lastfm_stat_album_percent)],
title: "Albums",
legend:"Listening",
style: albumChartStyle,
form: chartSize)
Spacer(minLength: 20)
PieChartView(
data: [Double(self.playlist.lastfm_stat_artist_percent), Double(100 - self.playlist.lastfm_stat_artist_percent)],
title: "Artists",
legend:"Listening",
style: artistChartStyle,
form: chartSize)
Spacer()
}
.padding([.vertical], 20)
.padding([.horizontal], 10)
}
.padding([.vertical], 20)
.padding([.horizontal], 10)
.listRowInsets(EdgeInsets())
}
Section(header: Text("Options")){
@ -168,7 +187,7 @@ struct PlaylistView: View {
}
}
Section(header: Text("Inputs")){
NavigationLink(destination: PlaylistInputList(names: self.$playlist.playlist_references, nameType: "Managed Playlists")) {
NavigationLink(destination: PlaylistInputList(names: self.$playlist.playlist_references, nameType: "Managed Playlists", type: .MixonomerPlaylists)) {
HStack {
Text("Managed Playlists")
Spacer()
@ -177,7 +196,7 @@ struct PlaylistView: View {
}
}
NavigationLink(destination: PlaylistInputList(names: self.$playlist.parts, nameType: "Spotify Playlists")) {
NavigationLink(destination: PlaylistInputList(names: self.$playlist.parts, nameType: "Spotify Playlists", type: .SpotifyPlaylists)) {
HStack {
Text("Spotify Playlists")
Spacer()
@ -225,7 +244,7 @@ struct PlaylistView: View {
.validate()
.responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
toastText = "Running!"
toastSuccess = true
@ -244,7 +263,7 @@ struct PlaylistView: View {
let api = PlaylistApi.refreshStats(name: playlist.name)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
toastText = "Refreshing Stats!"
toastSuccess = true
@ -270,7 +289,7 @@ struct PlaylistView: View {
let api = PlaylistApi.updatePlaylist(name: playlist.name, updates: updates)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
debugPrint("success")
} else {
debugPrint("error")
@ -283,7 +302,7 @@ struct PlaylistView: View {
let api = PlaylistApi.getPlaylist(name: self.playlist.name)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting playlist")

View File

@ -53,7 +53,7 @@ struct SettingsList: View {
let api = UserApi.deleteUser
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
self.liveUser.logout()
}

View File

@ -76,7 +76,7 @@ struct AddTagSheet: View {
let api = TagApi.newTag(tag_id: tag_id)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
self.tags.append(tag)
self.tags = self.tags.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })

View File

@ -31,7 +31,7 @@ struct TagList: View {
let api = TagApi.deleteTag(tag_id: self.liveUser.tags[index].tag_id)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
}
else {
@ -47,7 +47,7 @@ struct TagList: View {
}
}
.refreshable {
self.liveUser.refreshTags(onSuccess: {
self.liveUser.refresh_tags(onSuccess: {
toastText = "Refreshed!"
toastSuccess = true

View File

@ -64,12 +64,12 @@ struct TagObjList: View {
}
}
.navigationBarTitle(Text(objType))
.navigationBarItems(trailing:
Button(
action: { },
label: { Image(systemName: "plus.circle") }
)
)
// .navigationBarItems(trailing:
// Button(
// action: { },
// label: { Image(systemName: "plus.circle") }
// )
// )
}
}

View File

@ -31,7 +31,7 @@ struct TagRow: View {
.validate()
.responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
} else {
self.showingNetworkError = true

View File

@ -120,7 +120,7 @@ struct TagView: View {
let api = TagApi.runTag(tag_id: tag.tag_id)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
} else {
@ -133,7 +133,7 @@ struct TagView: View {
let api = TagApi.updateTag(tag_id: tag.tag_id, updates: updates)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
} else {
@ -146,7 +146,7 @@ struct TagView: View {
let api = TagApi.getTag(tag_id: self.tag.tag_id)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.checkNetworkResponse(response: response) {
if self.liveUser.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting tag")