added pull to refresh, moved playlist and tag reference to environment object, added get playlist

This commit is contained in:
aj 2020-02-22 13:28:15 +00:00
parent 54a3806908
commit fea9e3f84b
7 changed files with 147 additions and 29 deletions

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
E92F94822401412100B6B721 /* SwiftUIRefresh in Frameworks */ = {isa = PBXBuildFile; productRef = E92F94812401412100B6B721 /* SwiftUIRefresh */; };
E97AF45623FC4E7800635494 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = E97AF45523FC4E7800635494 /* User.swift */; };
E97AF45923FC50EC00635494 /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = E97AF45823FC50EC00635494 /* SwiftyJSON */; };
E97AF45B23FC748D00635494 /* UserApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = E97AF45A23FC748D00635494 /* UserApi.swift */; };
@ -97,6 +98,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
E92F94822401412100B6B721 /* SwiftUIRefresh in Frameworks */,
E97AF45923FC50EC00635494 /* SwiftyJSON in Frameworks */,
E98254D923FB53780056D9D3 /* Alamofire in Frameworks */,
E97AF45E23FC83AF00635494 /* KeychainAccess in Frameworks */,
@ -225,14 +227,14 @@
E9EA690923F9A5430012C3E8 /* Music Tools */ = {
isa = PBXGroup;
children = (
E97AF46A23FDA8ED00635494 /* Controller */,
E98254C623FA25280056D9D3 /* Application */,
E98254C023F9FFDD0056D9D3 /* Views */,
E98254BF23F9BE040056D9D3 /* Network */,
E98254BE23F9BD540056D9D3 /* Model */,
E9EA691023F9A54A0012C3E8 /* Assets.xcassets */,
E97AF46A23FDA8ED00635494 /* Controller */,
E9EA691823F9A54B0012C3E8 /* Info.plist */,
E98254BE23F9BD540056D9D3 /* Model */,
E98254BF23F9BE040056D9D3 /* Network */,
E9EA691223F9A54B0012C3E8 /* Preview Content */,
E98254C023F9FFDD0056D9D3 /* Views */,
);
path = "Music Tools";
sourceTree = "<group>";
@ -283,6 +285,7 @@
E98254D823FB53780056D9D3 /* Alamofire */,
E97AF45823FC50EC00635494 /* SwiftyJSON */,
E97AF45D23FC83AF00635494 /* KeychainAccess */,
E92F94812401412100B6B721 /* SwiftUIRefresh */,
);
productName = "Music Tools";
productReference = E9EA690723F9A5430012C3E8 /* Music Tools.app */;
@ -360,6 +363,7 @@
E98254D723FB53770056D9D3 /* XCRemoteSwiftPackageReference "alamofire" */,
E97AF45723FC50EC00635494 /* XCRemoteSwiftPackageReference "swiftyjson" */,
E97AF45C23FC83AF00635494 /* XCRemoteSwiftPackageReference "keychainaccess" */,
E92F94802401412100B6B721 /* XCRemoteSwiftPackageReference "swiftuirefresh" */,
);
productRefGroup = E9EA690823F9A5430012C3E8 /* Products */;
projectDirPath = "";
@ -752,6 +756,14 @@
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
E92F94802401412100B6B721 /* XCRemoteSwiftPackageReference "swiftuirefresh" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/siteline/swiftuirefresh";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.0.2;
};
};
E97AF45723FC50EC00635494 /* XCRemoteSwiftPackageReference "swiftyjson" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/swiftyjson/swiftyjson";
@ -779,6 +791,11 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
E92F94812401412100B6B721 /* SwiftUIRefresh */ = {
isa = XCSwiftPackageProductDependency;
package = E92F94802401412100B6B721 /* XCRemoteSwiftPackageReference "swiftuirefresh" */;
productName = SwiftUIRefresh;
};
E97AF45823FC50EC00635494 /* SwiftyJSON */ = {
isa = XCSwiftPackageProductDependency;
package = E97AF45723FC50EC00635494 /* XCRemoteSwiftPackageReference "swiftyjson" */;

View File

@ -19,6 +19,24 @@
"version": "4.1.0"
}
},
{
"package": "Introspect",
"repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git",
"state": {
"branch": null,
"revision": "de5c32c15ae169cfcb27397ffb2734dcd0e1e6d5",
"version": "0.1.0"
}
},
{
"package": "SwiftUIRefresh",
"repositoryURL": "https://github.com/siteline/swiftuirefresh",
"state": {
"branch": null,
"revision": "6939ec13efa866eb9f556f5de7f0e06f5d7f2761",
"version": "0.0.2"
}
},
{
"package": "SwiftyJSON",
"repositoryURL": "https://github.com/swiftyjson/swiftyjson",

View File

@ -33,6 +33,9 @@
<rect key="frame" x="196" y="633" width="120" height="53"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle0"/>
<state key="normal" title="Register"/>
<connections>
<segue destination="TND-IP-OdM" kind="show" id="96d-mV-baq"/>
</connections>
</button>
</subviews>
<constraints>
@ -57,11 +60,12 @@
<objects>
<viewController id="TND-IP-OdM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="MhD-yZ-pD8">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="VLy-9d-bfF"/>
</view>
<navigationItem key="navigationItem" id="ols-n0-cLe"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Dgg-BJ-VHU" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
@ -102,7 +106,7 @@
<constraint firstAttribute="height" constant="34" id="ynd-9a-coG"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" returnKeyType="go" textContentType="password"/>
<textInputTraits key="textInputTraits" returnKeyType="go" secureTextEntry="YES" textContentType="password"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6YH-OC-12B">
<rect key="frame" x="185.5" y="712" width="43" height="53"/>

View File

@ -9,11 +9,19 @@
import Foundation
class LiveUser: ObservableObject {
var playlists: [Playlist]
var tags: [Tag]
@Published var playlists: [Playlist]
@Published var tags: [Tag]
init(playlists: [Playlist], tags: [Tag]) {
self.playlists = playlists
self.tags = tags
}
func updatePlaylist(playlistIn: Playlist) {
guard let index = self.playlists.firstIndex(of: playlistIn) else {
fatalError("\(playlistIn) not found")
}
self.playlists[index] = playlistIn
}
}

View File

@ -24,6 +24,7 @@ public enum PlaylistApi {
case updatePlaylist(name: String, updates: JSON)
case deletePlaylist(name: String)
case newPlaylist(name: String, type: PlaylistType)
case getPlaylist(name: String)
}
extension PlaylistApi: ApiRequest {
@ -43,6 +44,8 @@ extension PlaylistApi: ApiRequest {
return "api/playlist"
case .newPlaylist:
return "api/playlist"
case .getPlaylist:
return "api/playlist"
}
}
@ -58,6 +61,8 @@ extension PlaylistApi: ApiRequest {
return .delete
case .newPlaylist:
return .put
case .getPlaylist:
return .get
}
}
@ -75,6 +80,8 @@ extension PlaylistApi: ApiRequest {
return JSON(["name": name])
case .newPlaylist(let name, let type):
return JSON(["name": name, "type": txTypeHeaders[type.rawValue]])
case .getPlaylist(let name):
return JSON(["name": name])
}
}
@ -90,6 +97,8 @@ extension PlaylistApi: ApiRequest {
return URLEncodedFormParameterEncoder()
case .newPlaylist:
return JSONParameterEncoder.default
case .getPlaylist:
return URLEncodedFormParameterEncoder()
}
}

