You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

311 lines
13 KiB

/*****************************************************************************
* VLCLibraryAlbumTableCellView.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 "VLCLibraryAlbumTableCellView.h"
#import "extensions/NSColor+VLCAdditions.h"
#import "extensions/NSFont+VLCAdditions.h"
#import "extensions/NSString+Helpers.h"
#import "extensions/NSView+VLCAdditions.h"
#import "views/VLCImageView.h"
#import "views/VLCTrackingView.h"
#import "main/VLCMain.h"
#import "library/VLCLibraryController.h"
#import "library/VLCLibraryDataTypes.h"
#import "library/VLCLibraryImageCache.h"
#import "library/VLCLibraryModel.h"
#import "library/VLCLibraryTableCellView.h"
#import "library/VLCLibraryTableView.h"
#import "library/VLCLibraryUIUnits.h"
#import "library/audio-library/VLCLibraryAlbumTracksDataSource.h"
#import "library/audio-library/VLCLibraryAlbumTracksTableViewDelegate.h"
NSString * const VLCAudioLibraryCellIdentifier = @"VLCAudioLibraryCellIdentifier";
NSString * const VLCLibraryAlbumTableCellTableViewIdentifier = @"VLCLibraryAlbumTableCellTableViewIdentifier";
NSString * const VLCLibraryAlbumTableCellTableViewColumnIdentifier = @"VLCLibraryAlbumTableCellTableViewColumnIdentifier";
const CGFloat VLCLibraryAlbumTableCellViewDefaultHeight = 168.;
@interface VLCLibraryAlbumTableCellView ()
{
VLCLibraryController *_libraryController;
VLCLibraryAlbumTracksDataSource *_tracksDataSource;
VLCLibraryAlbumTracksTableViewDelegate *_tracksTableViewDelegate;
VLCLibraryTableView *_tracksTableView;
NSTableColumn *_column;
}
@end
@implementation VLCLibraryAlbumTableCellView
+ (instancetype)fromNibWithOwner:(id)owner
{
return (VLCLibraryAlbumTableCellView*)[NSView fromNibNamed:@"VLCLibraryAlbumTableCellView"
withClass:[VLCLibraryAlbumTableCellView class]
withOwner:owner];
}
+ (CGFloat)defaultHeight
{
return VLCLibraryAlbumTableCellViewDefaultHeight;
}
- (CGFloat)height
{
if (_representedAlbum == nil) {
return -1;
}
const CGFloat artworkAndSecondaryLabelsHeight = VLCLibraryUIUnits.largeSpacing +
_representedImageView.frame.size.height +
VLCLibraryUIUnits.mediumSpacing +
_summaryTextField.frame.size.height +
VLCLibraryUIUnits.smallSpacing +
_yearTextField.frame.size.height +
VLCLibraryUIUnits.largeSpacing;
if(_tracksTableView == nil) {
return artworkAndSecondaryLabelsHeight;
}
const CGFloat titleAndTableViewHeight = VLCLibraryUIUnits.largeSpacing +
_albumNameTextField.frame.size.height +
VLCLibraryUIUnits.smallSpacing +
_artistNameTextField.frame.size.height +
VLCLibraryUIUnits.smallSpacing +
[self expectedTableViewHeight] +
VLCLibraryUIUnits.largeSpacing;
return titleAndTableViewHeight > artworkAndSecondaryLabelsHeight ? titleAndTableViewHeight : artworkAndSecondaryLabelsHeight;
}
- (CGFloat)expectedTableViewWidth
{
// We are positioning the table view to the right of the album art, which means we need
// to take into account the album's left spacing, right spacing, and the table view's
// right spacing. In this case we are using large spacing for all of these. We also
// throw in a little bit extra spacing to compensate for some mysterious internal spacing.
return self.frame.size.width - _representedImageView.frame.size.width - VLCLibraryUIUnits.largeSpacing * 3.75;
}
- (CGFloat)expectedTableViewHeight
{
const NSUInteger numberOfTracks = _representedAlbum.numberOfTracks;
const CGFloat intercellSpacing = numberOfTracks > 1 ? (numberOfTracks - 1) * _tracksTableView.intercellSpacing.height : 0;
return numberOfTracks * VLCLibraryTracksRowHeight + intercellSpacing + VLCLibraryUIUnits.mediumSpacing;
}
- (void)awakeFromNib
{
[self setupTracksTableView];
self.albumNameTextField.font = NSFont.VLCLibrarySubsectionHeaderFont;
self.artistNameTextField.font = NSFont.VLCLibrarySubsectionSubheaderFont;
self.trackingView.viewToHide = self.playInstantlyButton;
self.artistNameTextField.textColor = NSColor.VLCAccentColor;
[self prepareForReuse];
NSNotificationCenter * const notificationCenter = NSNotificationCenter.defaultCenter;
[notificationCenter addObserver:self
selector:@selector(handleAlbumUpdated:)
name:VLCLibraryModelAlbumUpdated
object:nil];
}
- (void)setupTracksTableView
{
_tracksTableView = [[VLCLibraryTableView alloc] initWithFrame:NSZeroRect];
_tracksTableView.identifier = VLCLibraryAlbumTableCellTableViewIdentifier;
_column = [[NSTableColumn alloc] initWithIdentifier:VLCLibraryAlbumTableCellTableViewColumnIdentifier];
_column.width = [self expectedTableViewWidth];
_column.maxWidth = MAXFLOAT;
[_tracksTableView addTableColumn:_column];
if(@available(macOS 11.0, *)) {
_tracksTableView.style = NSTableViewStyleFullWidth;
}
_tracksTableView.gridStyleMask = NSTableViewSolidHorizontalGridLineMask;
_tracksTableView.rowHeight = VLCLibraryTracksRowHeight;
_tracksTableView.backgroundColor = [NSColor clearColor];
_tracksDataSource = [[VLCLibraryAlbumTracksDataSource alloc] init];
_tracksTableViewDelegate = [[VLCLibraryAlbumTracksTableViewDelegate alloc] init];
_tracksTableView.dataSource = _tracksDataSource;
_tracksTableView.delegate = _tracksTableViewDelegate;
_tracksTableView.doubleAction = @selector(tracksTableViewDoubleClickAction:);
_tracksTableView.target = self;
_tracksTableView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_tracksTableView];
NSString *horizontalVisualConstraints = [NSString stringWithFormat:@"H:|-%f-[_representedImageView]-%f-[_tracksTableView]-%f-|",
VLCLibraryUIUnits.largeSpacing,
VLCLibraryUIUnits.largeSpacing,
VLCLibraryUIUnits.largeSpacing];
NSString *verticalVisualContraints = [NSString stringWithFormat:@"V:|-%f-[_albumNameTextField]-%f-[_artistNameTextField]-%f-[_tracksTableView]->=%f-|",
VLCLibraryUIUnits.largeSpacing,
VLCLibraryUIUnits.smallSpacing,
VLCLibraryUIUnits.mediumSpacing,
VLCLibraryUIUnits.largeSpacing];
NSDictionary *dict = NSDictionaryOfVariableBindings(_tracksTableView, _representedImageView, _albumNameTextField, _artistNameTextField);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:horizontalVisualConstraints options:0 metrics:0 views:dict]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalVisualContraints options:0 metrics:0 views:dict]];
NSNotificationCenter *notificationCenter = NSNotificationCenter.defaultCenter;
[notificationCenter addObserver:self
selector:@selector(handleTableViewSelectionIsChanging:)
name:NSTableViewSelectionIsChangingNotification
object:nil];
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.representedImageView.image = nil;
self.albumNameTextField.stringValue = @"";
self.artistNameTextField.stringValue = @"";
self.yearTextField.stringValue = @"";
self.summaryTextField.stringValue = @"";
self.yearTextField.hidden = NO;
self.playInstantlyButton.hidden = YES;
_tracksDataSource.representedAlbum = nil;
[_tracksTableView reloadData];
}
- (void)handleAlbumUpdated:(NSNotification *)notification
{
NSParameterAssert(notification);
if (_representedAlbum == nil) {
return;
}
VLCMediaLibraryAlbum * const album = (VLCMediaLibraryAlbum *)notification.object;
if (album == nil || _representedAlbum.libraryID != album.libraryID) {
return;
}
[self setRepresentedAlbum:album];
}
- (void)setFrameSize:(NSSize)size
{
[super setFrameSize:size];
// As it expects a scrollview as a parent, the table view will always resize itself and
// we cannot directly set its size. However, it resizes itself according to its columns
// and rows. We can therefore implicitly set its width by resizing the single column we
// are using.
//
// Since a column is just an NSObject and not an actual NSView object, however, we cannot
// use the normal autosizing/constraint systems and must instead calculate and set its
// size manually.
_column.width = [self expectedTableViewWidth];
}
- (IBAction)playInstantly:(id)sender
{
if (!_libraryController) {
_libraryController = VLCMain.sharedInstance.libraryController;
}
BOOL playImmediately = YES;
for (VLCMediaLibraryMediaItem *mediaItem in [_representedAlbum tracksAsMediaItems]) {
[_libraryController appendItemToPlaylist:mediaItem playImmediately:playImmediately];
if (playImmediately) {
playImmediately = NO;
}
}
}
- (void)setRepresentedAlbum:(VLCMediaLibraryAlbum *)representedAlbum
{
_representedAlbum = representedAlbum;
self.albumNameTextField.stringValue = _representedAlbum.title;
self.artistNameTextField.stringValue = _representedAlbum.artistName;
if (_representedAlbum.year > 0) {
self.yearTextField.intValue = _representedAlbum.year;
} else {
self.yearTextField.hidden = YES;
}
if (_representedAlbum.summary.length > 0) {
self.summaryTextField.stringValue = _representedAlbum.summary;
} else {
self.summaryTextField.stringValue = _representedAlbum.durationString;
}
[VLCLibraryImageCache thumbnailForLibraryItem:_representedAlbum withCompletion:^(NSImage * const thumbnail) {
self.representedImageView.image = thumbnail;
}];
__weak typeof(self) weakSelf = self; // Prevent retain cycle
[_tracksDataSource setRepresentedAlbum:_representedAlbum withCompletion:^{
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf->_tracksTableView reloadData];
}
}];
}
- (void)setRepresentedItem:(id<VLCMediaLibraryItemProtocol>)libraryItem
{
VLCMediaLibraryAlbum * const album = (VLCMediaLibraryAlbum *)libraryItem;
if (album != nil) {
[self setRepresentedAlbum:album];
}
}
- (void)tracksTableViewDoubleClickAction:(id)sender
{
if (!_libraryController) {
_libraryController = VLCMain.sharedInstance.libraryController;
}
NSArray *tracks = [_representedAlbum tracksAsMediaItems];
NSUInteger trackCount = tracks.count;
NSInteger clickedRow = _tracksTableView.clickedRow;
if (clickedRow < trackCount) {
[_libraryController appendItemToPlaylist:tracks[_tracksTableView.clickedRow] playImmediately:YES];
}
}
- (void)handleTableViewSelectionIsChanging:(NSNotification *)notification
{
NSParameterAssert(notification);
NSTableView * const tableView = notification.object;
NSAssert(tableView, @"Table view selection changing notification should carry valid table view");
if (tableView != _tracksTableView &&
tableView.identifier == VLCLibraryAlbumTableCellTableViewIdentifier) {
[_tracksTableView deselectAll:self];
}
}
@end