initial notifications support
This commit is contained in:
parent
a3b1a67b5b
commit
8f103fab3e
@ -10,6 +10,10 @@
|
|||||||
A10C8D29281302050018AE12 /* ToastUI in Frameworks */ = {isa = PBXBuildFile; productRef = A10C8D28281302050018AE12 /* ToastUI */; };
|
A10C8D29281302050018AE12 /* ToastUI in Frameworks */ = {isa = PBXBuildFile; productRef = A10C8D28281302050018AE12 /* ToastUI */; };
|
||||||
A11AC70628A188AE00645043 /* AuthApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11AC70528A188AE00645043 /* AuthApi.swift */; };
|
A11AC70628A188AE00645043 /* AuthApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11AC70528A188AE00645043 /* AuthApi.swift */; };
|
||||||
A13C54972928FD7C0034F233 /* ManagedInputList.swift in Sources */ = {isa = PBXBuildFile; fileRef = A13C54962928FD7C0034F233 /* ManagedInputList.swift */; };
|
A13C54972928FD7C0034F233 /* ManagedInputList.swift in Sources */ = {isa = PBXBuildFile; fileRef = A13C54962928FD7C0034F233 /* ManagedInputList.swift */; };
|
||||||
|
A15D257A293421350049055E /* StaticNotif.swift in Sources */ = {isa = PBXBuildFile; fileRef = A15D2579293421350049055E /* StaticNotif.swift */; };
|
||||||
|
A15D257C293425390049055E /* NotificationsControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = A15D257B293425390049055E /* NotificationsControls.swift */; };
|
||||||
|
A15D257E29342E4F0049055E /* APNSHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A15D257D29342E4F0049055E /* APNSHandler.swift */; };
|
||||||
|
A15D258029342EF50049055E /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A15D257F29342EF50049055E /* NetworkHelper.swift */; };
|
||||||
A1AF726F28A84F7D00D317C9 /* AdminApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF726E28A84F7D00D317C9 /* AdminApi.swift */; };
|
A1AF726F28A84F7D00D317C9 /* AdminApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF726E28A84F7D00D317C9 /* AdminApi.swift */; };
|
||||||
A1AF727128A850AE00D317C9 /* UsersList.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF727028A850AE00D317C9 /* UsersList.swift */; };
|
A1AF727128A850AE00D317C9 /* UsersList.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF727028A850AE00D317C9 /* UsersList.swift */; };
|
||||||
A1AF727328A9062600D317C9 /* UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF727228A9062600D317C9 /* UserView.swift */; };
|
A1AF727328A9062600D317C9 /* UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF727228A9062600D317C9 /* UserView.swift */; };
|
||||||
@ -71,6 +75,10 @@
|
|||||||
A11AC70528A188AE00645043 /* AuthApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthApi.swift; sourceTree = "<group>"; };
|
A11AC70528A188AE00645043 /* AuthApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthApi.swift; sourceTree = "<group>"; };
|
||||||
A13C54962928FD7C0034F233 /* ManagedInputList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedInputList.swift; sourceTree = "<group>"; };
|
A13C54962928FD7C0034F233 /* ManagedInputList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedInputList.swift; sourceTree = "<group>"; };
|
||||||
A146915A28118F940052999D /* Mixonomer.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Mixonomer.entitlements; sourceTree = "<group>"; };
|
A146915A28118F940052999D /* Mixonomer.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Mixonomer.entitlements; sourceTree = "<group>"; };
|
||||||
|
A15D2579293421350049055E /* StaticNotif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticNotif.swift; sourceTree = "<group>"; };
|
||||||
|
A15D257B293425390049055E /* NotificationsControls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsControls.swift; sourceTree = "<group>"; };
|
||||||
|
A15D257D29342E4F0049055E /* APNSHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APNSHandler.swift; sourceTree = "<group>"; };
|
||||||
|
A15D257F29342EF50049055E /* NetworkHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkHelper.swift; sourceTree = "<group>"; };
|
||||||
A1AF726E28A84F7D00D317C9 /* AdminApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminApi.swift; sourceTree = "<group>"; };
|
A1AF726E28A84F7D00D317C9 /* AdminApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminApi.swift; sourceTree = "<group>"; };
|
||||||
A1AF727028A850AE00D317C9 /* UsersList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersList.swift; sourceTree = "<group>"; };
|
A1AF727028A850AE00D317C9 /* UsersList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersList.swift; sourceTree = "<group>"; };
|
||||||
A1AF727228A9062600D317C9 /* UserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserView.swift; sourceTree = "<group>"; };
|
A1AF727228A9062600D317C9 /* UserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserView.swift; sourceTree = "<group>"; };
|
||||||
@ -143,6 +151,15 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
A15D2578293421250049055E /* Notifications */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A15D2579293421350049055E /* StaticNotif.swift */,
|
||||||
|
A15D257D29342E4F0049055E /* APNSHandler.swift */,
|
||||||
|
);
|
||||||
|
path = Notifications;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A1DBCDA428A5184D002CF730 /* Admin */ = {
|
A1DBCDA428A5184D002CF730 /* Admin */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -171,9 +188,10 @@
|
|||||||
E97AF45F23FC85D600635494 /* PlaylistApi.swift */,
|
E97AF45F23FC85D600635494 /* PlaylistApi.swift */,
|
||||||
E97AF45A23FC748D00635494 /* UserApi.swift */,
|
E97AF45A23FC748D00635494 /* UserApi.swift */,
|
||||||
E9E30C2523FEA4EF00574EEF /* TagApi.swift */,
|
E9E30C2523FEA4EF00574EEF /* TagApi.swift */,
|
||||||
E906F7F32414019C004E1E31 /* NetworkPersister.swift */,
|
|
||||||
A11AC70528A188AE00645043 /* AuthApi.swift */,
|
A11AC70528A188AE00645043 /* AuthApi.swift */,
|
||||||
A1AF726E28A84F7D00D317C9 /* AdminApi.swift */,
|
A1AF726E28A84F7D00D317C9 /* AdminApi.swift */,
|
||||||
|
E906F7F32414019C004E1E31 /* NetworkPersister.swift */,
|
||||||
|
A15D257F29342EF50049055E /* NetworkHelper.swift */,
|
||||||
);
|
);
|
||||||
path = Network;
|
path = Network;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -230,6 +248,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E9E30C3223FF255C00574EEF /* SettingsList.swift */,
|
E9E30C3223FF255C00574EEF /* SettingsList.swift */,
|
||||||
|
A15D257B293425390049055E /* NotificationsControls.swift */,
|
||||||
);
|
);
|
||||||
path = Settings;
|
path = Settings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -257,6 +276,7 @@
|
|||||||
E9EA690923F9A5430012C3E8 /* Mixonomer */ = {
|
E9EA690923F9A5430012C3E8 /* Mixonomer */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
A15D2578293421250049055E /* Notifications */,
|
||||||
A146915A28118F940052999D /* Mixonomer.entitlements */,
|
A146915A28118F940052999D /* Mixonomer.entitlements */,
|
||||||
E98254C623FA25280056D9D3 /* Application */,
|
E98254C623FA25280056D9D3 /* Application */,
|
||||||
E9EA691023F9A54A0012C3E8 /* Assets.xcassets */,
|
E9EA691023F9A54A0012C3E8 /* Assets.xcassets */,
|
||||||
@ -448,6 +468,7 @@
|
|||||||
E98254CA23FA26600056D9D3 /* PlaylistRow.swift in Sources */,
|
E98254CA23FA26600056D9D3 /* PlaylistRow.swift in Sources */,
|
||||||
E9EA690B23F9A5430012C3E8 /* AppDelegate.swift in Sources */,
|
E9EA690B23F9A5430012C3E8 /* AppDelegate.swift in Sources */,
|
||||||
E906F7F42414019C004E1E31 /* NetworkPersister.swift in Sources */,
|
E906F7F42414019C004E1E31 /* NetworkPersister.swift in Sources */,
|
||||||
|
A15D258029342EF50049055E /* NetworkHelper.swift in Sources */,
|
||||||
A1AF727328A9062600D317C9 /* UserView.swift in Sources */,
|
A1AF727328A9062600D317C9 /* UserView.swift in Sources */,
|
||||||
E9E30C3323FF255C00574EEF /* SettingsList.swift in Sources */,
|
E9E30C3323FF255C00574EEF /* SettingsList.swift in Sources */,
|
||||||
E9EA690D23F9A5430012C3E8 /* SceneDelegate.swift in Sources */,
|
E9EA690D23F9A5430012C3E8 /* SceneDelegate.swift in Sources */,
|
||||||
@ -459,8 +480,10 @@
|
|||||||
E97AF46023FC85D600635494 /* PlaylistApi.swift in Sources */,
|
E97AF46023FC85D600635494 /* PlaylistApi.swift in Sources */,
|
||||||
A11AC70628A188AE00645043 /* AuthApi.swift in Sources */,
|
A11AC70628A188AE00645043 /* AuthApi.swift in Sources */,
|
||||||
A1AF726F28A84F7D00D317C9 /* AdminApi.swift in Sources */,
|
A1AF726F28A84F7D00D317C9 /* AdminApi.swift in Sources */,
|
||||||
|
A15D257E29342E4F0049055E /* APNSHandler.swift in Sources */,
|
||||||
A1AF727128A850AE00D317C9 /* UsersList.swift in Sources */,
|
A1AF727128A850AE00D317C9 /* UsersList.swift in Sources */,
|
||||||
E9EA690F23F9A5430012C3E8 /* AppSkeleton.swift in Sources */,
|
E9EA690F23F9A5430012C3E8 /* AppSkeleton.swift in Sources */,
|
||||||
|
A15D257A293421350049055E /* StaticNotif.swift in Sources */,
|
||||||
E98254BD23F9B7A90056D9D3 /* Playlist.swift in Sources */,
|
E98254BD23F9B7A90056D9D3 /* Playlist.swift in Sources */,
|
||||||
A13C54972928FD7C0034F233 /* ManagedInputList.swift in Sources */,
|
A13C54972928FD7C0034F233 /* ManagedInputList.swift in Sources */,
|
||||||
E97AF46723FD650800635494 /* AddPlaylistSheet.swift in Sources */,
|
E97AF46723FD650800635494 /* AddPlaylistSheet.swift in Sources */,
|
||||||
@ -471,6 +494,7 @@
|
|||||||
E98254D023FB00B60056D9D3 /* LoginScreen.swift in Sources */,
|
E98254D023FB00B60056D9D3 /* LoginScreen.swift in Sources */,
|
||||||
E9E30C2623FEA4F000574EEF /* TagApi.swift in Sources */,
|
E9E30C2623FEA4F000574EEF /* TagApi.swift in Sources */,
|
||||||
E97AF46923FD9E1B00635494 /* SpotInputList.swift in Sources */,
|
E97AF46923FD9E1B00635494 /* SpotInputList.swift in Sources */,
|
||||||
|
A15D257C293425390049055E /* NotificationsControls.swift in Sources */,
|
||||||
E97AF45B23FC748D00635494 /* UserApi.swift in Sources */,
|
E97AF45B23FC748D00635494 /* UserApi.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
<EnvironmentVariables>
|
<EnvironmentVariables>
|
||||||
<EnvironmentVariable
|
<EnvironmentVariable
|
||||||
key = "MTOOLS_SERVER"
|
key = "MTOOLS_SERVER"
|
||||||
value = "http://127.0.0.1:5000/"
|
value = "http://127.0.0.1:8080/"
|
||||||
isEnabled = "YES">
|
isEnabled = "YES">
|
||||||
</EnvironmentVariable>
|
</EnvironmentVariable>
|
||||||
</EnvironmentVariables>
|
</EnvironmentVariables>
|
||||||
|
@ -15,6 +15,7 @@ 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.
|
||||||
|
UIApplication.shared.registerForRemoteNotifications()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +32,27 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
|
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
|
||||||
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
|
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func application(_ application: UIApplication,
|
||||||
|
didRegisterForRemoteNotificationsWithDeviceToken
|
||||||
|
deviceToken: Data) {
|
||||||
|
|
||||||
|
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
|
||||||
|
|
||||||
|
StaticNotif.token = token
|
||||||
|
}
|
||||||
|
|
||||||
|
func application(_ application: UIApplication,
|
||||||
|
didFailToRegisterForRemoteNotificationsWithError
|
||||||
|
error: Error) {
|
||||||
|
// Try again later.
|
||||||
|
}
|
||||||
|
|
||||||
|
func application(_ application: UIApplication,
|
||||||
|
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
|
||||||
|
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
|
||||||
|
completionHandler(.noData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Logger {
|
extension Logger {
|
||||||
|
@ -150,6 +150,66 @@
|
|||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"filename" : "16.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "32.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "32.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "64.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "128.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "256.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "256.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "512.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "512.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "1024.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename" : "48.png",
|
"filename" : "48.png",
|
||||||
"idiom" : "watch",
|
"idiom" : "watch",
|
||||||
@ -225,6 +285,13 @@
|
|||||||
"size" : "51x51",
|
"size" : "51x51",
|
||||||
"subtype" : "45mm"
|
"subtype" : "45mm"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "watch",
|
||||||
|
"role" : "appLauncher",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "54x54",
|
||||||
|
"subtype" : "49mm"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename" : "172.png",
|
"filename" : "172.png",
|
||||||
"idiom" : "watch",
|
"idiom" : "watch",
|
||||||
@ -256,71 +323,18 @@
|
|||||||
"size" : "117x117",
|
"size" : "117x117",
|
||||||
"subtype" : "45mm"
|
"subtype" : "45mm"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "watch",
|
||||||
|
"role" : "quickLook",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "129x129",
|
||||||
|
"subtype" : "49mm"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename" : "1024.png",
|
"filename" : "1024.png",
|
||||||
"idiom" : "watch-marketing",
|
"idiom" : "watch-marketing",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "16.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "16x16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "32.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "16x16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "32.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "32x32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "64.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "32x32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "128.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "128x128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "256.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "128x128"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "256.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "256x256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "512.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "256x256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "512.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "1x",
|
|
||||||
"size" : "512x512"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "1024.png",
|
|
||||||
"idiom" : "mac",
|
|
||||||
"scale" : "2x",
|
|
||||||
"size" : "512x512"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
@ -43,6 +43,10 @@
|
|||||||
</dict>
|
</dict>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIBackgroundModes</key>
|
||||||
|
<array>
|
||||||
|
<string>remote-notification</string>
|
||||||
|
</array>
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
<array>
|
<array>
|
||||||
<string>armv7</string>
|
<string>armv7</string>
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>aps-environment</key>
|
||||||
|
<string>development</string>
|
||||||
|
<key>com.apple.developer.aps-environment</key>
|
||||||
|
<string>development</string>
|
||||||
<key>com.apple.security.app-sandbox</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.network.client</key>
|
<key>com.apple.security.network.client</key>
|
||||||
|
@ -11,13 +11,14 @@ import Alamofire
|
|||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import KeychainAccess
|
import KeychainAccess
|
||||||
import OSLog
|
import OSLog
|
||||||
|
import UserNotifications
|
||||||
|
|
||||||
class LiveUser: ObservableObject {
|
class LiveUser: ObservableObject {
|
||||||
|
|
||||||
@Published var playlists: [Playlist]
|
@Published var playlists: [Playlist]
|
||||||
@Published var tags: [Tag]
|
@Published var tags: [Tag]
|
||||||
@Published var username: String
|
@Published var username: String
|
||||||
@Published var user: User?
|
@Published var user: User
|
||||||
|
|
||||||
@Published var loggedIn: Bool {
|
@Published var loggedIn: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
@ -25,6 +26,27 @@ class LiveUser: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requestAPNSPerms(){
|
||||||
|
let center = UNUserNotificationCenter.current()
|
||||||
|
center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
|
||||||
|
|
||||||
|
if error != nil {
|
||||||
|
self.handleAPNSFailure()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// load token from static var and pass to backend server
|
||||||
|
APNSHandler.pass_token_to_backend(onFailure: {
|
||||||
|
self.handleAPNSFailure()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleAPNSFailure(){
|
||||||
|
Logger.sys.debug("failed to get APNS token")
|
||||||
|
}
|
||||||
|
|
||||||
@Published var isRefreshingUser = false
|
@Published var isRefreshingUser = false
|
||||||
@Published var isRefreshingPlaylists = false
|
@Published var isRefreshingPlaylists = false
|
||||||
@Published var isRefreshingTags = false
|
@Published var isRefreshingTags = false
|
||||||
@ -34,6 +56,7 @@ class LiveUser: ObservableObject {
|
|||||||
self.tags = tags
|
self.tags = tags
|
||||||
self.username = username
|
self.username = username
|
||||||
self.loggedIn = loggedIn
|
self.loggedIn = loggedIn
|
||||||
|
self.user = User.get_null_user()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(playlists: [Playlist], tags: [Tag], username: String, loggedIn: Bool, user: User) {
|
init(playlists: [Playlist], tags: [Tag], username: String, loggedIn: Bool, user: User) {
|
||||||
@ -45,11 +68,7 @@ class LiveUser: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func lastfm_connected() -> Bool {
|
func lastfm_connected() -> Bool {
|
||||||
if let username = user?.lastfm_username {
|
return username.count > 0
|
||||||
return username.count > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func logout() {
|
func logout() {
|
||||||
@ -64,7 +83,7 @@ class LiveUser: ObservableObject {
|
|||||||
playlists.removeAll()
|
playlists.removeAll()
|
||||||
tags.removeAll()
|
tags.removeAll()
|
||||||
username = ""
|
username = ""
|
||||||
user = nil
|
user = User.get_null_user()
|
||||||
|
|
||||||
UserDefaults.standard.removeObject(forKey: "playlists")
|
UserDefaults.standard.removeObject(forKey: "playlists")
|
||||||
UserDefaults.standard.removeObject(forKey: "tags")
|
UserDefaults.standard.removeObject(forKey: "tags")
|
||||||
@ -224,27 +243,9 @@ class LiveUser: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func check_network_response(response: AFDataResponse<Any>) -> Bool {
|
func check_network_response(response: AFDataResponse<Any>) -> Bool {
|
||||||
|
return NetworkHelper.check_network_response(response: response, onTokenFail: {
|
||||||
if let statusCode = response.response?.statusCode {
|
self.logout()
|
||||||
switch statusCode {
|
})
|
||||||
case 401: // token has expired
|
|
||||||
Logger.sys.info("token expired, logging user out")
|
|
||||||
self.logout()
|
|
||||||
return false
|
|
||||||
case 400..<500:
|
|
||||||
Logger.net.error("client fault \(statusCode)")
|
|
||||||
return false
|
|
||||||
case 500..<600:
|
|
||||||
Logger.net.warning("server fault \(statusCode)")
|
|
||||||
return false
|
|
||||||
case _: // 200 -> Success
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.net.error("live user failed to access status code to check")
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func load_user_defaults() -> LiveUser {
|
func load_user_defaults() -> LiveUser {
|
||||||
@ -277,4 +278,12 @@ class LiveUser: ObservableObject {
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func get_preview_user() -> LiveUser {
|
||||||
|
return LiveUser(playlists: [], tags: [], username: "user", loggedIn: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func get_preview_user_with_user() -> LiveUser {
|
||||||
|
return LiveUser(playlists: [], tags: [], username: "user", loggedIn: false, user: User())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,28 +30,28 @@ class Playlist: Identifiable, Equatable, Codable, ObservableObject {
|
|||||||
self.updatePlaylist(updates: JSON(["include_recommendations": self.include_recommendations]))
|
self.updatePlaylist(updates: JSON(["include_recommendations": self.include_recommendations]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Published var recommendation_sample: Int{
|
@Published var recommendation_sample: Int {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["recommendation_sample": self.recommendation_sample]))
|
self.updatePlaylist(updates: JSON(["recommendation_sample": self.recommendation_sample]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Published var include_library_tracks: Bool{
|
@Published var include_library_tracks: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["include_library_tracks": self.include_library_tracks]))
|
self.updatePlaylist(updates: JSON(["include_library_tracks": self.include_library_tracks]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var parts: Array<String>{
|
@Published var parts: Array<String> {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["parts": self.parts]))
|
self.updatePlaylist(updates: JSON(["parts": self.parts]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Published var playlist_references: Array<String>{
|
@Published var playlist_references: Array<String> {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["playlist_references": self.playlist_references]))
|
self.updatePlaylist(updates: JSON(["playlist_references": self.playlist_references]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Published var shuffle: Bool{
|
@Published var shuffle: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["shuffle": self.shuffle]))
|
self.updatePlaylist(updates: JSON(["shuffle": self.shuffle]))
|
||||||
}
|
}
|
||||||
@ -88,45 +88,45 @@ class Playlist: Identifiable, Equatable, Codable, ObservableObject {
|
|||||||
|
|
||||||
@Published var lastfm_stat_last_refresh: String?
|
@Published var lastfm_stat_last_refresh: String?
|
||||||
|
|
||||||
@Published var add_last_month: Bool{
|
@Published var add_last_month: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["add_last_month": self.add_last_month]))
|
self.updatePlaylist(updates: JSON(["add_last_month": self.add_last_month]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Published var add_this_month: Bool{
|
@Published var add_this_month: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["add_this_month": self.add_this_month]))
|
self.updatePlaylist(updates: JSON(["add_this_month": self.add_this_month]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Published var day_boundary: Int{
|
@Published var day_boundary: Int {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["day_boundary": self.day_boundary]))
|
self.updatePlaylist(updates: JSON(["day_boundary": self.day_boundary]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var chart_range: LastFmRange{
|
@Published var chart_range: LastFmRange {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["chart_range": self.chart_range.rawValue]))
|
self.updatePlaylist(updates: JSON(["chart_range": self.chart_range.rawValue]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Published var chart_limit: Int{
|
@Published var chart_limit: Int {
|
||||||
didSet {
|
didSet {
|
||||||
self.updatePlaylist(updates: JSON(["chart_range": self.chart_range.rawValue]))
|
self.updatePlaylist(updates: JSON(["chart_limit": self.chart_limit]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePlaylist(updates: JSON) {
|
func updatePlaylist(updates: JSON) {
|
||||||
let api = PlaylistApi.updatePlaylist(name: self.name, updates: updates)
|
let api = PlaylistApi.updatePlaylist(name: self.name, updates: updates)
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
switch response.response?.statusCode {
|
switch response.response?.statusCode {
|
||||||
case 200, 201:
|
case 200, 201:
|
||||||
break
|
break
|
||||||
case _:
|
case _:
|
||||||
Logger.net.error("error: \(self.name), \(updates)")
|
Logger.net.error("error: \(self.name), \(updates)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//TODO: do better error checking
|
||||||
}
|
}
|
||||||
//TODO: do better error checking
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case name
|
case name
|
||||||
|
@ -15,7 +15,7 @@ enum UserType: String, Decodable {
|
|||||||
case admin = "admin"
|
case admin = "admin"
|
||||||
}
|
}
|
||||||
|
|
||||||
class User: Identifiable, Decodable {
|
class User: Identifiable, Decodable, ObservableObject {
|
||||||
|
|
||||||
//MARK: Properties
|
//MARK: Properties
|
||||||
|
|
||||||
@ -30,7 +30,29 @@ class User: Identifiable, Decodable {
|
|||||||
var last_refreshed: String
|
var last_refreshed: String
|
||||||
|
|
||||||
var spotify_linked: Bool
|
var spotify_linked: Bool
|
||||||
@Published var lastfm_username: String? {
|
|
||||||
|
@Published var notify: Bool {
|
||||||
|
didSet {
|
||||||
|
self.updateUser(updates: JSON(["notify": self.notify]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Published var notify_playlist_updates: Bool {
|
||||||
|
didSet {
|
||||||
|
self.updateUser(updates: JSON(["notify_playlist_updates": self.notify_playlist_updates]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Published var notify_tag_updates: Bool {
|
||||||
|
didSet {
|
||||||
|
self.updateUser(updates: JSON(["notify_tag_updates": self.notify_tag_updates]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Published var notify_admins: Bool {
|
||||||
|
didSet {
|
||||||
|
self.updateUser(updates: JSON(["notify_admins": self.notify_admins]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Published var lastfm_username: String {
|
||||||
didSet {
|
didSet {
|
||||||
self.updateUser(updates: JSON(["lastfm_username": self.lastfm_username]))
|
self.updateUser(updates: JSON(["lastfm_username": self.lastfm_username]))
|
||||||
}
|
}
|
||||||
@ -48,7 +70,12 @@ class User: Identifiable, Decodable {
|
|||||||
last_keygen: String = "",
|
last_keygen: String = "",
|
||||||
last_refreshed: String = "",
|
last_refreshed: String = "",
|
||||||
spotify_linked: Bool = true,
|
spotify_linked: Bool = true,
|
||||||
lastfm_username: String? = nil){
|
lastfm_username: String = "",
|
||||||
|
|
||||||
|
notify: Bool = false,
|
||||||
|
notify_playlist_updates: Bool = false,
|
||||||
|
notify_tag_updates: Bool = false,
|
||||||
|
notify_admins: Bool = false){
|
||||||
|
|
||||||
self.username = username
|
self.username = username
|
||||||
self.email = email
|
self.email = email
|
||||||
@ -61,19 +88,21 @@ class User: Identifiable, Decodable {
|
|||||||
self.last_refreshed = last_refreshed
|
self.last_refreshed = last_refreshed
|
||||||
self.spotify_linked = spotify_linked
|
self.spotify_linked = spotify_linked
|
||||||
self.lastfm_username = lastfm_username
|
self.lastfm_username = lastfm_username
|
||||||
|
|
||||||
|
self.notify = notify
|
||||||
|
self.notify_playlist_updates = notify_playlist_updates
|
||||||
|
self.notify_tag_updates = notify_tag_updates
|
||||||
|
self.notify_admins = notify_admins
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUser(updates: JSON) {
|
func updateUser(updates: JSON) {
|
||||||
let api = UserApi.updateUser(updates: updates)
|
let api = UserApi.updateUser(updates: updates)
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
switch response.response?.statusCode {
|
|
||||||
case 200, 201:
|
if !NetworkHelper.check_network_response(response: response) {
|
||||||
break
|
|
||||||
case _:
|
|
||||||
Logger.net.error("error while updating user: \(updates)")
|
Logger.net.error("error while updating user: \(updates)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: do better error checking
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
@ -89,6 +118,11 @@ class User: Identifiable, Decodable {
|
|||||||
|
|
||||||
case spotify_linked
|
case spotify_linked
|
||||||
case lastfm_username
|
case lastfm_username
|
||||||
|
|
||||||
|
case notify
|
||||||
|
case notify_playlist_updates
|
||||||
|
case notify_tag_updates
|
||||||
|
case notify_admins
|
||||||
}
|
}
|
||||||
|
|
||||||
required init(from decoder: Decoder) throws {
|
required init(from decoder: Decoder) throws {
|
||||||
@ -120,7 +154,31 @@ class User: Identifiable, Decodable {
|
|||||||
do{
|
do{
|
||||||
lastfm_username = try container.decode(String.self, forKey: .lastfm_username)
|
lastfm_username = try container.decode(String.self, forKey: .lastfm_username)
|
||||||
}catch {
|
}catch {
|
||||||
lastfm_username = nil
|
lastfm_username = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
do{
|
||||||
|
notify = try container.decode(Bool.self, forKey: .notify)
|
||||||
|
}catch {
|
||||||
|
notify = false
|
||||||
|
}
|
||||||
|
|
||||||
|
do{
|
||||||
|
notify_playlist_updates = try container.decode(Bool.self, forKey: .notify_playlist_updates)
|
||||||
|
}catch {
|
||||||
|
notify_playlist_updates = false
|
||||||
|
}
|
||||||
|
|
||||||
|
do{
|
||||||
|
notify_tag_updates = try container.decode(Bool.self, forKey: .notify_tag_updates)
|
||||||
|
}catch {
|
||||||
|
notify_tag_updates = false
|
||||||
|
}
|
||||||
|
|
||||||
|
do{
|
||||||
|
notify_admins = try container.decode(Bool.self, forKey: .notify_admins)
|
||||||
|
}catch {
|
||||||
|
notify_admins = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +197,15 @@ class User: Identifiable, Decodable {
|
|||||||
|
|
||||||
try container.encode(self.spotify_linked, forKey: .spotify_linked)
|
try container.encode(self.spotify_linked, forKey: .spotify_linked)
|
||||||
try container.encode(self.lastfm_username, forKey: .lastfm_username)
|
try container.encode(self.lastfm_username, forKey: .lastfm_username)
|
||||||
|
|
||||||
|
try container.encode(self.notify, forKey: .notify)
|
||||||
|
try container.encode(self.notify_playlist_updates, forKey: .notify_playlist_updates)
|
||||||
|
try container.encode(self.notify_tag_updates, forKey: .notify_tag_updates)
|
||||||
|
try container.encode(self.notify_admins, forKey: .notify_admins)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func get_null_user() -> User {
|
||||||
|
return User()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
38
Mixonomer/Network/NetworkHelper.swift
Normal file
38
Mixonomer/Network/NetworkHelper.swift
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// NetworkHelper.swift
|
||||||
|
// Mixonomer
|
||||||
|
//
|
||||||
|
// Created by Andy Pack on 27/11/2022.
|
||||||
|
// Copyright © 2022 Sarsoo. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import OSLog
|
||||||
|
import Alamofire
|
||||||
|
|
||||||
|
class NetworkHelper {
|
||||||
|
|
||||||
|
static func check_network_response(response: AFDataResponse<Any>, onTokenFail: (() -> Void)? = nil) -> Bool {
|
||||||
|
|
||||||
|
if let statusCode = response.response?.statusCode {
|
||||||
|
switch statusCode {
|
||||||
|
case 401: // token has expired
|
||||||
|
Logger.sys.info("token expired, logging user out")
|
||||||
|
onTokenFail?()
|
||||||
|
return false
|
||||||
|
case 400..<500:
|
||||||
|
Logger.net.error("client fault \(statusCode)")
|
||||||
|
return false
|
||||||
|
case 500..<600:
|
||||||
|
Logger.net.warning("server fault \(statusCode)")
|
||||||
|
return false
|
||||||
|
case _: // 200 -> Success
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.net.error("failed to access network status code to validate")
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,11 @@ public enum UserApi {
|
|||||||
case getUser
|
case getUser
|
||||||
case updateUser(updates: JSON)
|
case updateUser(updates: JSON)
|
||||||
case deleteUser
|
case deleteUser
|
||||||
|
case passAPNSToken(updates: String)
|
||||||
|
case updateNotify(state: Bool)
|
||||||
|
case updateNotifyPlaylist(state: String)
|
||||||
|
case updateNotifyTag(state: String)
|
||||||
|
case updateNotifyAdmin(state: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UserApi: ApiRequest {
|
extension UserApi: ApiRequest {
|
||||||
@ -30,6 +35,10 @@ extension UserApi: ApiRequest {
|
|||||||
return "api/user"
|
return "api/user"
|
||||||
case .deleteUser:
|
case .deleteUser:
|
||||||
return "api/user"
|
return "api/user"
|
||||||
|
case .passAPNSToken:
|
||||||
|
return "api/user"
|
||||||
|
case .updateNotify, .updateNotifyPlaylist, .updateNotifyTag, .updateNotifyAdmin:
|
||||||
|
return "api/user"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +50,10 @@ extension UserApi: ApiRequest {
|
|||||||
return .post
|
return .post
|
||||||
case .deleteUser:
|
case .deleteUser:
|
||||||
return .delete
|
return .delete
|
||||||
|
case .passAPNSToken:
|
||||||
|
return .post
|
||||||
|
case .updateNotify, .updateNotifyPlaylist, .updateNotifyTag, .updateNotifyAdmin:
|
||||||
|
return .post
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +63,16 @@ extension UserApi: ApiRequest {
|
|||||||
return nil
|
return nil
|
||||||
case .updateUser(let updates):
|
case .updateUser(let updates):
|
||||||
return updates
|
return updates
|
||||||
|
case .passAPNSToken(let token):
|
||||||
|
return JSON(["apns_token": token])
|
||||||
|
case .updateNotify(let state):
|
||||||
|
return JSON(["notify": state])
|
||||||
|
case .updateNotifyPlaylist(let state):
|
||||||
|
return JSON(["notify_playlist_updates": state])
|
||||||
|
case .updateNotifyTag(let state):
|
||||||
|
return JSON(["notify_tag_updates": state])
|
||||||
|
case .updateNotifyAdmin(let state):
|
||||||
|
return JSON(["notify_admins": state])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +80,9 @@ extension UserApi: ApiRequest {
|
|||||||
switch self {
|
switch self {
|
||||||
case .getUser, .deleteUser:
|
case .getUser, .deleteUser:
|
||||||
return nil
|
return nil
|
||||||
case .updateUser:
|
case .updateUser, .passAPNSToken:
|
||||||
|
return JSONParameterEncoder.default
|
||||||
|
case .updateNotify, .updateNotifyPlaylist, .updateNotifyTag, .updateNotifyAdmin:
|
||||||
return JSONParameterEncoder.default
|
return JSONParameterEncoder.default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +95,7 @@ extension UserApi: ApiRequest {
|
|||||||
return ApiRequestDefaults.authMethod
|
return ApiRequestDefaults.authMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
static func fromJSON(user: Data) -> User? {
|
static func fromJSON(user: Data) -> User {
|
||||||
|
|
||||||
let decoder = JSONDecoder()
|
let decoder = JSONDecoder()
|
||||||
do {
|
do {
|
||||||
@ -78,11 +103,11 @@ extension UserApi: ApiRequest {
|
|||||||
return user
|
return user
|
||||||
} catch {
|
} catch {
|
||||||
Logger.parse.error("error parsing user from json: \(error)")
|
Logger.parse.error("error parsing user from json: \(error)")
|
||||||
|
return User.get_null_user()
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func fromJSON(user: JSON) -> User? {
|
static func fromJSON(user: JSON) -> User {
|
||||||
|
|
||||||
let _json = user.rawString()?.data(using: .utf8)
|
let _json = user.rawString()?.data(using: .utf8)
|
||||||
|
|
||||||
@ -95,16 +120,16 @@ extension UserApi: ApiRequest {
|
|||||||
Logger.parse.error("error parsing user from json: \(error)")
|
Logger.parse.error("error parsing user from json: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
return User.get_null_user()
|
||||||
}
|
}
|
||||||
|
|
||||||
static func fromJSON(user: [JSON]) -> [User] {
|
static func fromJSON(user: [JSON]) -> [User] {
|
||||||
var _users: [User] = []
|
var _users: [User] = []
|
||||||
for dict in user {
|
for dict in user {
|
||||||
let _iter = self.fromJSON(user: dict)
|
let _iter = self.fromJSON(user: dict)
|
||||||
if let returned = _iter {
|
|
||||||
_users.append(returned)
|
_users.append(_iter)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return _users
|
return _users
|
||||||
}
|
}
|
||||||
|
37
Mixonomer/Notifications/APNSHandler.swift
Normal file
37
Mixonomer/Notifications/APNSHandler.swift
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// APNSHandler.swift
|
||||||
|
// Mixonomer
|
||||||
|
//
|
||||||
|
// Created by Andy Pack on 27/11/2022.
|
||||||
|
// Copyright © 2022 Sarsoo. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import OSLog
|
||||||
|
|
||||||
|
class APNSHandler {
|
||||||
|
|
||||||
|
static func pass_token_to_backend(onFailure: (() -> Void)? = nil) {
|
||||||
|
// check if a token is waiting to be handed off
|
||||||
|
if let token = StaticNotif.token {
|
||||||
|
if !StaticNotif.hasDelivered {
|
||||||
|
|
||||||
|
Logger.sys.info("passing off APNS network token")
|
||||||
|
let api = UserApi.passAPNSToken(updates: token)
|
||||||
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
|
|
||||||
|
if NetworkHelper.check_network_response(response: response) {
|
||||||
|
Logger.net.debug("successfully handed off APNS token")
|
||||||
|
StaticNotif.hasDelivered = true
|
||||||
|
} else {
|
||||||
|
Logger.net.error("failed to hand off APNS token: \(response.response?.statusCode ?? 0)")
|
||||||
|
onFailure?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Logger.sys.debug("no APNS token waiting, skipping network handoff")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
Mixonomer/Notifications/StaticNotif.swift
Normal file
14
Mixonomer/Notifications/StaticNotif.swift
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// StaticNotif.swift
|
||||||
|
// Mixonomer
|
||||||
|
//
|
||||||
|
// Created by Andy Pack on 27/11/2022.
|
||||||
|
// Copyright © 2022 Sarsoo. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class StaticNotif {
|
||||||
|
static var token: String?
|
||||||
|
static var hasDelivered: Bool = false
|
||||||
|
}
|
@ -74,6 +74,6 @@ struct UsersList: View {
|
|||||||
struct UsersList_Previews: PreviewProvider {
|
struct UsersList_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
UsersList()
|
UsersList()
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,6 @@ struct AppSkeleton: View {
|
|||||||
struct RootView_Previews: PreviewProvider {
|
struct RootView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
AppSkeleton()
|
AppSkeleton()
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,11 +237,11 @@ struct LoginScreen_Previews: PreviewProvider {
|
|||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
Group{
|
Group{
|
||||||
LoginScreen(screenMode: .None)
|
LoginScreen(screenMode: .None)
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
LoginScreen(screenMode: .Login)
|
LoginScreen(screenMode: .Login)
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
LoginScreen(screenMode: .Register)
|
LoginScreen(screenMode: .Register)
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,6 @@ struct AddPlaylistSheet: View {
|
|||||||
struct AddPlaylistSheet_Previews: PreviewProvider {
|
struct AddPlaylistSheet_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
AddPlaylistSheet(playlists: .constant([]), username: .constant("username"))
|
AddPlaylistSheet(playlists: .constant([]), username: .constant("username"))
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ struct PlaylistList: View {
|
|||||||
NavigationView {
|
NavigationView {
|
||||||
|
|
||||||
List{
|
List{
|
||||||
if liveUser.user?.spotify_linked == false {
|
if liveUser.user.spotify_linked == false {
|
||||||
Text("Spotify isn't linked, login to the web client to pair")
|
Text("Spotify isn't linked, login to the web client to pair")
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
@ -101,9 +101,9 @@ struct PlaylistList_Previews: PreviewProvider {
|
|||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
Group {
|
Group {
|
||||||
PlaylistList()
|
PlaylistList()
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
PlaylistList()
|
PlaylistList()
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false, user: User()))
|
.environmentObject(LiveUser.get_preview_user_with_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,6 @@ struct PlaylistRow_Previews: PreviewProvider {
|
|||||||
PlaylistView(playlist: .constant(
|
PlaylistView(playlist: .constant(
|
||||||
Playlist(name: "playlist name", username: "username")
|
Playlist(name: "playlist name", username: "username")
|
||||||
))
|
))
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,7 +366,7 @@ struct PlaylistView_Previews: PreviewProvider {
|
|||||||
lastfm_stat_artist_percent: 80
|
lastfm_stat_artist_percent: 80
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
PlaylistView(playlist: .constant(
|
PlaylistView(playlist: .constant(
|
||||||
Playlist(name: "playlist name",
|
Playlist(name: "playlist name",
|
||||||
username: "username",
|
username: "username",
|
||||||
@ -375,7 +375,7 @@ struct PlaylistView_Previews: PreviewProvider {
|
|||||||
lastfm_stat_artist_percent: 80
|
lastfm_stat_artist_percent: 80
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false, user: User()))
|
.environmentObject(LiveUser.get_preview_user_with_user())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
52
Mixonomer/Views/Settings/NotificationsControls.swift
Normal file
52
Mixonomer/Views/Settings/NotificationsControls.swift
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// NotificationsControls.swift
|
||||||
|
// Mixonomer
|
||||||
|
//
|
||||||
|
// Created by Andy Pack on 27/11/2022.
|
||||||
|
// Copyright © 2022 Sarsoo. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct NotificationsControls: View {
|
||||||
|
|
||||||
|
@EnvironmentObject var liveUser: LiveUser
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
Section {
|
||||||
|
Toggle(isOn: self.$liveUser.user.notify) {
|
||||||
|
Text("Enabled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Section {
|
||||||
|
Button("Request permission on this device") {
|
||||||
|
self.liveUser.requestAPNSPerms()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Section {
|
||||||
|
Toggle(isOn: self.$liveUser.user.notify_playlist_updates) {
|
||||||
|
Text("Playlist Updates")
|
||||||
|
}
|
||||||
|
Toggle(isOn: self.$liveUser.user.notify_tag_updates) {
|
||||||
|
Text("Tag Updates")
|
||||||
|
}
|
||||||
|
|
||||||
|
if liveUser.user.type == .admin {
|
||||||
|
Toggle(isOn: self.$liveUser.user.notify_admins) {
|
||||||
|
Text("Admin Updates")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.listStyle(GroupedListStyle())
|
||||||
|
.navigationBarTitle(Text("Notifications 🔔"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NotificationsControls_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
NotificationsControls()
|
||||||
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
|
}
|
||||||
|
}
|
@ -16,13 +16,7 @@ struct SettingsList: View {
|
|||||||
@State private var deleteAlertShowing = false
|
@State private var deleteAlertShowing = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
NavigationView {
|
||||||
let spotify_link_bind = Binding<Bool>(get: { liveUser.user?.spotify_linked ?? false},
|
|
||||||
set: { newVal in liveUser.user?.spotify_linked = newVal })
|
|
||||||
// let lastfm_bind = Binding<String>(get: { liveUser.user?.lastfm_username ?? ""},
|
|
||||||
// set: { newVal in liveUser.user?.lastfm_username = newVal })
|
|
||||||
|
|
||||||
return NavigationView {
|
|
||||||
List{
|
List{
|
||||||
Section {
|
Section {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
@ -47,21 +41,25 @@ struct SettingsList: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Section(header: Text("Integrations")) {
|
Section(header: Text("Integrations")) {
|
||||||
Toggle(isOn: spotify_link_bind) {
|
Toggle(isOn: self.$liveUser.user.spotify_linked) {
|
||||||
Text("Spotify Link")
|
Text("Spotify Link")
|
||||||
}
|
}
|
||||||
.disabled(true)
|
.disabled(true)
|
||||||
|
|
||||||
// NavigationLink("Last.fm Username") {
|
NavigationLink("Last.fm") {
|
||||||
// List{
|
List{
|
||||||
// TextField("Username", text: lastfm_bind)
|
TextField("Username", text: self.$liveUser.user.lastfm_username)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section(header: Text("Last.fm")) {
|
Section {
|
||||||
// TextField("Last.fm Username", text: lastfm_bind)
|
NavigationLink(destination: NotificationsControls()) {
|
||||||
// }
|
HStack {
|
||||||
|
Text("Notifications")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
@ -128,6 +126,6 @@ struct SettingsList: View {
|
|||||||
struct SettingsList_Previews: PreviewProvider {
|
struct SettingsList_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
SettingsList()
|
SettingsList()
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,6 @@ struct AddTagSheet: View {
|
|||||||
struct AddTagSheet_Previews: PreviewProvider {
|
struct AddTagSheet_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
AddTagSheet(tags: .constant([]), username: .constant("username"))
|
AddTagSheet(tags: .constant([]), username: .constant("username"))
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,6 @@ struct TagList: View {
|
|||||||
struct TagList_Previews: PreviewProvider {
|
struct TagList_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
TagList()
|
TagList()
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,6 @@ struct TagRow_Previews: PreviewProvider {
|
|||||||
|
|
||||||
last_updated: "10th Feb")
|
last_updated: "10th Feb")
|
||||||
))
|
))
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,32 +118,41 @@ struct TagView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runTag() {
|
func runTag() {
|
||||||
|
|
||||||
|
Logger.net.debug("running tag from view: \(self.tag.name)")
|
||||||
|
|
||||||
let api = TagApi.runTag(tag_id: tag.tag_id)
|
let api = TagApi.runTag(tag_id: tag.tag_id)
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
|
|
||||||
if self.liveUser.check_network_response(response: response) {
|
if self.liveUser.check_network_response(response: response) {
|
||||||
|
Logger.net.debug("successfully running tag: \(self.tag.name)")
|
||||||
} else {
|
} else {
|
||||||
|
Logger.net.error("request failed for running tag: \(self.tag.name)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: do better error checking
|
//TODO: do better error checking
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTag(updates: JSON) {
|
func updateTag(updates: JSON) {
|
||||||
|
|
||||||
|
Logger.net.debug("updating tag from view: \(self.tag.name)")
|
||||||
|
|
||||||
let api = TagApi.updateTag(tag_id: tag.tag_id, updates: updates)
|
let api = TagApi.updateTag(tag_id: tag.tag_id, updates: updates)
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
|
|
||||||
if self.liveUser.check_network_response(response: response) {
|
if self.liveUser.check_network_response(response: response) {
|
||||||
|
Logger.net.debug("successfully updated tag: \(self.tag.name)")
|
||||||
} else {
|
} else {
|
||||||
|
Logger.net.error("request failed for updating tag: \(self.tag.name)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: do better error checking
|
//TODO: do better error checking
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshTag() {
|
func refreshTag() {
|
||||||
|
|
||||||
|
Logger.net.debug("refreshing tag from view: \(self.tag.name)")
|
||||||
|
|
||||||
let api = TagApi.getTag(tag_id: self.tag.tag_id)
|
let api = TagApi.getTag(tag_id: self.tag.tag_id)
|
||||||
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
|
||||||
|
|
||||||
@ -190,6 +199,6 @@ struct TagView_Previews: PreviewProvider {
|
|||||||
|
|
||||||
last_updated: "10th Feb")
|
last_updated: "10th Feb")
|
||||||
))
|
))
|
||||||
.environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false))
|
.environmentObject(LiveUser.get_preview_user())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user