mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Compare commits
No commits in common. "e2ce88e67e128987bd70c6fa441d3865da51ae07" and "e6e76473da657d082c082d7663e91e1c79a8f4d2" have entirely different histories.
e2ce88e67e
...
e6e76473da
@ -15,9 +15,6 @@
|
|||||||
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B5220DD8970006D9BE /* Notification.swift */; };
|
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B5220DD8970006D9BE /* Notification.swift */; };
|
||||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */; };
|
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */; };
|
||||||
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */; };
|
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */; };
|
||||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3C1220E134F0006D9BE /* AlbumViewController.swift */; };
|
|
||||||
E408D3CA220E341D0006D9BE /* AlbumItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3C8220E341D0006D9BE /* AlbumItem.swift */; };
|
|
||||||
E408D3CB220E341D0006D9BE /* AlbumItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = E408D3C9220E341D0006D9BE /* AlbumItem.xib */; };
|
|
||||||
E41B22C021FB6BBA00D544F6 /* libmpdclient.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
|
E41B22C021FB6BBA00D544F6 /* libmpdclient.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||||
E41B22C121FB6C3300D544F6 /* libmpdclient.2.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
E41B22C121FB6C3300D544F6 /* libmpdclient.2.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; };
|
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; };
|
||||||
@ -27,8 +24,6 @@
|
|||||||
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC912204F4B80024217A /* QueueViewController.swift */; };
|
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC912204F4B80024217A /* QueueViewController.swift */; };
|
||||||
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC932206097F0024217A /* NotificationsController.swift */; };
|
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC932206097F0024217A /* NotificationsController.swift */; };
|
||||||
E4E8CC9A22075D370024217A /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* Song.swift */; };
|
E4E8CC9A22075D370024217A /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* Song.swift */; };
|
||||||
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB2378220F10B8008C70C0 /* Pair.swift */; };
|
|
||||||
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB237A220F7CF1008C70C0 /* Album.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -78,9 +73,6 @@
|
|||||||
E408D3B5220DD8970006D9BE /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
E408D3B5220DD8970006D9BE /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
||||||
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSUserInterfaceItemIdentifier.swift; sourceTree = "<group>"; };
|
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSUserInterfaceItemIdentifier.swift; sourceTree = "<group>"; };
|
||||||
E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawRepresentable.swift; sourceTree = "<group>"; };
|
E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawRepresentable.swift; sourceTree = "<group>"; };
|
||||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumViewController.swift; sourceTree = "<group>"; };
|
|
||||||
E408D3C8220E341D0006D9BE /* AlbumItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumItem.swift; sourceTree = "<group>"; };
|
|
||||||
E408D3C9220E341D0006D9BE /* AlbumItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlbumItem.xib; sourceTree = "<group>"; };
|
|
||||||
E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpdclient.2.dylib; path = libmpdclient/output/libmpdclient.2.dylib; sourceTree = "<group>"; };
|
E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpdclient.2.dylib; path = libmpdclient/output/libmpdclient.2.dylib; sourceTree = "<group>"; };
|
||||||
E41B22C421FB715A00D544F6 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
E41B22C421FB715A00D544F6 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||||
E41B22C521FB932700D544F6 /* MPDClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDClient.swift; sourceTree = "<group>"; };
|
E41B22C521FB932700D544F6 /* MPDClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDClient.swift; sourceTree = "<group>"; };
|
||||||
@ -125,8 +117,6 @@
|
|||||||
E4E8CC912204F4B80024217A /* QueueViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueViewController.swift; sourceTree = "<group>"; };
|
E4E8CC912204F4B80024217A /* QueueViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueViewController.swift; sourceTree = "<group>"; };
|
||||||
E4E8CC932206097F0024217A /* NotificationsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsController.swift; sourceTree = "<group>"; };
|
E4E8CC932206097F0024217A /* NotificationsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsController.swift; sourceTree = "<group>"; };
|
||||||
E4E8CC9922075D370024217A /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = "<group>"; };
|
E4E8CC9922075D370024217A /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = "<group>"; };
|
||||||
E4EB2378220F10B8008C70C0 /* Pair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pair.swift; sourceTree = "<group>"; };
|
|
||||||
E4EB237A220F7CF1008C70C0 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -182,7 +172,6 @@
|
|||||||
E408D3B7220DE8CC0006D9BE /* Extensions */,
|
E408D3B7220DE8CC0006D9BE /* Extensions */,
|
||||||
E4D1B598220BA3C90026F233 /* Resources */,
|
E4D1B598220BA3C90026F233 /* Resources */,
|
||||||
E4D1B597220BA3A20026F233 /* Controllers */,
|
E4D1B597220BA3A20026F233 /* Controllers */,
|
||||||
E408D3C3220E138B0006D9BE /* Views */,
|
|
||||||
E41B22C721FB966C00D544F6 /* include */,
|
E41B22C721FB966C00D544F6 /* include */,
|
||||||
E407861B2110CE6E006887B1 /* AppDelegate.swift */,
|
E407861B2110CE6E006887B1 /* AppDelegate.swift */,
|
||||||
E40786242110CE70006887B1 /* Info.plist */,
|
E40786242110CE70006887B1 /* Info.plist */,
|
||||||
@ -227,16 +216,6 @@
|
|||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
E408D3C3220E138B0006D9BE /* Views */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
E40786212110CE70006887B1 /* Main.storyboard */,
|
|
||||||
E408D3C8220E341D0006D9BE /* AlbumItem.swift */,
|
|
||||||
E408D3C9220E341D0006D9BE /* AlbumItem.xib */,
|
|
||||||
);
|
|
||||||
path = Views;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
E41B22BE21FB6B3300D544F6 /* Frameworks */ = {
|
E41B22BE21FB6B3300D544F6 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -312,8 +291,6 @@
|
|||||||
children = (
|
children = (
|
||||||
E4E8CC9922075D370024217A /* Song.swift */,
|
E4E8CC9922075D370024217A /* Song.swift */,
|
||||||
E4A642D922090CBE00067D21 /* Status.swift */,
|
E4A642D922090CBE00067D21 /* Status.swift */,
|
||||||
E4EB2378220F10B8008C70C0 /* Pair.swift */,
|
|
||||||
E4EB237A220F7CF1008C70C0 /* Album.swift */,
|
|
||||||
);
|
);
|
||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -329,7 +306,6 @@
|
|||||||
E4D1B597220BA3A20026F233 /* Controllers */ = {
|
E4D1B597220BA3A20026F233 /* Controllers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
|
||||||
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
||||||
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
||||||
E465049921E94DF500A70F4C /* WindowController.swift */,
|
E465049921E94DF500A70F4C /* WindowController.swift */,
|
||||||
@ -341,6 +317,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E407861F2110CE70006887B1 /* Assets.xcassets */,
|
E407861F2110CE70006887B1 /* Assets.xcassets */,
|
||||||
|
E40786212110CE70006887B1 /* Main.storyboard */,
|
||||||
);
|
);
|
||||||
path = Resources;
|
path = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -456,7 +433,6 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
E40786202110CE70006887B1 /* Assets.xcassets in Resources */,
|
E40786202110CE70006887B1 /* Assets.xcassets in Resources */,
|
||||||
E408D3CB220E341D0006D9BE /* AlbumItem.xib in Resources */,
|
|
||||||
E40786232110CE70006887B1 /* Main.storyboard in Resources */,
|
E40786232110CE70006887B1 /* Main.storyboard in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@ -482,21 +458,17 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
|
|
||||||
E4A642DA22090CBE00067D21 /* Status.swift in Sources */,
|
E4A642DA22090CBE00067D21 /* Status.swift in Sources */,
|
||||||
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */,
|
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */,
|
||||||
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
|
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
|
||||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
||||||
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */,
|
|
||||||
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
||||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
||||||
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
|
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
|
||||||
E4E8CC9A22075D370024217A /* Song.swift in Sources */,
|
E4E8CC9A22075D370024217A /* Song.swift in Sources */,
|
||||||
E408D3CA220E341D0006D9BE /* AlbumItem.swift in Sources */,
|
|
||||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
||||||
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */,
|
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */,
|
||||||
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */,
|
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */,
|
||||||
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
//
|
|
||||||
// AlbumViewController.swift
|
|
||||||
// Persephone
|
|
||||||
//
|
|
||||||
// Created by Daniel Barber on 2019/2/08.
|
|
||||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Cocoa
|
|
||||||
|
|
||||||
class AlbumViewController: NSViewController,
|
|
||||||
NSCollectionViewDataSource,
|
|
||||||
NSCollectionViewDelegate {
|
|
||||||
var albums: [MPDClient.Album] = []
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
|
||||||
self,
|
|
||||||
selector: #selector(updateAlbums(_:)),
|
|
||||||
name: Notification.loadedAlbums,
|
|
||||||
object: AppDelegate.mpdClient
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func updateAlbums(_ notification: Notification) {
|
|
||||||
guard let albums = notification.userInfo?[Notification.albumsKey] as? [MPDClient.Album]
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
print("Loaded albums")
|
|
||||||
self.albums = albums
|
|
||||||
|
|
||||||
albumCollectionView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
|
|
||||||
return albums.count
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
|
||||||
let item = collectionView.makeItem(
|
|
||||||
withIdentifier: NSUserInterfaceItemIdentifier("AlbumItem"),
|
|
||||||
for: indexPath
|
|
||||||
)
|
|
||||||
guard let albumItem = item as? AlbumItem else { return item }
|
|
||||||
|
|
||||||
albumItem.view.wantsLayer = true
|
|
||||||
albumItem.setAlbumTitle(albums[indexPath.item].title)
|
|
||||||
albumItem.setAlbumArtist(albums[indexPath.item].artist)
|
|
||||||
|
|
||||||
return albumItem
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBOutlet var albumCollectionView: NSCollectionView!
|
|
||||||
}
|
|
||||||
@ -32,13 +32,6 @@ class NotificationsController: MPDClientDelegate {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.Album]) {
|
|
||||||
sendNotification(
|
|
||||||
name: Notification.loadedAlbums,
|
|
||||||
userInfo: [Notification.albumsKey: albums]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func sendNotification(name: Notification.Name, userInfo: [AnyHashable : Any]) {
|
private func sendNotification(name: Notification.Name, userInfo: [AnyHashable : Any]) {
|
||||||
self.notificationQueue.async {
|
self.notificationQueue.async {
|
||||||
NotificationCenter.default.post(
|
NotificationCenter.default.post(
|
||||||
|
|||||||
@ -12,10 +12,8 @@ extension Notification {
|
|||||||
static let stateChanged = Notification.Name("MPDClientStateChanged")
|
static let stateChanged = Notification.Name("MPDClientStateChanged")
|
||||||
static let queueChanged = Notification.Name("MPDClientQueueChanged")
|
static let queueChanged = Notification.Name("MPDClientQueueChanged")
|
||||||
static let queuePosChanged = Notification.Name("MPDClientQueuePosChanged")
|
static let queuePosChanged = Notification.Name("MPDClientQueuePosChanged")
|
||||||
static let loadedAlbums = Notification.Name("MPDClientLoadedAlbums")
|
|
||||||
|
|
||||||
static let stateKey = "state"
|
static let stateKey = "state"
|
||||||
static let queueKey = "queue"
|
static let queueKey = "queue"
|
||||||
static let queuePosKey = "song"
|
static let queuePosKey = "song"
|
||||||
static let albumsKey = "albums"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,8 +22,7 @@ class MPDClient {
|
|||||||
private let commandQueue = DispatchQueue(label: "commandQueue")
|
private let commandQueue = DispatchQueue(label: "commandQueue")
|
||||||
|
|
||||||
enum Command {
|
enum Command {
|
||||||
case prevTrack, nextTrack, playPause, stop, fetchStatus, fetchQueue,
|
case prevTrack, nextTrack, playPause, stop, fetchStatus, fetchQueue
|
||||||
fetchAllAlbums
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Idle: OptionSet {
|
struct Idle: OptionSet {
|
||||||
@ -58,8 +57,6 @@ class MPDClient {
|
|||||||
|
|
||||||
fetchQueue()
|
fetchQueue()
|
||||||
|
|
||||||
fetchAllAlbums()
|
|
||||||
|
|
||||||
self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state)
|
self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state)
|
||||||
self.delegate?.didUpdateQueue(mpdClient: self, queue: self.queue)
|
self.delegate?.didUpdateQueue(mpdClient: self, queue: self.queue)
|
||||||
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song)
|
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song)
|
||||||
@ -81,10 +78,6 @@ class MPDClient {
|
|||||||
sendCommand(command: .fetchQueue)
|
sendCommand(command: .fetchQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAllAlbums() {
|
|
||||||
sendCommand(command: .fetchAllAlbums)
|
|
||||||
}
|
|
||||||
|
|
||||||
func playPause() {
|
func playPause() {
|
||||||
queueCommand(command: .playPause)
|
queueCommand(command: .playPause)
|
||||||
}
|
}
|
||||||
@ -110,7 +103,6 @@ class MPDClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sendCommand(command: Command) {
|
func sendCommand(command: Command) {
|
||||||
print("Command:", command)
|
|
||||||
switch command {
|
switch command {
|
||||||
|
|
||||||
// Transport commands
|
// Transport commands
|
||||||
@ -122,12 +114,19 @@ class MPDClient {
|
|||||||
sendStop()
|
sendStop()
|
||||||
case .playPause:
|
case .playPause:
|
||||||
sendPlay()
|
sendPlay()
|
||||||
|
|
||||||
case .fetchStatus:
|
case .fetchStatus:
|
||||||
sendRunStatus()
|
guard let status = mpd_run_status(connection) else { break }
|
||||||
|
self.status = Status(status)
|
||||||
|
|
||||||
case .fetchQueue:
|
case .fetchQueue:
|
||||||
sendFetchQueue()
|
self.queue = []
|
||||||
case .fetchAllAlbums:
|
mpd_send_list_queue_meta(connection)
|
||||||
allAlbums()
|
|
||||||
|
while let mpdSong = mpd_recv_song(connection) {
|
||||||
|
let song = Song(mpdSong)
|
||||||
|
self.queue.append(song)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,84 +158,6 @@ class MPDClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendRunStatus() {
|
|
||||||
guard let status = mpd_run_status(connection) else { return }
|
|
||||||
self.status = Status(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendFetchQueue() {
|
|
||||||
self.queue = []
|
|
||||||
mpd_send_list_queue_meta(connection)
|
|
||||||
|
|
||||||
while let mpdSong = mpd_recv_song(connection) {
|
|
||||||
let song = Song(mpdSong)
|
|
||||||
self.queue.append(song)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func allAlbums() {
|
|
||||||
var albums: [Album] = []
|
|
||||||
var artist: String = ""
|
|
||||||
|
|
||||||
mpd_search_db_tags(self.connection, MPD_TAG_ALBUM)
|
|
||||||
mpd_search_add_group_tag(self.connection, MPD_TAG_ALBUM_ARTIST)
|
|
||||||
mpd_search_commit(self.connection)
|
|
||||||
while let mpdPair = mpd_recv_pair(self.connection) {
|
|
||||||
let name = String(cString: mpdPair.pointee.name)
|
|
||||||
let value = String(cString: mpdPair.pointee.value)
|
|
||||||
|
|
||||||
switch name {
|
|
||||||
case "AlbumArtist":
|
|
||||||
artist = value
|
|
||||||
case "Album":
|
|
||||||
albums.append(Album(title: value, artist: artist))
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
mpd_return_pair(self.connection, mpdPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate?.didLoadAlbums(mpdClient: self, albums: albums)
|
|
||||||
}
|
|
||||||
|
|
||||||
func albumsForArtist(_ artist: String) -> [Album] {
|
|
||||||
var albums: [Album] = []
|
|
||||||
|
|
||||||
mpd_search_db_tags(self.connection, MPD_TAG_ALBUM)
|
|
||||||
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ARTIST, artist)
|
|
||||||
mpd_search_commit(self.connection)
|
|
||||||
while let mpdAlbumPair = mpd_recv_pair_tag(self.connection, MPD_TAG_ALBUM) {
|
|
||||||
print(artist, "-", String(cString: mpdAlbumPair.pointee.value))
|
|
||||||
albums.append(Album(title: String(cString: mpdAlbumPair.pointee.value), artist: artist))
|
|
||||||
mpd_return_pair(self.connection, mpdAlbumPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
return albums
|
|
||||||
}
|
|
||||||
|
|
||||||
func allArtists() -> [String] {
|
|
||||||
var artists: [String] = []
|
|
||||||
|
|
||||||
mpd_search_db_tags(self.connection, MPD_TAG_ARTIST)
|
|
||||||
mpd_search_commit(self.connection)
|
|
||||||
while let mpdArtistPair = mpd_recv_pair_tag(self.connection, MPD_TAG_ARTIST) {
|
|
||||||
artists.append(String(cString: mpdArtistPair.pointee.value))
|
|
||||||
mpd_return_pair(self.connection, mpdArtistPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
return artists
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendSearchDbTags(_ tagType: mpd_tag_type) {
|
|
||||||
mpd_search_db_tags(self.connection, tagType)
|
|
||||||
mpd_search_commit(self.connection)
|
|
||||||
while let mpdPair = mpd_recv_pair_tag(self.connection, tagType) {
|
|
||||||
print(String(cString: mpdPair.pointee.value))
|
|
||||||
mpd_return_pair(self.connection, mpdPair)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func noIdle() {
|
func noIdle() {
|
||||||
mpd_send_noidle(connection)
|
mpd_send_noidle(connection)
|
||||||
}
|
}
|
||||||
@ -263,7 +184,6 @@ class MPDClient {
|
|||||||
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song)
|
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song)
|
||||||
}
|
}
|
||||||
if !mpdIdle.isEmpty {
|
if !mpdIdle.isEmpty {
|
||||||
print("Status")
|
|
||||||
self.idle()
|
self.idle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
//
|
|
||||||
// Album.swift
|
|
||||||
// Persephone
|
|
||||||
//
|
|
||||||
// Created by Daniel Barber on 2019/2/09.
|
|
||||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
extension MPDClient {
|
|
||||||
class Album {
|
|
||||||
let title: String
|
|
||||||
let artist: String
|
|
||||||
|
|
||||||
init(title: String, artist: String) {
|
|
||||||
self.title = title
|
|
||||||
self.artist = artist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
//
|
|
||||||
// Pair.swift
|
|
||||||
// Persephone
|
|
||||||
//
|
|
||||||
// Created by Daniel Barber on 2019/2/09.
|
|
||||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import mpdclient
|
|
||||||
|
|
||||||
class Pair {
|
|
||||||
let mpdPair: UnsafeMutablePointer<mpd_pair>
|
|
||||||
|
|
||||||
init(_ mpdPair: UnsafeMutablePointer<mpd_pair>) {
|
|
||||||
self.mpdPair = mpdPair
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -12,5 +12,4 @@ protocol MPDClientDelegate {
|
|||||||
func didUpdateState(mpdClient: MPDClient, state: MPDClient.Status.State)
|
func didUpdateState(mpdClient: MPDClient, state: MPDClient.Status.State)
|
||||||
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song])
|
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song])
|
||||||
func didUpdateQueuePos(mpdClient: MPDClient, song: Int)
|
func didUpdateQueuePos(mpdClient: MPDClient, song: Int)
|
||||||
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.Album])
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "blankAlbum.pdf"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
@ -908,55 +908,47 @@
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="744" y="459"/>
|
<point key="canvasLocation" x="744" y="459"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--Album View Controller-->
|
<!--View Controller-->
|
||||||
<scene sceneID="7Ua-Hj-zWt">
|
<scene sceneID="7Ua-Hj-zWt">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController id="gPn-fP-LFc" customClass="AlbumViewController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
<viewController id="gPn-fP-LFc" sceneMemberID="viewController">
|
||||||
<view key="view" id="v1d-6d-Fl3">
|
<view key="view" id="v1d-6d-Fl3">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<scrollView wantsLayer="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="i5f-35-7x8">
|
<scrollView wantsLayer="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wia-Qk-FEw">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||||
<clipView key="contentView" id="iXE-Xl-zu6">
|
<clipView key="contentView" id="leP-Jn-VMY">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<collectionView id="lfq-AB-epE">
|
<collectionView id="2XB-gk-sPO">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="450" height="158"/>
|
<rect key="frame" x="0.0" y="0.0" width="450" height="158"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
|
||||||
<collectionViewFlowLayout key="collectionViewLayout" minimumInteritemSpacing="20" minimumLineSpacing="20" id="K0l-P8-OW0">
|
<collectionViewFlowLayout key="collectionViewLayout" minimumInteritemSpacing="10" minimumLineSpacing="10" id="OKj-Q2-LS1">
|
||||||
<size key="itemSize" width="206" height="248"/>
|
<size key="itemSize" width="50" height="50"/>
|
||||||
<edgeInsets key="sectionInset" left="40" right="40" top="20" bottom="60"/>
|
|
||||||
</collectionViewFlowLayout>
|
</collectionViewFlowLayout>
|
||||||
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<connections>
|
|
||||||
<outlet property="dataSource" destination="gPn-fP-LFc" id="2VB-5V-ltv"/>
|
|
||||||
<outlet property="delegate" destination="gPn-fP-LFc" id="LQ2-Vl-r08"/>
|
|
||||||
</connections>
|
|
||||||
</collectionView>
|
</collectionView>
|
||||||
</subviews>
|
</subviews>
|
||||||
</clipView>
|
</clipView>
|
||||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="bK3-Ei-Odz">
|
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="Dqn-NC-UFS">
|
||||||
<rect key="frame" x="1" y="213" width="348" height="16"/>
|
<rect key="frame" x="1" y="144" width="233" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="SkF-fO-hfN">
|
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="Enn-qw-4lt">
|
||||||
<rect key="frame" x="234" y="1" width="15" height="143"/>
|
<rect key="frame" x="234" y="1" width="15" height="143"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
</scrollView>
|
</scrollView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="i5f-35-7x8" firstAttribute="top" secondItem="v1d-6d-Fl3" secondAttribute="top" id="BXd-LQ-OWX"/>
|
<constraint firstItem="wia-Qk-FEw" firstAttribute="top" secondItem="v1d-6d-Fl3" secondAttribute="top" id="NG4-cV-AAv"/>
|
||||||
<constraint firstItem="i5f-35-7x8" firstAttribute="leading" secondItem="v1d-6d-Fl3" secondAttribute="leading" id="Bgm-NV-0Ft"/>
|
<constraint firstAttribute="bottom" secondItem="wia-Qk-FEw" secondAttribute="bottom" id="emh-fE-n6N"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="i5f-35-7x8" secondAttribute="bottom" id="G8K-PG-9Zq"/>
|
<constraint firstAttribute="trailing" secondItem="wia-Qk-FEw" secondAttribute="trailing" id="izX-0D-aEA"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="i5f-35-7x8" secondAttribute="trailing" id="vcm-wb-Ghi"/>
|
<constraint firstItem="wia-Qk-FEw" firstAttribute="leading" secondItem="v1d-6d-Fl3" secondAttribute="leading" id="v7v-S1-h5Z"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<connections>
|
|
||||||
<outlet property="albumCollectionView" destination="lfq-AB-epE" id="p69-Fs-hCN"/>
|
|
||||||
</connections>
|
|
||||||
</viewController>
|
</viewController>
|
||||||
<customObject id="uex-Ws-5X4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="uex-Ws-5X4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
@ -1,27 +0,0 @@
|
|||||||
//
|
|
||||||
// AlbumItem.swift
|
|
||||||
// Persephone
|
|
||||||
//
|
|
||||||
// Created by Daniel Barber on 2019/2/08.
|
|
||||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Cocoa
|
|
||||||
|
|
||||||
class AlbumItem: NSCollectionViewItem {
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
// Do view setup here.
|
|
||||||
}
|
|
||||||
|
|
||||||
func setAlbumTitle(_ title: String) {
|
|
||||||
albumTitle.stringValue = title
|
|
||||||
}
|
|
||||||
|
|
||||||
func setAlbumArtist(_ artist: String) {
|
|
||||||
albumArtist.stringValue = artist
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBOutlet var albumTitle: NSTextField!
|
|
||||||
@IBOutlet var albumArtist: NSTextField!
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
|
||||||
<dependencies>
|
|
||||||
<deployment identifier="macosx"/>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
|
||||||
<objects>
|
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="AlbumItem" customModule="Persephone" customModuleProvider="target">
|
|
||||||
<connections>
|
|
||||||
<outlet property="albumArtist" destination="5Uu-j1-qyT" id="2Et-tX-InT"/>
|
|
||||||
<outlet property="albumTitle" destination="KEh-NL-c2W" id="SI3-hm-H2B"/>
|
|
||||||
<outlet property="view" destination="Hz6-mo-xeY" id="v7W-XA-Emc"/>
|
|
||||||
</connections>
|
|
||||||
</customObject>
|
|
||||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
|
||||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
|
||||||
<customView id="Hz6-mo-xeY">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="206" height="248"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
|
||||||
<subviews>
|
|
||||||
<textField identifier="albumTitle" horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" preferredMaxLayoutWidth="206" translatesAutoresizingMaskIntoConstraints="NO" id="KEh-NL-c2W">
|
|
||||||
<rect key="frame" x="-2" y="20" width="210" height="17"/>
|
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" title="Label" id="pDs-0t-e1j">
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</textFieldCell>
|
|
||||||
</textField>
|
|
||||||
<textField identifier="albumArtist" horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" preferredMaxLayoutWidth="206" translatesAutoresizingMaskIntoConstraints="NO" id="5Uu-j1-qyT">
|
|
||||||
<rect key="frame" x="-2" y="0.0" width="210" height="17"/>
|
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" title="Label" id="yZn-e9-zyP">
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</textFieldCell>
|
|
||||||
</textField>
|
|
||||||
<imageView identifier="albumArtwork" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Kfb-8f-ean">
|
|
||||||
<rect key="frame" x="0.0" y="42" width="206" height="206"/>
|
|
||||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="blankAlbum" id="FsA-JX-BFh"/>
|
|
||||||
</imageView>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="KEh-NL-c2W" firstAttribute="leading" secondItem="5Uu-j1-qyT" secondAttribute="leading" id="Iji-NN-ju3"/>
|
|
||||||
<constraint firstItem="Kfb-8f-ean" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="JMi-4i-dgs"/>
|
|
||||||
<constraint firstItem="KEh-NL-c2W" firstAttribute="top" secondItem="Kfb-8f-ean" secondAttribute="bottom" constant="5" id="Jdb-sY-lnB"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="Kfb-8f-ean" secondAttribute="trailing" id="KQC-Wz-Bsg"/>
|
|
||||||
<constraint firstItem="Kfb-8f-ean" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="Qbk-jx-zAi"/>
|
|
||||||
<constraint firstItem="Kfb-8f-ean" firstAttribute="leading" secondItem="KEh-NL-c2W" secondAttribute="leading" id="diY-bi-0Yg"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="5Uu-j1-qyT" secondAttribute="bottom" id="puG-ym-5hh"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="KEh-NL-c2W" secondAttribute="bottom" constant="20" symbolic="YES" id="yIJ-L1-2c5"/>
|
|
||||||
</constraints>
|
|
||||||
<point key="canvasLocation" x="3" y="142"/>
|
|
||||||
</customView>
|
|
||||||
<collectionViewItem id="Qgu-aI-55A" customClass="AlbumItem" customModule="Persephone" customModuleProvider="target"/>
|
|
||||||
</objects>
|
|
||||||
<resources>
|
|
||||||
<image name="blankAlbum" width="128" height="128"/>
|
|
||||||
</resources>
|
|
||||||
</document>
|
|
||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user