iOS Now Playing
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1220"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E411C26C241C10F0008B9682"
|
||||
BuildableName = "Persephone.app"
|
||||
BlueprintName = "Persephone-iOS"
|
||||
ReferencedContainer = "container:Persephone.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E411C281241C10F5008B9682"
|
||||
BuildableName = "Persephone-iOSTests.xctest"
|
||||
BlueprintName = "Persephone-iOSTests"
|
||||
ReferencedContainer = "container:Persephone.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E411C28C241C10F5008B9682"
|
||||
BuildableName = "Persephone-iOSUITests.xctest"
|
||||
BlueprintName = "Persephone-iOSUITests"
|
||||
ReferencedContainer = "container:Persephone.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E411C26C241C10F0008B9682"
|
||||
BuildableName = "Persephone.app"
|
||||
BlueprintName = "Persephone-iOS"
|
||||
ReferencedContainer = "container:Persephone.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E411C26C241C10F0008B9682"
|
||||
BuildableName = "Persephone.app"
|
||||
BlueprintName = "Persephone-iOS"
|
||||
ReferencedContainer = "container:Persephone.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
BIN
Resources/export/iosAppIcon.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
Resources/export/iosAppIcon@2x.png
Normal file
|
After Width: | Height: | Size: 548 KiB |
BIN
Resources/export/nextTrackButtonHugeiOS.pdf
Normal file
BIN
Resources/export/nextTrackButtonHugeiOS.png
Normal file
|
After Width: | Height: | Size: 687 B |
BIN
Resources/export/nextTrackButtonHugeiOS@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Resources/export/nextTrackButtonHugeiOS@3x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Resources/export/pauseButtonHugeiOS.pdf
Normal file
BIN
Resources/export/pauseButtonHugeiOS.png
Normal file
|
After Width: | Height: | Size: 313 B |
BIN
Resources/export/pauseButtonHugeiOS@2x.png
Normal file
|
After Width: | Height: | Size: 545 B |
BIN
Resources/export/pauseButtonHugeiOS@3x.png
Normal file
|
After Width: | Height: | Size: 972 B |
BIN
Resources/export/playButtonHugeiOS.pdf
Normal file
BIN
Resources/export/playButtonHugeiOS.png
Normal file
|
After Width: | Height: | Size: 657 B |
BIN
Resources/export/playButtonHugeiOS@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Resources/export/playButtonHugeiOS@3x.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
Resources/export/prevTrackButtonHugeiOS.pdf
Normal file
BIN
Resources/export/prevTrackButtonHugeiOS.png
Normal file
|
After Width: | Height: | Size: 681 B |
BIN
Resources/export/prevTrackButtonHugeiOS@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
iOS/Assets.xcassets/nextTrackButtonHugeiOS.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "nextTrackButtonHugeiOS.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true,
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
BIN
iOS/Assets.xcassets/nextTrackButtonHugeiOS.imageset/nextTrackButtonHugeiOS.pdf
vendored
Normal file
16
iOS/Assets.xcassets/pauseButtonHugeiOS.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "pauseButtonHugeiOS.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true,
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
BIN
iOS/Assets.xcassets/pauseButtonHugeiOS.imageset/pauseButtonHugeiOS.pdf
vendored
Normal file
16
iOS/Assets.xcassets/playButtonHugeiOS.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "playButtonHugeiOS.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true,
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
BIN
iOS/Assets.xcassets/playButtonHugeiOS.imageset/playButtonHugeiOS.pdf
vendored
Normal file
16
iOS/Assets.xcassets/prevTrackButtonHugeiOS.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "prevTrackButtonHugeiOS.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true,
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
BIN
iOS/Assets.xcassets/prevTrackButtonHugeiOS.imageset/prevTrackButtonHugeiOS.pdf
vendored
Normal file
16
iOS/Assets.xcassets/speakerHigh.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "speakerHigh.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true,
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
BIN
iOS/Assets.xcassets/speakerHigh.imageset/speakerHigh.pdf
vendored
Normal file
16
iOS/Assets.xcassets/speakerOff.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "speakerOff.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true,
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
BIN
iOS/Assets.xcassets/speakerOff.imageset/speakerOff.pdf
vendored
Normal file
@ -34,6 +34,7 @@ class AlbumViewController: UICollectionViewController {
|
||||
}
|
||||
|
||||
@objc func didConnect() {
|
||||
print("Album view controller - Connected!")
|
||||
App.mpdClient.fetchAllAlbums()
|
||||
}
|
||||
|
||||
|
||||
134
iOS/Components/Now Playing/NowPlayingBarViewController.swift
Normal file
@ -0,0 +1,134 @@
|
||||
//
|
||||
// NowPlayingViewController.swift
|
||||
// Persephone-iOS
|
||||
//
|
||||
// Created by Dan Barber on 2020-5-15.
|
||||
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ReSwift
|
||||
import Kingfisher
|
||||
|
||||
class NowPlayingBarViewController: UIViewController {
|
||||
@IBOutlet var separatorHeight: NSLayoutConstraint!
|
||||
@IBOutlet var playPauseButton: UIButton!
|
||||
@IBOutlet var nextButton: UIButton!
|
||||
@IBOutlet var songTitle: UILabel!
|
||||
@IBOutlet var albumCoverView: UIImageView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
separatorHeight.constant = 1 / traitCollection.displayScale
|
||||
|
||||
App.store.subscribe(self) {
|
||||
$0.select {
|
||||
($0.playerState, $0.queueState)
|
||||
}
|
||||
}
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didConnect), name: .didConnect, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willDisconnect), name: .willDisconnect, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didReloadAlbumArt), name: .didReloadAlbumArt, object: nil)
|
||||
|
||||
albumCoverView.layer.backgroundColor = UIColor.black.cgColor
|
||||
albumCoverView.layer.cornerRadius = 4
|
||||
albumCoverView.layer.borderWidth = 1 / traitCollection.displayScale
|
||||
albumCoverView.layer.masksToBounds = true
|
||||
|
||||
setAppearance()
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
|
||||
separatorHeight.constant = 1 / traitCollection.displayScale
|
||||
|
||||
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
|
||||
setAppearance()
|
||||
}
|
||||
}
|
||||
|
||||
func setAppearance() {
|
||||
let darkMode = traitCollection.userInterfaceStyle == .dark
|
||||
|
||||
albumCoverView.layer.borderColor = darkMode ? CGColor.albumBorderColorDark : CGColor.albumBorderColorLight
|
||||
}
|
||||
|
||||
@objc func didConnect() {
|
||||
App.mpdClient.fetchQueue()
|
||||
}
|
||||
|
||||
@objc func willDisconnect() {
|
||||
DispatchQueue.main.async {
|
||||
App.store.dispatch(UpdateQueuePosAction(queuePos: -1))
|
||||
App.store.dispatch(UpdateQueueAction(queue: []))
|
||||
}
|
||||
}
|
||||
|
||||
@objc func didReloadAlbumArt() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
func setTransportControlState(_ state: PlayerState) {
|
||||
guard let state = state.state else { return }
|
||||
|
||||
playPauseButton.isEnabled = state.isOneOf([.playing, .paused, .stopped])
|
||||
nextButton.isEnabled = state.isOneOf([.playing, .paused])
|
||||
|
||||
if state.isOneOf([.paused, .stopped, .unknown]) {
|
||||
playPauseButton.setImage(.playIconLarge, for: .normal)
|
||||
} else {
|
||||
playPauseButton.setImage(.pauseIconLarge, for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
func setSong(_ song: Song?) {
|
||||
guard let song = song else {
|
||||
self.songTitle.text = "Not Playing"
|
||||
self.albumCoverView.image = .defaultCoverArt
|
||||
return
|
||||
}
|
||||
|
||||
songTitle.text = song.title
|
||||
|
||||
let provider = MPDAlbumArtImageDataProvider(
|
||||
songUri: song.mpdSong.uriString,
|
||||
cacheKey: song.album.hash
|
||||
)
|
||||
|
||||
albumCoverView.kf.setImage(
|
||||
with: .provider(provider),
|
||||
placeholder: UIImage.defaultCoverArt,
|
||||
options: [
|
||||
.processor(DownsamplingImageProcessor(size: .queueSongCoverSize)),
|
||||
.scaleFactor(traitCollection.displayScale),
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction func playPauseButtonAction(_ sender: Any) {
|
||||
App.mpdClient.playPause()
|
||||
}
|
||||
|
||||
@IBAction func nextButtonAction(_ sender: Any) {
|
||||
App.mpdClient.nextTrack()
|
||||
}
|
||||
|
||||
@IBAction func expandNowPlaying(_ sender: Any) {
|
||||
}
|
||||
}
|
||||
|
||||
extension NowPlayingBarViewController: StoreSubscriber {
|
||||
typealias StoreSubscriberStateType = (
|
||||
playerState: PlayerState, queueState: QueueState
|
||||
)
|
||||
|
||||
func newState(state: StoreSubscriberStateType) {
|
||||
DispatchQueue.main.async {
|
||||
self.setTransportControlState(state.playerState)
|
||||
self.setSong(state.playerState.currentSong)
|
||||
}
|
||||
}
|
||||
}
|
||||
131
iOS/Components/Now Playing/NowPlayingBarViewController.xib
Normal file
@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="Stack View standard spacing" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="NowPlayingBarViewController" customModule="Persephone" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="albumCoverView" destination="6Cn-Qu-3ab" id="w0j-pd-zrj"/>
|
||||
<outlet property="nextButton" destination="k9u-Hf-Cp0" id="bs9-R1-q5h"/>
|
||||
<outlet property="playPauseButton" destination="aJD-nr-kHS" id="6sM-tz-FHK"/>
|
||||
<outlet property="separatorHeight" destination="chi-7m-8Ds" id="Ex2-Wm-ygG"/>
|
||||
<outlet property="songTitle" destination="4nQ-FU-7Ub" id="eGu-nR-CuK"/>
|
||||
<outlet property="view" destination="fma-vB-sY1" id="5BF-fd-Kur"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" id="fma-vB-sY1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="9j9-AN-ijy">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="63"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="defaultCoverArt" translatesAutoresizingMaskIntoConstraints="NO" id="6Cn-Qu-3ab">
|
||||
<rect key="frame" x="20" y="8" width="47" height="47"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="6Cn-Qu-3ab" secondAttribute="height" multiplier="1:1" id="I6V-Kn-Cwa"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Tik-7x-PaQ">
|
||||
<rect key="frame" x="75" y="8" width="0.0" height="47"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" id="DuG-NI-0Bp"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="249" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Not Playing" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4nQ-FU-7Ub">
|
||||
<rect key="frame" x="83" y="8" width="152" height="47"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="center" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aJD-nr-kHS" userLabel="PlayButton">
|
||||
<rect key="frame" x="243" y="8" width="32" height="47"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="4Un-9M-vOk"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="32" id="MMT-BK-4vu"/>
|
||||
</constraints>
|
||||
<color key="tintColor" systemColor="labelColor"/>
|
||||
<state key="normal" image="playButtonLarge">
|
||||
<color key="titleColor" systemColor="labelColor"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="playPauseButtonAction:" destination="-1" eventType="touchUpInside" id="a3n-1h-p00"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="center" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k9u-Hf-Cp0" userLabel="NextButton">
|
||||
<rect key="frame" x="283" y="8" width="32" height="47"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="32" id="etc-kL-NdJ"/>
|
||||
<constraint firstAttribute="width" constant="32" id="fy0-Z2-OSg"/>
|
||||
</constraints>
|
||||
<color key="tintColor" systemColor="labelColor"/>
|
||||
<state key="normal" image="nextTrackButtonLarge">
|
||||
<color key="titleColor" systemColor="labelColor"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="nextButtonAction:" destination="-1" eventType="touchUpInside" id="3Ke-PH-ud9"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="Xfd-VS-LUl"/>
|
||||
<directionalEdgeInsets key="directionalLayoutMargins" top="8" leading="20" bottom="8" trailing="20"/>
|
||||
</stackView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uXQ-Mb-Jkv" userLabel="ExpandButton">
|
||||
<rect key="frame" x="20" y="8" width="215" height="47"/>
|
||||
<state key="normal">
|
||||
<color key="titleColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="expandNowPlaying:" destination="-1" eventType="touchUpInside" id="F2I-ho-gVx"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2EO-qL-ast">
|
||||
<rect key="frame" x="0.0" y="63" width="335" height="1"/>
|
||||
<color key="backgroundColor" systemColor="separatorColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="chi-7m-8Ds"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="uXQ-Mb-Jkv" firstAttribute="bottom" secondItem="6Cn-Qu-3ab" secondAttribute="bottom" id="9FW-TH-Tef"/>
|
||||
<constraint firstItem="9j9-AN-ijy" firstAttribute="top" secondItem="fma-vB-sY1" secondAttribute="top" id="Bpq-6d-BwN"/>
|
||||
<constraint firstItem="uXQ-Mb-Jkv" firstAttribute="trailing" secondItem="4nQ-FU-7Ub" secondAttribute="trailing" id="SI9-AZ-DKb"/>
|
||||
<constraint firstItem="uXQ-Mb-Jkv" firstAttribute="leading" secondItem="6Cn-Qu-3ab" secondAttribute="leading" id="Wae-93-MpQ"/>
|
||||
<constraint firstItem="9j9-AN-ijy" firstAttribute="leading" secondItem="fma-vB-sY1" secondAttribute="leading" id="aG7-qp-jXe"/>
|
||||
<constraint firstAttribute="trailing" secondItem="9j9-AN-ijy" secondAttribute="trailing" id="cCF-6v-1x0"/>
|
||||
<constraint firstAttribute="trailing" secondItem="2EO-qL-ast" secondAttribute="trailing" id="dp6-XJ-FaI"/>
|
||||
<constraint firstItem="2EO-qL-ast" firstAttribute="top" secondItem="9j9-AN-ijy" secondAttribute="bottom" id="k9V-5A-Xt0"/>
|
||||
<constraint firstItem="uXQ-Mb-Jkv" firstAttribute="top" secondItem="6Cn-Qu-3ab" secondAttribute="top" id="ps9-CX-XSk"/>
|
||||
<constraint firstItem="2EO-qL-ast" firstAttribute="leading" secondItem="fma-vB-sY1" secondAttribute="leading" id="ueX-jc-IqH"/>
|
||||
<constraint firstAttribute="bottom" secondItem="2EO-qL-ast" secondAttribute="bottom" id="zCc-Cc-PPh"/>
|
||||
</constraints>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="-512.31884057971024" y="-32.142857142857139"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="defaultCoverArt" width="128" height="128"/>
|
||||
<image name="nextTrackButtonLarge" width="28" height="28"/>
|
||||
<image name="playButtonLarge" width="22" height="22"/>
|
||||
<systemColor name="labelColor">
|
||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<systemColor name="separatorColor">
|
||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
@ -9,32 +9,22 @@
|
||||
import UIKit
|
||||
|
||||
class NowPlayingTabBarController: UITabBarController {
|
||||
private var barHeight: NSLayoutConstraint!
|
||||
let nowPlayingViewController = NowPlayingViewController()
|
||||
let nowPlayingViewController = NowPlayingBarViewController()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
addChild(nowPlayingViewController)
|
||||
let subview = nowPlayingViewController.view!
|
||||
tabBar.superview?.addSubview(subview)
|
||||
tabBar.clipsToBounds = false
|
||||
view.addSubview(subview)
|
||||
subview.translatesAutoresizingMaskIntoConstraints = false
|
||||
barHeight = subview.heightAnchor.constraint(equalToConstant: 0)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
subview.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
subview.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
subview.topAnchor.constraint(equalTo: tabBar.topAnchor),
|
||||
barHeight,
|
||||
subview.heightAnchor.constraint(equalToConstant: NowPlayingTabBar.barHeight),
|
||||
])
|
||||
nowPlayingViewController.didMove(toParent: self)
|
||||
|
||||
|
||||
additionalSafeAreaInsets.bottom = NowPlayingTabBar.barHeight
|
||||
}
|
||||
|
||||
override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
|
||||
super.preferredContentSizeDidChange(forChildContentContainer: container)
|
||||
|
||||
barHeight.constant = container.preferredContentSize.height
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,132 +2,29 @@
|
||||
// NowPlayingViewController.swift
|
||||
// Persephone-iOS
|
||||
//
|
||||
// Created by Dan Barber on 2020-5-15.
|
||||
// Created by Dan Barber on 2020-12-01.
|
||||
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ReSwift
|
||||
import Kingfisher
|
||||
|
||||
class NowPlayingViewController: UIViewController {
|
||||
@IBOutlet var separatorHeight: NSLayoutConstraint!
|
||||
@IBOutlet var playPauseButton: UIButton!
|
||||
@IBOutlet var nextButton: UIButton!
|
||||
@IBOutlet var songTitle: UILabel!
|
||||
@IBOutlet var albumCoverView: UIImageView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
separatorHeight.constant = 1 / traitCollection.displayScale
|
||||
|
||||
App.store.subscribe(self) {
|
||||
$0.select { $0.playerState }
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didConnect), name: .didConnect, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willDisconnect), name: .willDisconnect, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didReloadAlbumArt), name: .didReloadAlbumArt, object: nil)
|
||||
|
||||
albumCoverView.layer.backgroundColor = UIColor.black.cgColor
|
||||
albumCoverView.layer.cornerRadius = 4
|
||||
albumCoverView.layer.borderWidth = 1 / traitCollection.displayScale
|
||||
albumCoverView.layer.masksToBounds = true
|
||||
|
||||
setAppearance()
|
||||
}
|
||||
|
||||
override func didMove(toParent parent: UIViewController?) {
|
||||
super.didMove(toParent: parent)
|
||||
/*
|
||||
// MARK: - Navigation
|
||||
|
||||
preferredContentSize.height = NowPlayingTabBar.barHeight
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
|
||||
separatorHeight.constant = 1 / traitCollection.displayScale
|
||||
|
||||
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
|
||||
setAppearance()
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
// Get the new view controller using segue.destination.
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
}
|
||||
|
||||
func setAppearance() {
|
||||
let darkMode = traitCollection.userInterfaceStyle == .dark
|
||||
*/
|
||||
|
||||
albumCoverView.layer.borderColor = darkMode ? CGColor.albumBorderColorDark : CGColor.albumBorderColorLight
|
||||
}
|
||||
|
||||
@objc func didConnect() {
|
||||
App.mpdClient.fetchQueue()
|
||||
}
|
||||
|
||||
@objc func willDisconnect() {
|
||||
DispatchQueue.main.async {
|
||||
App.store.dispatch(UpdateQueuePosAction(queuePos: -1))
|
||||
App.store.dispatch(UpdateQueueAction(queue: []))
|
||||
}
|
||||
}
|
||||
|
||||
@objc func didReloadAlbumArt() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
func setTransportControlState(_ state: PlayerState) {
|
||||
guard let state = state.state else { return }
|
||||
|
||||
playPauseButton.isEnabled = state.isOneOf([.playing, .paused, .stopped])
|
||||
nextButton.isEnabled = state.isOneOf([.playing, .paused])
|
||||
|
||||
if state.isOneOf([.paused, .stopped, .unknown]) {
|
||||
playPauseButton.setImage(.playIconLarge, for: .normal)
|
||||
} else {
|
||||
playPauseButton.setImage(.pauseIconLarge, for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
func setSong(_ song: Song?) {
|
||||
guard let song = song else {
|
||||
self.songTitle.text = "Not Playing"
|
||||
self.albumCoverView.image = .defaultCoverArt
|
||||
return
|
||||
}
|
||||
|
||||
songTitle.text = song.title
|
||||
|
||||
let provider = MPDAlbumArtImageDataProvider(
|
||||
songUri: song.mpdSong.uriString,
|
||||
cacheKey: song.album.hash
|
||||
)
|
||||
|
||||
albumCoverView.kf.setImage(
|
||||
with: .provider(provider),
|
||||
placeholder: UIImage.defaultCoverArt,
|
||||
options: [
|
||||
.processor(DownsamplingImageProcessor(size: .queueSongCoverSize)),
|
||||
.scaleFactor(traitCollection.displayScale),
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction func playPauseButtonAction(_ sender: Any) {
|
||||
App.mpdClient.playPause()
|
||||
}
|
||||
|
||||
@IBAction func nextButtonAction(_ sender: Any) {
|
||||
App.mpdClient.nextTrack()
|
||||
}
|
||||
}
|
||||
|
||||
extension NowPlayingViewController: StoreSubscriber {
|
||||
typealias StoreSubscriberStateType = PlayerState
|
||||
|
||||
func newState(state: PlayerState) {
|
||||
DispatchQueue.main.async {
|
||||
self.setTransportControlState(state)
|
||||
self.setSong(state.currentSong)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,105 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina5_9" orientation="portrait" appearance="dark"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="Stack View standard spacing" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="NowPlayingViewController" customModule="Persephone" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="albumCoverView" destination="6Cn-Qu-3ab" id="w0j-pd-zrj"/>
|
||||
<outlet property="nextButton" destination="k9u-Hf-Cp0" id="bs9-R1-q5h"/>
|
||||
<outlet property="playPauseButton" destination="aJD-nr-kHS" id="6sM-tz-FHK"/>
|
||||
<outlet property="separatorHeight" destination="chi-7m-8Ds" id="Ex2-Wm-ygG"/>
|
||||
<outlet property="songTitle" destination="4nQ-FU-7Ub" id="eGu-nR-CuK"/>
|
||||
<outlet property="view" destination="fma-vB-sY1" id="5BF-fd-Kur"/>
|
||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" id="fma-vB-sY1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="9j9-AN-ijy">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="63"/>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" minimumValueImage="speakerOff" maximumValueImage="speakerHigh" translatesAutoresizingMaskIntoConstraints="NO" id="69b-PX-D8O">
|
||||
<rect key="frame" x="30" y="694" width="315" height="31"/>
|
||||
</slider>
|
||||
<progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" ambiguous="YES" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="s9e-Zd-M6C">
|
||||
<rect key="frame" x="32" y="544" width="311" height="4"/>
|
||||
</progressView>
|
||||
<stackView opaque="NO" contentMode="center" fixedFrame="YES" distribution="equalCentering" alignment="center" spacing="87" translatesAutoresizingMaskIntoConstraints="NO" id="g2E-QV-g22">
|
||||
<rect key="frame" x="32" y="601" width="312" height="46"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="defaultCoverArt" translatesAutoresizingMaskIntoConstraints="NO" id="6Cn-Qu-3ab">
|
||||
<rect key="frame" x="20" y="8" width="47" height="47"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="6Cn-Qu-3ab" secondAttribute="height" multiplier="1:1" id="I6V-Kn-Cwa"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Tik-7x-PaQ">
|
||||
<rect key="frame" x="75" y="8" width="0.0" height="47"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" id="DuG-NI-0Bp"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="249" verticalHuggingPriority="251" text="Not Playing" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4nQ-FU-7Ub">
|
||||
<rect key="frame" x="83" y="8" width="152" height="47"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="center" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aJD-nr-kHS">
|
||||
<rect key="frame" x="243" y="8" width="32" height="47"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="4Un-9M-vOk"/>
|
||||
</constraints>
|
||||
<color key="tintColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<state key="normal" image="playButtonLarge">
|
||||
<color key="titleColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="playPauseButtonAction:" destination="-1" eventType="touchUpInside" id="a3n-1h-p00"/>
|
||||
</connections>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ix3-hb-WwP" userLabel="Previous Button">
|
||||
<rect key="frame" x="0.0" y="0.0" width="46" height="46"/>
|
||||
<color key="tintColor" systemColor="labelColor"/>
|
||||
<state key="normal" image="prevTrackButtonHugeiOS"/>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="center" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k9u-Hf-Cp0">
|
||||
<rect key="frame" x="283" y="8" width="32" height="47"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="fy0-Z2-OSg"/>
|
||||
</constraints>
|
||||
<color key="tintColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<state key="normal" image="nextTrackButtonLarge">
|
||||
<color key="titleColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="nextButtonAction:" destination="-1" eventType="touchUpInside" id="3Ke-PH-ud9"/>
|
||||
</connections>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4qp-Jh-zT7" userLabel="Play Button">
|
||||
<rect key="frame" x="133" y="0.0" width="46" height="46"/>
|
||||
<color key="tintColor" systemColor="labelColor"/>
|
||||
<state key="normal" image="playButtonHugeiOS"/>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5SE-nt-QeW" userLabel="Next Button">
|
||||
<rect key="frame" x="266" y="0.0" width="46" height="46"/>
|
||||
<color key="tintColor" systemColor="labelColor"/>
|
||||
<state key="normal" image="nextTrackButtonHugeiOS"/>
|
||||
</button>
|
||||
</subviews>
|
||||
<directionalEdgeInsets key="directionalLayoutMargins" top="8" leading="20" bottom="8" trailing="20"/>
|
||||
<viewLayoutGuide key="safeArea" id="Xfd-VS-LUl"/>
|
||||
</stackView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2EO-qL-ast">
|
||||
<rect key="frame" x="0.0" y="63" width="335" height="1"/>
|
||||
<color key="backgroundColor" systemColor="separatorColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="chi-7m-8Ds"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="9j9-AN-ijy" firstAttribute="top" secondItem="fma-vB-sY1" secondAttribute="top" id="Bpq-6d-BwN"/>
|
||||
<constraint firstItem="9j9-AN-ijy" firstAttribute="leading" secondItem="fma-vB-sY1" secondAttribute="leading" id="aG7-qp-jXe"/>
|
||||
<constraint firstAttribute="trailing" secondItem="9j9-AN-ijy" secondAttribute="trailing" id="cCF-6v-1x0"/>
|
||||
<constraint firstAttribute="trailing" secondItem="2EO-qL-ast" secondAttribute="trailing" id="dp6-XJ-FaI"/>
|
||||
<constraint firstItem="2EO-qL-ast" firstAttribute="top" secondItem="9j9-AN-ijy" secondAttribute="bottom" id="k9V-5A-Xt0"/>
|
||||
<constraint firstItem="2EO-qL-ast" firstAttribute="leading" secondItem="fma-vB-sY1" secondAttribute="leading" id="ueX-jc-IqH"/>
|
||||
<constraint firstAttribute="bottom" secondItem="2EO-qL-ast" secondAttribute="bottom" id="zCc-Cc-PPh"/>
|
||||
<constraint firstItem="s9e-Zd-M6C" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="32" id="OzT-yE-YIZ"/>
|
||||
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="69b-PX-D8O" secondAttribute="bottom" constant="54" id="S4t-SJ-XGN"/>
|
||||
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="s9e-Zd-M6C" secondAttribute="trailing" constant="32" id="TmT-dF-PSV"/>
|
||||
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="69b-PX-D8O" secondAttribute="trailing" constant="32" id="b4J-ZE-ZiR"/>
|
||||
<constraint firstItem="69b-PX-D8O" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="32" id="du2-8n-Nmm"/>
|
||||
</constraints>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="-512.31884057971024" y="-32.142857142857139"/>
|
||||
<point key="canvasLocation" x="-376.80000000000001" y="73.152709359605907"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="defaultCoverArt" width="128" height="128"/>
|
||||
<image name="nextTrackButtonLarge" width="28" height="28"/>
|
||||
<image name="playButtonLarge" width="22" height="22"/>
|
||||
<image name="nextTrackButtonHugeiOS" width="46" height="46"/>
|
||||
<image name="playButtonHugeiOS" width="46" height="46"/>
|
||||
<image name="prevTrackButtonHugeiOS" width="46" height="46"/>
|
||||
<image name="speakerHigh" width="21" height="17"/>
|
||||
<image name="speakerOff" width="21" height="17"/>
|
||||
<systemColor name="labelColor">
|
||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@ -21,7 +21,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
_ = App.mpdServerController
|
||||
|
||||
App.store.dispatch(UpdateServerHost(host: "192.168.1.42"))
|
||||
App.store.dispatch(UpdateServerHost(host: "192.168.4.31"))
|
||||
}
|
||||
|
||||
func sceneDidDisconnect(_ scene: UIScene) {
|
||||
|
||||