mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-30 13:19:44 +02:00
feat(concerts): show artwork-themed event details in app
This commit is contained in:
1 parent
ab58cdbb0c
commit
abb8dc4a42
18 files changed
+1047
-23
No files matched your search
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
C0CE00000000000000000001 /* ConcertCalendarBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0CE00000000000000000002 /* ConcertCalendarBridge.swift */; };
|
||||
A0D100000000000000000001 /* AudioOutputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D100000000000000000002 /* AudioOutputView.swift */; };
|
||||
F59500000000000000000011 /* PlayerWidgetState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59500000000000000000001 /* PlayerWidgetState.swift */; };
|
||||
F59500000000000000000012 /* PlayerControlIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F59500000000000000000002 /* PlayerControlIntent.swift */; };
|
||||
@@ -70,6 +71,7 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
C0CE00000000000000000002 /* ConcertCalendarBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcertCalendarBridge.swift; sourceTree = "<group>"; };
|
||||
A0D100000000000000000002 /* AudioOutputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioOutputView.swift; sourceTree = "<group>"; };
|
||||
F59500000000000000000009 /* PlayerWidget.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = PlayerWidget.xcconfig; sourceTree = "<group>"; };
|
||||
F59500000000000000000001 /* PlayerWidgetState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerWidgetState.swift; sourceTree = "<group>"; };
|
||||
@@ -213,6 +215,7 @@
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
F59500000000000000000004 /* PlayerWidgetBridge.swift */,
|
||||
A0D100000000000000000002 /* AudioOutputView.swift */,
|
||||
C0CE00000000000000000002 /* ConcertCalendarBridge.swift */,
|
||||
F59500000000000000000007 /* Runner.entitlements */,
|
||||
C03400000000000000000002 /* CoreBackend.swift */,
|
||||
D08A594730CF000100000002 /* DownloadProgressSubscription.swift */,
|
||||
@@ -475,6 +478,7 @@
|
||||
F59500000000000000000012 /* PlayerControlIntent.swift in Sources */,
|
||||
F59500000000000000000013 /* PlayerWidgetBridge.swift in Sources */,
|
||||
A0D100000000000000000001 /* AudioOutputView.swift in Sources */,
|
||||
C0CE00000000000000000001 /* ConcertCalendarBridge.swift in Sources */,
|
||||
C03400000000000000000001 /* CoreBackend.swift in Sources */,
|
||||
D08A594730CF000100000001 /* DownloadProgressSubscription.swift in Sources */,
|
||||
A11CE0012F00000000000001 /* ExtensionCallbackParser.swift in Sources */,
|
||||
|
||||
@@ -23,6 +23,7 @@ import UniformTypeIdentifiers
|
||||
private var lastLibraryScanProgressPayload: String?
|
||||
private var libraryScanProgressGeneration: UInt64 = 0
|
||||
private var backendChannel: FlutterMethodChannel?
|
||||
private var concertCalendar: ConcertCalendarBridge?
|
||||
private let coreBackend: CoreBackend = createCoreBackend()
|
||||
private var pendingSessionGrantEvents: [[String: Any]] = []
|
||||
|
||||
@@ -55,6 +56,9 @@ import UniformTypeIdentifiers
|
||||
}
|
||||
|
||||
private func configureFlutterEngine(_ messenger: FlutterBinaryMessenger, registry: FlutterPluginRegistry) {
|
||||
concertCalendar = ConcertCalendarBridge(messenger: messenger) { [weak self] in
|
||||
self?.activeWindow?.rootViewController
|
||||
}
|
||||
PlayerWidgetBridge.shared.attach(messenger)
|
||||
let channel = FlutterMethodChannel(
|
||||
name: CHANNEL,
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import EventKit
|
||||
import EventKitUI
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
final class ConcertCalendarBridge: NSObject, EKEventEditViewDelegate {
|
||||
private let channel: FlutterMethodChannel
|
||||
private let presenter: () -> UIViewController?
|
||||
private let store = EKEventStore()
|
||||
|
||||
init(messenger: FlutterBinaryMessenger, presenter: @escaping () -> UIViewController?) {
|
||||
channel = FlutterMethodChannel(name: "com.zarz.spotiflac/concert_calendar", binaryMessenger: messenger)
|
||||
self.presenter = presenter
|
||||
super.init()
|
||||
channel.setMethodCallHandler { [weak self] call, result in
|
||||
guard call.method == "add" else {
|
||||
result(FlutterMethodNotImplemented)
|
||||
return
|
||||
}
|
||||
guard let self, let data = call.arguments as? [String: Any],
|
||||
let start = data["start"] as? NSNumber else {
|
||||
result(false)
|
||||
return
|
||||
}
|
||||
if #available(iOS 17.0, *) {
|
||||
// The system editor saves only after the user confirms; it
|
||||
// needs no permission to read the person's existing events.
|
||||
self.present(data, start: start, result: result)
|
||||
} else {
|
||||
self.store.requestAccess(to: .event) { [weak self] allowed, _ in
|
||||
DispatchQueue.main.async {
|
||||
guard let self, allowed else { result(false); return }
|
||||
self.present(data, start: start, result: result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func present(_ data: [String: Any], start: NSNumber, result: @escaping FlutterResult) {
|
||||
guard let controller = presenter(), controller.viewIfLoaded?.window != nil,
|
||||
controller.presentedViewController == nil else {
|
||||
result(false)
|
||||
return
|
||||
}
|
||||
let event = EKEvent(eventStore: store)
|
||||
event.title = data["title"] as? String
|
||||
event.location = data["location"] as? String
|
||||
event.startDate = Date(timeIntervalSince1970: start.doubleValue / 1000)
|
||||
let end = (data["end"] as? NSNumber)?.doubleValue ?? 0
|
||||
event.endDate = end > start.doubleValue
|
||||
? Date(timeIntervalSince1970: end / 1000)
|
||||
: event.startDate.addingTimeInterval(3600)
|
||||
if let url = data["url"] as? String { event.url = URL(string: url) }
|
||||
let editor = EKEventEditViewController()
|
||||
editor.eventStore = store
|
||||
editor.event = event
|
||||
editor.editViewDelegate = self
|
||||
controller.present(editor, animated: true) { result(true) }
|
||||
}
|
||||
|
||||
func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
|
||||
controller.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>Add a concert to your calendar after you review and save it.</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleLocalizations</key>
|
||||
|
||||
Reference in new issue
Block a user