mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Add album view
This commit is contained in:
parent
3cbb24f50d
commit
447432120a
@ -15,6 +15,9 @@
|
||||
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B5220DD8970006D9BE /* Notification.swift */; };
|
||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.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, ); }; };
|
||||
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 */; };
|
||||
@ -24,6 +27,8 @@
|
||||
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC912204F4B80024217A /* QueueViewController.swift */; };
|
||||
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC932206097F0024217A /* NotificationsController.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 */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -73,6 +78,9 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -117,6 +125,8 @@
|
||||
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>"; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -172,6 +182,7 @@
|
||||
E408D3B7220DE8CC0006D9BE /* Extensions */,
|
||||
E4D1B598220BA3C90026F233 /* Resources */,
|
||||
E4D1B597220BA3A20026F233 /* Controllers */,
|
||||
E408D3C3220E138B0006D9BE /* Views */,
|
||||
E41B22C721FB966C00D544F6 /* include */,
|
||||
E407861B2110CE6E006887B1 /* AppDelegate.swift */,
|
||||
E40786242110CE70006887B1 /* Info.plist */,
|
||||
@ -216,6 +227,16 @@
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E408D3C3220E138B0006D9BE /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E40786212110CE70006887B1 /* Main.storyboard */,
|
||||
E408D3C8220E341D0006D9BE /* AlbumItem.swift */,
|
||||
E408D3C9220E341D0006D9BE /* AlbumItem.xib */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E41B22BE21FB6B3300D544F6 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -291,6 +312,8 @@
|
||||
children = (
|
||||
E4E8CC9922075D370024217A /* Song.swift */,
|
||||
E4A642D922090CBE00067D21 /* Status.swift */,
|
||||
E4EB2378220F10B8008C70C0 /* Pair.swift */,
|
||||
E4EB237A220F7CF1008C70C0 /* Album.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@ -306,6 +329,7 @@
|
||||
E4D1B597220BA3A20026F233 /* Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
||||
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
||||
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
||||
E465049921E94DF500A70F4C /* WindowController.swift */,
|
||||
@ -317,7 +341,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E407861F2110CE70006887B1 /* Assets.xcassets */,
|
||||
E40786212110CE70006887B1 /* Main.storyboard */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
@ -433,6 +456,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E40786202110CE70006887B1 /* Assets.xcassets in Resources */,
|
||||
E408D3CB220E341D0006D9BE /* AlbumItem.xib in Resources */,
|
||||
E40786232110CE70006887B1 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -458,17 +482,21 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
|
||||
E4A642DA22090CBE00067D21 /* Status.swift in Sources */,
|
||||
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */,
|
||||
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
|
||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
||||
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */,
|
||||
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
||||
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
|
||||
E4E8CC9A22075D370024217A /* Song.swift in Sources */,
|
||||
E408D3CA220E341D0006D9BE /* AlbumItem.swift in Sources */,
|
||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
||||
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */,
|
||||
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */,
|
||||
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
56
Persephone/Controllers/AlbumViewController.swift
Normal file
56
Persephone/Controllers/AlbumViewController.swift
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// 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,6 +32,13 @@ 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]) {
|
||||
self.notificationQueue.async {
|
||||
NotificationCenter.default.post(
|
||||
|
||||
@ -12,8 +12,10 @@ extension Notification {
|
||||
static let stateChanged = Notification.Name("MPDClientStateChanged")
|
||||
static let queueChanged = Notification.Name("MPDClientQueueChanged")
|
||||
static let queuePosChanged = Notification.Name("MPDClientQueuePosChanged")
|
||||
static let loadedAlbums = Notification.Name("MPDClientLoadedAlbums")
|
||||
|
||||
static let stateKey = "state"
|
||||
static let queueKey = "queue"
|
||||
static let queuePosKey = "song"
|
||||
static let albumsKey = "albums"
|
||||
}
|
||||
|
||||
@ -22,7 +22,8 @@ class MPDClient {
|
||||
private let commandQueue = DispatchQueue(label: "commandQueue")
|
||||
|
||||
enum Command {
|
||||
case prevTrack, nextTrack, playPause, stop, fetchStatus, fetchQueue
|
||||
case prevTrack, nextTrack, playPause, stop, fetchStatus, fetchQueue,
|
||||
fetchAllAlbums
|
||||
}
|
||||
|
||||
struct Idle: OptionSet {
|
||||
@ -57,6 +58,8 @@ class MPDClient {
|
||||
|
||||
fetchQueue()
|
||||
|
||||
fetchAllAlbums()
|
||||
|
||||
self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state)
|
||||
self.delegate?.didUpdateQueue(mpdClient: self, queue: self.queue)
|
||||
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song)
|
||||
@ -78,6 +81,10 @@ class MPDClient {
|
||||
sendCommand(command: .fetchQueue)
|
||||
}
|
||||
|
||||
func fetchAllAlbums() {
|
||||
sendCommand(command: .fetchAllAlbums)
|
||||
}
|
||||
|
||||
func playPause() {
|
||||
queueCommand(command: .playPause)
|
||||
}
|
||||
@ -103,6 +110,7 @@ class MPDClient {
|
||||
}
|
||||
|
||||
func sendCommand(command: Command) {
|
||||
print("Command:", command)
|
||||
switch command {
|
||||
|
||||
// Transport commands
|
||||
@ -114,19 +122,12 @@ class MPDClient {
|
||||
sendStop()
|
||||
case .playPause:
|
||||
sendPlay()
|
||||
|
||||
case .fetchStatus:
|
||||
guard let status = mpd_run_status(connection) else { break }
|
||||
self.status = Status(status)
|
||||
|
||||
sendRunStatus()
|
||||
case .fetchQueue:
|
||||
self.queue = []
|
||||
mpd_send_list_queue_meta(connection)
|
||||
|
||||
while let mpdSong = mpd_recv_song(connection) {
|
||||
let song = Song(mpdSong)
|
||||
self.queue.append(song)
|
||||
}
|
||||
sendFetchQueue()
|
||||
case .fetchAllAlbums:
|
||||
allAlbums()
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,6 +159,84 @@ 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() {
|
||||
mpd_send_noidle(connection)
|
||||
}
|
||||
@ -184,6 +263,7 @@ class MPDClient {
|
||||
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song)
|
||||
}
|
||||
if !mpdIdle.isEmpty {
|
||||
print("Status")
|
||||
self.idle()
|
||||
}
|
||||
}
|
||||
|
||||
21
Persephone/MPDClient/Models/Album.swift
Normal file
21
Persephone/MPDClient/Models/Album.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Persephone/MPDClient/Models/Pair.swift
Normal file
18
Persephone/MPDClient/Models/Pair.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// 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,4 +12,5 @@ protocol MPDClientDelegate {
|
||||
func didUpdateState(mpdClient: MPDClient, state: MPDClient.Status.State)
|
||||
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song])
|
||||
func didUpdateQueuePos(mpdClient: MPDClient, song: Int)
|
||||
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.Album])
|
||||
}
|
||||
|
||||
12
Persephone/Resources/Assets.xcassets/blankAlbum.imageset/Contents.json
vendored
Normal file
12
Persephone/Resources/Assets.xcassets/blankAlbum.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "blankAlbum.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Persephone/Resources/Assets.xcassets/blankAlbum.imageset/blankAlbum.pdf
vendored
Normal file
BIN
Persephone/Resources/Assets.xcassets/blankAlbum.imageset/blankAlbum.pdf
vendored
Normal file
Binary file not shown.
27
Persephone/Views/AlbumItem.swift
Normal file
27
Persephone/Views/AlbumItem.swift
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// 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!
|
||||
}
|
||||
60
Persephone/Views/AlbumItem.xib
Normal file
60
Persephone/Views/AlbumItem.xib
Normal file
@ -0,0 +1,60 @@
|
||||
<?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" translatesAutoresizingMaskIntoConstraints="NO" id="KEh-NL-c2W">
|
||||
<rect key="frame" x="-2" y="20" width="37" height="17"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" 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" translatesAutoresizingMaskIntoConstraints="NO" id="5Uu-j1-qyT">
|
||||
<rect key="frame" x="-2" y="0.0" width="37" height="17"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" 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>
|
||||
@ -908,47 +908,55 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="744" y="459"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<!--Album View Controller-->
|
||||
<scene sceneID="7Ua-Hj-zWt">
|
||||
<objects>
|
||||
<viewController id="gPn-fP-LFc" sceneMemberID="viewController">
|
||||
<viewController id="gPn-fP-LFc" customClass="AlbumViewController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="v1d-6d-Fl3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<scrollView wantsLayer="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wia-Qk-FEw">
|
||||
<scrollView wantsLayer="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="i5f-35-7x8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||
<clipView key="contentView" id="leP-Jn-VMY">
|
||||
<clipView key="contentView" id="iXE-Xl-zu6">
|
||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView id="2XB-gk-sPO">
|
||||
<collectionView id="lfq-AB-epE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="450" height="158"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumInteritemSpacing="10" minimumLineSpacing="10" id="OKj-Q2-LS1">
|
||||
<size key="itemSize" width="50" height="50"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumInteritemSpacing="20" minimumLineSpacing="20" id="K0l-P8-OW0">
|
||||
<size key="itemSize" width="206" height="248"/>
|
||||
<edgeInsets key="sectionInset" left="40" right="40" top="20" bottom="60"/>
|
||||
</collectionViewFlowLayout>
|
||||
<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>
|
||||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="Dqn-NC-UFS">
|
||||
<rect key="frame" x="1" y="144" width="233" height="15"/>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="bK3-Ei-Odz">
|
||||
<rect key="frame" x="1" y="213" width="348" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="Enn-qw-4lt">
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="SkF-fO-hfN">
|
||||
<rect key="frame" x="234" y="1" width="15" height="143"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="wia-Qk-FEw" firstAttribute="top" secondItem="v1d-6d-Fl3" secondAttribute="top" id="NG4-cV-AAv"/>
|
||||
<constraint firstAttribute="bottom" secondItem="wia-Qk-FEw" secondAttribute="bottom" id="emh-fE-n6N"/>
|
||||
<constraint firstAttribute="trailing" secondItem="wia-Qk-FEw" secondAttribute="trailing" id="izX-0D-aEA"/>
|
||||
<constraint firstItem="wia-Qk-FEw" firstAttribute="leading" secondItem="v1d-6d-Fl3" secondAttribute="leading" id="v7v-S1-h5Z"/>
|
||||
<constraint firstItem="i5f-35-7x8" firstAttribute="top" secondItem="v1d-6d-Fl3" secondAttribute="top" id="BXd-LQ-OWX"/>
|
||||
<constraint firstItem="i5f-35-7x8" firstAttribute="leading" secondItem="v1d-6d-Fl3" secondAttribute="leading" id="Bgm-NV-0Ft"/>
|
||||
<constraint firstAttribute="bottom" secondItem="i5f-35-7x8" secondAttribute="bottom" id="G8K-PG-9Zq"/>
|
||||
<constraint firstAttribute="trailing" secondItem="i5f-35-7x8" secondAttribute="trailing" id="vcm-wb-Ghi"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="albumCollectionView" destination="lfq-AB-epE" id="p69-Fs-hCN"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="uex-Ws-5X4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
BIN
Resources/export/blankAlbum.pdf
Normal file
BIN
Resources/export/blankAlbum.pdf
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user