mirror of https://code.videolan.org/videolan/vlc
macosx: Add expandable detail view to the album collection view
Signed-off-by: Claudio Cambra <claudio.cambra@gmail.com>
This commit is contained in:
parent
fa106a29ad
commit
53c0bfa28f
|
@ -58,10 +58,16 @@ libmacosx_plugin_la_SOURCES = \
|
|||
gui/macosx/library/VLCInputItem.m \
|
||||
gui/macosx/library/VLCLibraryAlbumTableCellView.h \
|
||||
gui/macosx/library/VLCLibraryAlbumTableCellView.m \
|
||||
gui/macosx/library/VLCLibraryAlbumTracksDataSource.h \
|
||||
gui/macosx/library/VLCLibraryAlbumTracksDataSource.m \
|
||||
gui/macosx/library/VLCLibraryAudioDataSource.h \
|
||||
gui/macosx/library/VLCLibraryAudioDataSource.m \
|
||||
gui/macosx/library/VLCLibraryCollectionViewFlowLayout.h \
|
||||
gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m \
|
||||
gui/macosx/library/VLCLibraryCollectionViewItem.h \
|
||||
gui/macosx/library/VLCLibraryCollectionViewItem.m \
|
||||
gui/macosx/library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.h \
|
||||
gui/macosx/library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.m \
|
||||
gui/macosx/library/VLCLibraryCollectionViewSupplementaryElementView.h \
|
||||
gui/macosx/library/VLCLibraryCollectionViewSupplementaryElementView.m \
|
||||
gui/macosx/library/VLCLibraryController.h \
|
||||
|
@ -297,6 +303,7 @@ libmacosx_plugin_la_XIB_SOURCES = \
|
|||
gui/macosx/UI/VLCLibraryTableCellView.xib \
|
||||
gui/macosx/UI/VLCPlaylistTableCellView.xib \
|
||||
gui/macosx/UI/VLCLibraryCollectionViewItem.xib \
|
||||
gui/macosx/UI/VLCLibraryCollectionViewAlbumSupplementaryDetailView.xib \
|
||||
gui/macosx/UI/VLCMediaSourceCollectionViewItem.xib \
|
||||
gui/macosx/UI/VLCMediaSourceDeviceCollectionViewItem.xib \
|
||||
gui/macosx/UI/VLCInformationWindow.xib \
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="20037" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="20037"/>
|
||||
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="VLCLibraryCollectionViewAlbumItem"/>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<view id="HAc-or-XD8" customClass="VLCLibraryCollectionViewAlbumSupplementaryDetailView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1061" height="332"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<box boxType="custom" borderType="none" cornerRadius="4" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="TDx-ys-0hc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1061" height="312"/>
|
||||
<view key="contentView" id="l4M-qd-E0u">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1061" height="312"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
<color key="borderColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="fillColor" name="separatorColor" catalog="System" colorSpace="catalog"/>
|
||||
</box>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="top" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FWp-yd-2Pm">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1061" height="302"/>
|
||||
<subviews>
|
||||
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TOx-1e-6D9">
|
||||
<rect key="frame" x="0.0" y="10" width="351" height="292"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="xZd-Hk-h2M">
|
||||
<rect key="frame" x="10" y="0.0" width="331" height="292"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="no-art" id="6X6-Og-u8A"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="xZd-Hk-h2M" secondAttribute="trailing" constant="10" id="GHL-NF-uZf"/>
|
||||
<constraint firstItem="xZd-Hk-h2M" firstAttribute="top" secondItem="TOx-1e-6D9" secondAttribute="top" id="fYG-48-y9a"/>
|
||||
<constraint firstItem="xZd-Hk-h2M" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="TOx-1e-6D9" secondAttribute="leading" constant="10" id="gvA-cd-m3X"/>
|
||||
<constraint firstItem="xZd-Hk-h2M" firstAttribute="centerX" secondItem="TOx-1e-6D9" secondAttribute="centerX" id="zLM-Ut-V4H"/>
|
||||
</constraints>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bw7-QB-Ssc">
|
||||
<rect key="frame" x="359" y="20" width="702" height="282"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nCe-dY-YMM">
|
||||
<rect key="frame" x="-2" y="230" width="124" height="52"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Album name" id="6RM-x8-Y4y">
|
||||
<font key="font" textStyle="title1" name=".SFNS-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="HnP-Fk-juB">
|
||||
<rect key="frame" x="-2" y="206" width="87" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Album details" id="Nwk-76-Wx9">
|
||||
<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>
|
||||
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="52" horizontalPageScroll="10" verticalLineScroll="52" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" horizontalScrollElasticity="none" id="9ZS-oy-iP9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="701" height="198"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" drawsBackground="NO" id="3V4-tX-owM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="701" height="198"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="50" viewBased="YES" id="eEJ-WA-0aM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="701" height="198"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<tableViewGridLines key="gridStyleMask" horizontal="YES"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn editable="NO" width="641" minWidth="10" maxWidth="1000" id="tVn-dP-rPg">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="LqL-cf-UYG">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="vmz-MH-Uum">
|
||||
<rect key="frame" x="11" y="1" width="650" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<nil key="backgroundColor"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="ZBY-pE-E7T">
|
||||
<rect key="frame" x="-100" y="-100" width="701" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="WRE-VM-L7s">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="TOx-1e-6D9" secondAttribute="bottom" constant="10" id="sVI-op-597"/>
|
||||
<constraint firstItem="TOx-1e-6D9" firstAttribute="width" secondItem="bw7-QB-Ssc" secondAttribute="width" multiplier="0.5" id="wgl-yE-5rb"/>
|
||||
</constraints>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="TDx-ys-0hc" firstAttribute="trailing" secondItem="FWp-yd-2Pm" secondAttribute="trailing" id="288-Qz-cb7"/>
|
||||
<constraint firstItem="TDx-ys-0hc" firstAttribute="leading" secondItem="FWp-yd-2Pm" secondAttribute="leading" id="4AV-xO-cVg"/>
|
||||
<constraint firstItem="FWp-yd-2Pm" firstAttribute="leading" secondItem="HAc-or-XD8" secondAttribute="leading" id="D62-3E-aDO"/>
|
||||
<constraint firstItem="TDx-ys-0hc" firstAttribute="top" secondItem="HAc-or-XD8" secondAttribute="top" constant="20" id="Wob-l9-MuU"/>
|
||||
<constraint firstAttribute="bottom" secondItem="TDx-ys-0hc" secondAttribute="bottom" id="aub-cX-QrF"/>
|
||||
<constraint firstAttribute="trailing" secondItem="FWp-yd-2Pm" secondAttribute="trailing" id="cPm-6m-umY"/>
|
||||
<constraint firstItem="FWp-yd-2Pm" firstAttribute="top" secondItem="TDx-ys-0hc" secondAttribute="top" constant="10" id="cVs-ac-sSk"/>
|
||||
<constraint firstItem="FWp-yd-2Pm" firstAttribute="bottom" secondItem="TDx-ys-0hc" secondAttribute="bottom" id="pZF-BE-cG1"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="albumArtworkImageView" destination="xZd-Hk-h2M" id="J8l-V9-P06"/>
|
||||
<outlet property="albumDetailsTextField" destination="HnP-Fk-juB" id="Hm3-l8-a9s"/>
|
||||
<outlet property="albumTitleTextField" destination="nCe-dY-YMM" id="h3l-p0-w3e"/>
|
||||
<outlet property="albumTracksTableView" destination="eEJ-WA-0aM" id="l8k-M9-a8e"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-237.5" y="-257"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="no-art" width="128" height="128"/>
|
||||
</resources>
|
||||
</document>
|
|
@ -25,12 +25,13 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class VLCImageView;
|
||||
@class VLCLibraryTracksDataSource;
|
||||
@class VLCTrackingView;
|
||||
@class VLCMediaLibraryAlbum;
|
||||
|
||||
@interface VLCLibraryAlbumTableCellView : NSTableCellView
|
||||
|
||||
extern NSString *VLCAudioLibraryCellIdentifier;
|
||||
|
||||
+ (CGFloat)defaultHeight;
|
||||
+ (CGFloat)heightForAlbum:(VLCMediaLibraryAlbum *)album;
|
||||
|
||||
|
|
|
@ -29,22 +29,17 @@
|
|||
#import "library/VLCLibraryController.h"
|
||||
#import "library/VLCLibraryDataTypes.h"
|
||||
#import "library/VLCLibraryTableCellView.h"
|
||||
#import "library/VLCLibraryAlbumTracksDataSource.h"
|
||||
|
||||
NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier";
|
||||
const CGFloat VLCLibraryTracksRowHeight = 50.;
|
||||
const CGFloat VLCLibraryAlbumTableCellViewDefaultHeight = 168.;
|
||||
const CGFloat LayoutSpacer;
|
||||
|
||||
@interface VLCLibraryTracksDataSource : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
||||
|
||||
@property (readwrite, retain, nonatomic, nullable) VLCMediaLibraryAlbum *representedAlbum;
|
||||
|
||||
@end
|
||||
|
||||
@interface VLCLibraryAlbumTableCellView ()
|
||||
{
|
||||
VLCLibraryController *_libraryController;
|
||||
VLCLibraryTracksDataSource *_tracksDataSource;
|
||||
VLCLibraryAlbumTracksDataSource *_tracksDataSource;
|
||||
NSTableView *_tracksTableView;
|
||||
}
|
||||
@end
|
||||
|
@ -75,7 +70,7 @@ const CGFloat LayoutSpacer;
|
|||
_tracksTableView.rowHeight = VLCLibraryTracksRowHeight;
|
||||
[_tracksTableView addTableColumn:column];
|
||||
_tracksTableView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_tracksDataSource = [[VLCLibraryTracksDataSource alloc] init];
|
||||
_tracksDataSource = [[VLCLibraryAlbumTracksDataSource alloc] init];
|
||||
_tracksTableView.dataSource = _tracksDataSource;
|
||||
_tracksTableView.delegate = _tracksDataSource;
|
||||
_tracksTableView.doubleAction = @selector(tracksTableViewDoubleClickAction:);
|
||||
|
@ -152,68 +147,3 @@ const CGFloat LayoutSpacer;
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface VLCLibraryTracksDataSource ()
|
||||
{
|
||||
NSArray *_tracks;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation VLCLibraryTracksDataSource
|
||||
|
||||
- (void)setRepresentedAlbum:(VLCMediaLibraryAlbum *)representedAlbum
|
||||
{
|
||||
_representedAlbum = representedAlbum;
|
||||
_tracks = [_representedAlbum tracksAsMediaItems];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
if (_representedAlbum != nil) {
|
||||
return _representedAlbum.numberOfTracks;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
VLCLibraryTableCellView *cellView = [tableView makeViewWithIdentifier:VLCAudioLibraryCellIdentifier owner:self];
|
||||
|
||||
if (cellView == nil) {
|
||||
/* the following code saves us an instance of NSViewController which we don't need */
|
||||
NSNib *nib = [[NSNib alloc] initWithNibNamed:@"VLCLibraryTableCellView" bundle:nil];
|
||||
NSArray *topLevelObjects;
|
||||
if (![nib instantiateWithOwner:self topLevelObjects:&topLevelObjects]) {
|
||||
NSAssert(1, @"Failed to load nib file to show audio library items");
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (id topLevelObject in topLevelObjects) {
|
||||
if ([topLevelObject isKindOfClass:[VLCLibraryTableCellView class]]) {
|
||||
cellView = topLevelObject;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cellView.identifier = VLCAudioLibraryCellIdentifier;
|
||||
}
|
||||
|
||||
VLCMediaLibraryMediaItem *mediaItem = _tracks[row];
|
||||
|
||||
NSImage *image = mediaItem.smallArtworkImage;
|
||||
if (!image) {
|
||||
image = [NSImage imageNamed: @"noart.png"];
|
||||
}
|
||||
cellView.representedImageView.image = image;
|
||||
cellView.representedMediaItem = mediaItem;
|
||||
|
||||
NSString *title = mediaItem.title;
|
||||
cellView.primaryTitleTextField.hidden = NO;
|
||||
cellView.secondaryTitleTextField.hidden = NO;
|
||||
cellView.primaryTitleTextField.stringValue = title;
|
||||
cellView.secondaryTitleTextField.stringValue = [NSString stringWithTime:mediaItem.duration / 1000];
|
||||
|
||||
return cellView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*****************************************************************************
|
||||
* VLCLibraryAlbumTracksDataSource.h: MacOS X interface module
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2022 VLC authors and VideoLAN
|
||||
*
|
||||
* Authors: Claudio Cambra <claudio.cambra@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class VLCMediaLibraryAlbum;
|
||||
|
||||
@interface VLCLibraryAlbumTracksDataSource : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
||||
|
||||
@property (readwrite, retain, nonatomic, nullable) VLCMediaLibraryAlbum *representedAlbum;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,98 @@
|
|||
/*****************************************************************************
|
||||
* VLCLibraryAlbumTracksDataSource.m: MacOS X interface module
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2019 VLC authors and VideoLAN
|
||||
*
|
||||
* Authors: Felix Paul Kühne <fkuehne # videolan -dot- org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#import "VLCLibraryAlbumTracksDataSource.h"
|
||||
#import "VLCLibraryAlbumTableCellView.h"
|
||||
#import "extensions/NSFont+VLCAdditions.h"
|
||||
#import "extensions/NSString+Helpers.h"
|
||||
#import "views/VLCImageView.h"
|
||||
#import "views/VLCTrackingView.h"
|
||||
#import "main/VLCMain.h"
|
||||
#import "library/VLCLibraryController.h"
|
||||
#import "library/VLCLibraryDataTypes.h"
|
||||
#import "library/VLCLibraryTableCellView.h"
|
||||
#import "library/VLCLibraryAlbumTracksDataSource.h"
|
||||
|
||||
@interface VLCLibraryAlbumTracksDataSource ()
|
||||
{
|
||||
NSArray *_tracks;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation VLCLibraryAlbumTracksDataSource
|
||||
|
||||
- (void)setRepresentedAlbum:(VLCMediaLibraryAlbum *)representedAlbum
|
||||
{
|
||||
_representedAlbum = representedAlbum;
|
||||
_tracks = [_representedAlbum tracksAsMediaItems];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
if (_representedAlbum != nil) {
|
||||
return _representedAlbum.numberOfTracks;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
VLCLibraryTableCellView *cellView = [tableView makeViewWithIdentifier:VLCAudioLibraryCellIdentifier owner:self];
|
||||
|
||||
if (cellView == nil) {
|
||||
/* the following code saves us an instance of NSViewController which we don't need */
|
||||
NSNib *nib = [[NSNib alloc] initWithNibNamed:@"VLCLibraryTableCellView" bundle:nil];
|
||||
NSArray *topLevelObjects;
|
||||
if (![nib instantiateWithOwner:self topLevelObjects:&topLevelObjects]) {
|
||||
NSAssert(1, @"Failed to load nib file to show audio library items");
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (id topLevelObject in topLevelObjects) {
|
||||
if ([topLevelObject isKindOfClass:[VLCLibraryTableCellView class]]) {
|
||||
cellView = topLevelObject;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cellView.identifier = VLCAudioLibraryCellIdentifier;
|
||||
}
|
||||
|
||||
VLCMediaLibraryMediaItem *mediaItem = _tracks[row];
|
||||
|
||||
NSImage *image = mediaItem.smallArtworkImage;
|
||||
if (!image) {
|
||||
image = [NSImage imageNamed: @"noart.png"];
|
||||
}
|
||||
cellView.representedImageView.image = image;
|
||||
cellView.representedMediaItem = mediaItem;
|
||||
|
||||
NSString *title = mediaItem.title;
|
||||
cellView.primaryTitleTextField.hidden = NO;
|
||||
cellView.secondaryTitleTextField.hidden = NO;
|
||||
cellView.primaryTitleTextField.stringValue = title;
|
||||
cellView.secondaryTitleTextField.stringValue = [NSString stringWithTime:mediaItem.duration / 1000];
|
||||
|
||||
return cellView;
|
||||
}
|
||||
|
||||
@end
|
|
@ -30,14 +30,15 @@
|
|||
#import "library/VLCLibraryTableCellView.h"
|
||||
#import "library/VLCLibraryAlbumTableCellView.h"
|
||||
#import "library/VLCLibraryCollectionViewItem.h"
|
||||
#import "library/VLCLibraryCollectionViewFlowLayout.h"
|
||||
#import "library/VLCLibraryCollectionViewAlbumSupplementaryDetailView.h"
|
||||
|
||||
#import "extensions/NSString+Helpers.h"
|
||||
#import "views/VLCImageView.h"
|
||||
|
||||
static NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier";
|
||||
|
||||
@interface VLCLibraryAudioDataSource () <NSCollectionViewDelegate, NSCollectionViewDataSource>
|
||||
{
|
||||
VLCLibraryCollectionViewFlowLayout *_collectionViewFlowLayout;
|
||||
NSInteger _currentSelectedSegment;
|
||||
NSArray<NSString *> *_placeholderImageNames;
|
||||
NSArray<NSString *> *_placeholderLabelStrings;
|
||||
|
@ -67,12 +68,19 @@ static NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier
|
|||
_collectionView.delegate = self;
|
||||
|
||||
[_collectionView registerClass:[VLCLibraryCollectionViewItem class] forItemWithIdentifier:VLCLibraryCellIdentifier];
|
||||
|
||||
NSCollectionViewFlowLayout *flowLayout = _collectionView.collectionViewLayout;
|
||||
flowLayout.itemSize = CGSizeMake(214., 260.);
|
||||
flowLayout.sectionInset = NSEdgeInsetsMake(20., 20., 20., 20.);
|
||||
flowLayout.minimumLineSpacing = 20.;
|
||||
flowLayout.minimumInteritemSpacing = 20.;
|
||||
|
||||
NSNib *albumSupplementaryDetailView = [[NSNib alloc] initWithNibNamed:@"VLCLibraryCollectionViewAlbumSupplementaryDetailView" bundle:nil];
|
||||
[_collectionView registerNib:albumSupplementaryDetailView
|
||||
forSupplementaryViewOfKind:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind
|
||||
withIdentifier:VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier];
|
||||
|
||||
_collectionViewFlowLayout = [[VLCLibraryCollectionViewFlowLayout alloc] init];
|
||||
_collectionView.collectionViewLayout = _collectionViewFlowLayout;
|
||||
|
||||
_collectionViewFlowLayout.itemSize = CGSizeMake(214., 260.);
|
||||
_collectionViewFlowLayout.sectionInset = NSEdgeInsetsMake(20., 20., 20., 20.);
|
||||
_collectionViewFlowLayout.minimumLineSpacing = 20.;
|
||||
_collectionViewFlowLayout.minimumInteritemSpacing = 20.;
|
||||
|
||||
_groupSelectionTableView.target = self;
|
||||
_groupSelectionTableView.doubleAction = @selector(groubSelectionDoubleClickAction:);
|
||||
|
@ -112,6 +120,7 @@ static NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier
|
|||
|
||||
- (IBAction)segmentedControlAction:(id)sender
|
||||
{
|
||||
[_collectionViewFlowLayout resetLayout];
|
||||
_currentSelectedSegment = _segmentedControl.selectedSegment;
|
||||
switch (_currentSelectedSegment) {
|
||||
case 0:
|
||||
|
@ -400,6 +409,42 @@ static NSString *VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier
|
|||
return viewItem;
|
||||
}
|
||||
|
||||
- (void)collectionView:(NSCollectionView *)collectionView didSelectItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
|
||||
{
|
||||
NSIndexPath *indexPath = indexPaths.anyObject;
|
||||
if (!indexPath || _currentParentType != VLC_ML_PARENT_ALBUM) {
|
||||
return;
|
||||
}
|
||||
|
||||
[_collectionViewFlowLayout expandDetailSectionAtIndex:indexPath];
|
||||
}
|
||||
|
||||
- (void)collectionView:(NSCollectionView *)collectionView didDeselectItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
|
||||
{
|
||||
NSIndexPath *indexPath = indexPaths.anyObject;
|
||||
if (!indexPath || _currentParentType != VLC_ML_PARENT_ALBUM) {
|
||||
return;
|
||||
}
|
||||
|
||||
[_collectionViewFlowLayout collapseDetailSectionAtIndex:indexPath];
|
||||
}
|
||||
|
||||
- (NSView *)collectionView:(NSCollectionView *)collectionView
|
||||
viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
|
||||
atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if ([kind isEqualToString:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind] && _currentParentType == VLC_ML_PARENT_ALBUM) {
|
||||
VLCLibraryCollectionViewAlbumSupplementaryDetailView* albumSupplementaryDetailView = [collectionView makeSupplementaryViewOfKind:kind withIdentifier:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind forIndexPath:indexPath];
|
||||
|
||||
VLCMediaLibraryAlbum *album = _displayedCollection[indexPath.item];
|
||||
albumSupplementaryDetailView.representedAlbum = album;
|
||||
|
||||
return albumSupplementaryDetailView;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation VLCLibraryGroupDataSource
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*****************************************************************************
|
||||
* VLCLibraryCollectionViewSupplementaryDetailView.h: MacOS X interface module
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2022 VLC authors and VideoLAN
|
||||
*
|
||||
* Authors: Claudio Cambra <claudio.cambra@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class VLCMediaLibraryAlbum;
|
||||
|
||||
extern NSString *const VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier;
|
||||
extern NSCollectionViewSupplementaryElementKind const VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind;
|
||||
|
||||
@interface VLCLibraryCollectionViewAlbumSupplementaryDetailView : NSView <NSCollectionViewElement>
|
||||
|
||||
@property (readwrite, retain, nonatomic) VLCMediaLibraryAlbum *representedAlbum;
|
||||
@property (readwrite, weak) IBOutlet NSTextField *albumTitleTextField;
|
||||
@property (readwrite, weak) IBOutlet NSTextField *albumDetailsTextField;
|
||||
@property (readwrite, weak) IBOutlet NSImageView *albumArtworkImageView;
|
||||
@property (readwrite, weak) IBOutlet NSTableView *albumTracksTableView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,84 @@
|
|||
/*****************************************************************************
|
||||
* VLCLibraryCollectionViewSupplementaryDetailView.m: MacOS X interface module
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2021 VLC authors and VideoLAN
|
||||
*
|
||||
* Authors: Samuel Bassaly <shkshk90 # gmail -dot- com>
|
||||
* Claudio Cambra <claudio.cambra@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#import "VLCLibraryCollectionViewAlbumSupplementaryDetailView.h"
|
||||
|
||||
#import "main/VLCMain.h"
|
||||
#import "library/VLCLibraryController.h"
|
||||
#import "library/VLCLibraryDataTypes.h"
|
||||
#import "library/VLCLibraryModel.h"
|
||||
#import "library/VLCLibraryMenuController.h"
|
||||
#import "views/VLCImageView.h"
|
||||
#import "extensions/NSString+Helpers.h"
|
||||
#import "extensions/NSFont+VLCAdditions.h"
|
||||
#import "extensions/NSColor+VLCAdditions.h"
|
||||
#import "extensions/NSView+VLCAdditions.h"
|
||||
#import "library/VLCLibraryAlbumTracksDataSource.h"
|
||||
#import "library/VLCLibraryAlbumTableCellView.h"
|
||||
|
||||
NSString *const VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier = @"VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier";
|
||||
NSCollectionViewSupplementaryElementKind const VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind = @"VLCLibraryCollectionViewAlbumSupplementaryDetailViewIdentifier";
|
||||
|
||||
@interface VLCLibraryCollectionViewAlbumSupplementaryDetailView ()
|
||||
{
|
||||
VLCLibraryAlbumTracksDataSource *_tracksDataSource;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation VLCLibraryCollectionViewAlbumSupplementaryDetailView
|
||||
|
||||
@synthesize representedAlbum = _representedAlbum;
|
||||
@synthesize albumTitleTextField = _albumTitleTextField;
|
||||
@synthesize albumDetailsTextField = _albumDetailsTextField;
|
||||
@synthesize albumArtworkImageView = _albumArtworkImageView;
|
||||
@synthesize albumTracksTableView = _albumTracksTableView;
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
_tracksDataSource = [[VLCLibraryAlbumTracksDataSource alloc] init];
|
||||
_albumTracksTableView.dataSource = _tracksDataSource;
|
||||
_albumTracksTableView.delegate = _tracksDataSource;
|
||||
}
|
||||
|
||||
- (void)setRepresentedAlbum:(VLCMediaLibraryAlbum *)representedAlbum
|
||||
{
|
||||
_representedAlbum = representedAlbum;
|
||||
[self updateRepresentation];
|
||||
}
|
||||
|
||||
- (void)updateRepresentation
|
||||
{
|
||||
if (_representedAlbum == nil) {
|
||||
NSAssert(1, @"no media item assigned for collection view item", nil);
|
||||
return;
|
||||
}
|
||||
|
||||
_albumTitleTextField.stringValue = _representedAlbum.displayString;
|
||||
_albumDetailsTextField.stringValue = _representedAlbum.artistName;
|
||||
_albumArtworkImageView.image = _representedAlbum.smallArtworkImage;
|
||||
_tracksDataSource.representedAlbum = _representedAlbum;
|
||||
|
||||
[_albumTracksTableView reloadData];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,35 @@
|
|||
/*****************************************************************************
|
||||
* VLCLibraryCollectionViewFlowLayout.h: MacOS X interface module
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2022 VLC authors and VideoLAN
|
||||
*
|
||||
* Authors: Claudio Cambra <claudio.cambra@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface VLCLibraryCollectionViewFlowLayout : NSCollectionViewFlowLayout
|
||||
|
||||
- (void)expandDetailSectionAtIndex:(NSIndexPath *)indexPath;
|
||||
- (void)collapseDetailSectionAtIndex:(NSIndexPath *)indexPath;
|
||||
- (void)resetLayout;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,274 @@
|
|||
/*****************************************************************************
|
||||
* VLCLibraryCollectionViewFlowLayout.m: MacOS X interface module
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2022 VLC authors and VideoLAN
|
||||
*
|
||||
* Authors: Claudio Cambra <claudio.cambra@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#import "VLCLibraryCollectionViewFlowLayout.h"
|
||||
#import "VLCLibraryCollectionViewAlbumSupplementaryDetailView.h"
|
||||
|
||||
#pragma mark - Private data
|
||||
static const NSUInteger kAnimationSteps = 16;
|
||||
static const NSUInteger kWrapAroundValue = (NSUInteger)-1;
|
||||
|
||||
static const CGFloat kDetailViewMargin = 8.;
|
||||
static const CGFloat kDetailViewCollapsedHeight = 0.;
|
||||
static const CGFloat kDetailViewExpandedHeight = 300.;
|
||||
|
||||
static const CGFloat kAnimationHeightIncrement = kDetailViewExpandedHeight / (CGFloat)kAnimationSteps;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, VLCDetailViewAnimationType)
|
||||
{
|
||||
VLCDetailViewAnimationTypeExpand,
|
||||
VLCDetailViewAnimationTypeCollapse,
|
||||
};
|
||||
|
||||
static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
|
||||
const CVTimeStamp *inNow,
|
||||
const CVTimeStamp *inOutputTime,
|
||||
CVOptionFlags flagsIn,
|
||||
CVOptionFlags *flagsOut,
|
||||
void *displayLinkContext);
|
||||
|
||||
#pragma mark - VLCLibraryCollectionViewFlowLayout
|
||||
@interface VLCLibraryCollectionViewFlowLayout ()
|
||||
{
|
||||
NSUInteger _lastHeightIndex;
|
||||
CVDisplayLinkRef _displayLinkRef;
|
||||
}
|
||||
|
||||
@property (nonatomic, readwrite) BOOL detailViewIsAnimating;
|
||||
@property (nonatomic, readonly) BOOL animationIsCollapse;
|
||||
@property (nonatomic, readwrite) NSUInteger animationIndex;
|
||||
@property (nonatomic, readwrite, strong) NSIndexPath *selectedIndexPath;
|
||||
|
||||
@end
|
||||
|
||||
@implementation VLCLibraryCollectionViewFlowLayout
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self resetLayout];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public methods
|
||||
- (void)expandDetailSectionAtIndex:(NSIndexPath *)indexPath
|
||||
{
|
||||
if([_selectedIndexPath isEqual:indexPath]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_selectedIndexPath = indexPath;
|
||||
[self animateDetailViewWithAnimation:VLCDetailViewAnimationTypeExpand];
|
||||
}
|
||||
|
||||
- (void)collapseDetailSectionAtIndex:(NSIndexPath *)indexPath
|
||||
{
|
||||
if(![_selectedIndexPath isEqual:indexPath]) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self animateDetailViewWithAnimation:VLCDetailViewAnimationTypeCollapse];
|
||||
}
|
||||
|
||||
- (void)resetLayout
|
||||
{
|
||||
[self releaseDisplayLink];
|
||||
|
||||
_selectedIndexPath = nil;
|
||||
_detailViewIsAnimating = NO;
|
||||
_animationIndex = 0;
|
||||
|
||||
[self invalidateLayout];
|
||||
}
|
||||
|
||||
#pragma mark - Flow Layout methods
|
||||
|
||||
- (NSCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSCollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
|
||||
|
||||
if(_selectedIndexPath == nil || indexPath == _selectedIndexPath) {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
[attributes setFrame:[self frameForDisplacedAttributes:attributes]];
|
||||
return attributes;
|
||||
}
|
||||
|
||||
- (NSArray<__kindof NSCollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(NSRect)rect
|
||||
{
|
||||
if (_selectedIndexPath == nil) {
|
||||
return [super layoutAttributesForElementsInRect:rect];
|
||||
}
|
||||
|
||||
NSRect selectedItemFrame = [[self layoutAttributesForItemAtIndexPath:_selectedIndexPath] frame];
|
||||
|
||||
// Computed attributes from parent
|
||||
NSMutableArray<__kindof NSCollectionViewLayoutAttributes *> *layoutAttributesArray = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
|
||||
for (int i = 0; i < layoutAttributesArray.count; i++) {
|
||||
NSCollectionViewLayoutAttributes *attributes = layoutAttributesArray[i];
|
||||
[attributes setFrame:[self frameForDisplacedAttributes:attributes]];
|
||||
layoutAttributesArray[i] = attributes;
|
||||
}
|
||||
|
||||
// Add detail view to the attributes set -- detail view about to be shown
|
||||
[layoutAttributesArray addObject:[self layoutAttributesForSupplementaryViewOfKind:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind atIndexPath:self.selectedIndexPath]];
|
||||
|
||||
return layoutAttributesArray;
|
||||
}
|
||||
|
||||
- (NSCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSCollectionViewSupplementaryElementKind)elementKind
|
||||
atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if ([elementKind isEqualToString:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind]) {
|
||||
NSCollectionViewLayoutAttributes *detailViewAttributes = [NSCollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind
|
||||
withIndexPath:indexPath];
|
||||
NSAssert1(detailViewAttributes != NULL,
|
||||
@"Failed to create NSCollectionViewLayoutAttributes for view of kind %@.",
|
||||
VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind );
|
||||
|
||||
float selectedItemFrameMaxY = _selectedIndexPath == nil ? 0 : NSMaxY([[self layoutAttributesForItemAtIndexPath:_selectedIndexPath] frame]);
|
||||
detailViewAttributes.frame = NSMakeRect(NSMinX(self.collectionView.frame),
|
||||
selectedItemFrameMaxY + kDetailViewMargin,
|
||||
self.collectionViewContentSize.width - 16.0,
|
||||
(_animationIndex * kAnimationHeightIncrement));
|
||||
|
||||
return detailViewAttributes;
|
||||
}
|
||||
|
||||
NSCollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:elementKind
|
||||
atIndexPath:indexPath];
|
||||
[attributes setFrame:[self frameForDisplacedAttributes:attributes]];
|
||||
return attributes;
|
||||
}
|
||||
|
||||
- (NSSet<NSIndexPath *> *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind
|
||||
{
|
||||
if ([elementKind isEqualToString:VLCLibraryCollectionViewAlbumSupplementaryDetailViewKind]) {
|
||||
return [self.collectionView indexPathsForVisibleSupplementaryElementsOfKind:elementKind];
|
||||
}
|
||||
return [NSSet set];
|
||||
}
|
||||
|
||||
# pragma mark - Calculation of displaced frame attributes
|
||||
|
||||
- (NSRect)frameForDisplacedAttributes:(NSCollectionViewLayoutAttributes *)inAttributes {
|
||||
NSRect attributesFrame = inAttributes.frame;
|
||||
if (self.selectedIndexPath) {
|
||||
NSRect selectedItemFrame = [[self layoutAttributesForItemAtIndexPath:_selectedIndexPath] frame];
|
||||
if (NSMinY(attributesFrame) > (NSMaxY(selectedItemFrame))) {
|
||||
attributesFrame.origin.y += (_animationIndex * kAnimationHeightIncrement) + kDetailViewMargin;
|
||||
}
|
||||
}
|
||||
return attributesFrame;
|
||||
}
|
||||
|
||||
#pragma mark - Detail view animation
|
||||
- (void)animateDetailViewWithAnimation:(VLCDetailViewAnimationType)type
|
||||
{
|
||||
if (type == VLCDetailViewAnimationTypeExpand) {
|
||||
_animationIsCollapse = NO;
|
||||
_animationIndex = kWrapAroundValue;
|
||||
_lastHeightIndex = kAnimationSteps - 1;
|
||||
} else {
|
||||
_animationIsCollapse = YES;
|
||||
_animationIndex = kAnimationSteps;
|
||||
_lastHeightIndex = 0;
|
||||
}
|
||||
|
||||
_detailViewIsAnimating = YES;
|
||||
|
||||
if (_displayLinkRef == NULL) {
|
||||
[self initDisplayLink];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)initDisplayLink
|
||||
{
|
||||
const CVReturn createResult = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLinkRef);
|
||||
|
||||
if ((createResult != kCVReturnSuccess) || (_displayLinkRef == NULL)) {
|
||||
_detailViewIsAnimating = NO;
|
||||
return;
|
||||
}
|
||||
|
||||
CVDisplayLinkSetOutputCallback(_displayLinkRef, detailViewAnimationCallback, (__bridge void *)self);
|
||||
CVDisplayLinkStart(_displayLinkRef);
|
||||
}
|
||||
|
||||
- (void)releaseDisplayLink
|
||||
{
|
||||
if (_displayLinkRef == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
CVDisplayLinkStop(_displayLinkRef);
|
||||
CVDisplayLinkRelease(_displayLinkRef);
|
||||
|
||||
_displayLinkRef = NULL;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static CVReturn detailViewAnimationCallback(
|
||||
CVDisplayLinkRef displayLink,
|
||||
const CVTimeStamp *inNow,
|
||||
const CVTimeStamp *inOutputTime,
|
||||
CVOptionFlags flagsIn,
|
||||
CVOptionFlags *flagsOut,
|
||||
void *displayLinkContext)
|
||||
{
|
||||
VLCLibraryCollectionViewFlowLayout *bridgedSelf = (__bridge VLCLibraryCollectionViewFlowLayout *)displayLinkContext;
|
||||
BOOL animationFinished = NO;
|
||||
|
||||
if(bridgedSelf.detailViewIsAnimating) {
|
||||
if (bridgedSelf.animationIsCollapse) {
|
||||
--bridgedSelf.animationIndex;
|
||||
animationFinished = (bridgedSelf.animationIndex == kWrapAroundValue);
|
||||
} else {
|
||||
++bridgedSelf.animationIndex;
|
||||
animationFinished = (bridgedSelf.animationIndex == kAnimationSteps);
|
||||
}
|
||||
}
|
||||
|
||||
if (bridgedSelf.detailViewIsAnimating == NO || animationFinished) {
|
||||
bridgedSelf.detailViewIsAnimating = NO;
|
||||
[bridgedSelf releaseDisplayLink];
|
||||
|
||||
if (bridgedSelf.animationIsCollapse) {
|
||||
bridgedSelf.selectedIndexPath = nil;
|
||||
bridgedSelf.animationIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void){
|
||||
[bridgedSelf invalidateLayout];
|
||||
});
|
||||
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
|
@ -322,6 +322,9 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
|
|||
_audioGroupSelectionTableView.dataSource = _libraryAudioGroupDataSource;
|
||||
_audioGroupSelectionTableView.delegate = _libraryAudioGroupDataSource;
|
||||
_audioGroupSelectionTableView.rowHeight = [VLCLibraryAlbumTableCellView defaultHeight];
|
||||
_audioLibraryCollectionView.selectable = YES;
|
||||
_audioLibraryCollectionView.allowsMultipleSelection = NO;
|
||||
_audioLibraryCollectionView.allowsEmptySelection = YES;
|
||||
|
||||
_mediaSourceDataSource = [[VLCMediaSourceBaseDataSource alloc] init];
|
||||
_mediaSourceDataSource.collectionView = _mediaSourceCollectionView;
|
||||
|
|
Loading…
Reference in New Issue