View File

@ -7,10 +7,28 @@
//
import SwiftUI
//import SwiftUIRefresh
import SwiftyJSON
final class ChangeableBool: ObservableObject {
var onClick: () -> ()
init(onClick: @escaping () -> ()) {
self.onClick = onClick
}
@Published var state: Bool = false {
didSet {
self.onClick()
}
}
}
struct PlaylistView: View {
@EnvironmentObject var liveUser: LiveUser
init(playlist: Playlist) {
self.playlist = playlist
@ -25,6 +43,8 @@ struct PlaylistView: View {
@State private var rec_num: Int = 0
@State private var isRefreshing = false
var body: some View {
List {
Section(header: Text("Options")){
@ -87,6 +107,9 @@ struct PlaylistView: View {
}
}
}
// .pullToRefresh(isShowing: $isRefreshing) {
// self.refreshPlaylist()
// }
.navigationBarTitle(Text(playlist.name))
.onAppear {
self.$recommendations.wrappedValue = self.playlist.include_recommendations
@ -114,7 +137,31 @@ struct PlaylistView: View {
func updatePlaylist(updates: JSON) {
let api = PlaylistApi.updatePlaylist(name: playlist.name, updates: updates)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
switch response.result {
case .success:
debugPrint("success")
case .failure:
debugPrint("error")
}
}
//TODO: do better error checking
}
func refreshPlaylist(updates: JSON) {
let api = PlaylistApi.getPlaylist(name: self.playlist.name)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
guard let data = response.data else {
fatalError("error getting playlist")
}
guard let json = try? JSON(data: data) else {
fatalError("error parsing reponse")
}
// let playlist = Playlist.fromDict(json["playlist"])
//
// self.playlist = playlist
// self.isRefreshing = false
}
//TODO: do better error checking
}

View File

@ -7,6 +7,7 @@
//
import SwiftUI
import SwiftUIRefresh
import Alamofire
import SwiftyJSON
@ -15,16 +16,17 @@ struct RootView: View {
@EnvironmentObject var liveUser: LiveUser
@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 showAdd = false // State for showing add modal view
@State private var justDeletedPlaylists: Array<Playlist> = [] // Cache of recently deleted playlists for removing from next net request
@State private var justDeletedTags: Array<Tag> = []
@State private var isRefreshingPlaylists = false
@State private var isRefreshingTags = false
// refresh playlist list on interval
let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
// let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
var body: some View {
TabView {
@ -32,24 +34,27 @@ struct RootView: View {
// PLAYLISTS
NavigationView {
List{
ForEach(playlists) { playlist in
ForEach(liveUser.playlists) { playlist in
PlaylistRow(playlist: playlist)
}
.onDelete { indexSet in
indexSet.forEach { index in
// add to recently deleted playlist cache
self.justDeletedPlaylists.append(self.playlists[index])
self.justDeletedPlaylists.append(self.liveUser.playlists[index])
let api = PlaylistApi.deletePlaylist(name: self.playlists[index].name)
let api = PlaylistApi.deletePlaylist(name: self.liveUser.playlists[index].name)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
}
}
self.playlists.remove(atOffsets: indexSet)
self.liveUser.playlists.remove(atOffsets: indexSet)
}
}
.pullToRefresh(isShowing: $isRefreshingPlaylists) {
self.refreshPlaylists()
}
.navigationBarTitle(Text("Playlists").font(.title))
// add playlist button
@ -58,7 +63,7 @@ struct RootView: View {
action: { self.showAdd = true },
label: { Text("Add") }
).sheet(isPresented: $showAdd) {
AddPlaylistSheet(state: self.$showAdd, playlists: self.$playlists)
AddPlaylistSheet(state: self.$showAdd, playlists: self.$liveUser.playlists)
}
)
}
@ -73,24 +78,27 @@ struct RootView: View {
// TAGS
NavigationView {
List{
ForEach(tags) { tag in
ForEach(liveUser.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])
self.justDeletedTags.append(self.liveUser.tags[index])
let api = TagApi.deleteTag(tag_id: self.tags[index].tag_id)
let api = TagApi.deleteTag(tag_id: self.liveUser.tags[index].tag_id)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
}
}
self.tags.remove(atOffsets: indexSet)
self.liveUser.tags.remove(atOffsets: indexSet)
}
}
.pullToRefresh(isShowing: $isRefreshingTags) {
self.refreshTags()
}
.navigationBarTitle(Text("Tags").font(.title))
// add playlist button
@ -99,7 +107,7 @@ struct RootView: View {
action: { self.showAdd = true },
label: { Text("Add") }
).sheet(isPresented: $showAdd) {
AddPlaylistSheet(state: self.$showAdd, playlists: self.$playlists)
AddPlaylistSheet(state: self.$showAdd, playlists: self.$liveUser.playlists)
}
)
}
@ -122,15 +130,20 @@ struct RootView: View {
}
}
.tag(2)
.onReceive(timer) { _ in
self.fetch()
}
// .onReceive(timer) { _ in
// self.fetch()
// }
}.onAppear {
self.fetch()
self.fetchAll()
}
}
private func fetch() {
private func fetchAll() {
refreshPlaylists()
refreshTags()
}
func refreshPlaylists() {
let api = PlaylistApi.getPlaylists
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
@ -165,10 +178,12 @@ struct RootView: View {
// update state
self.liveUser.playlists = playlists
self.playlists = self.liveUser.playlists
self.isRefreshingPlaylists = false
}
//TODO: do better error checking
}
func refreshTags() {
let tagApi = TagApi.getTags
RequestBuilder.buildRequest(apiRequest: tagApi).responseJSON{ response in
@ -203,7 +218,7 @@ struct RootView: View {
// update state
self.liveUser.tags = tags
self.tags = self.liveUser.tags
self.isRefreshingTags = false
}
}
}