[vlc-commits] [Git][videolan/vlc][master] 6 commits: macosx: Add VLCLibraryAudioDataSourceHeaderDelegate

Steve Lhomme (@robUx4) gitlab at videolan.org
Mon Nov 24 06:19:52 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
47ca5186 by Claudio Cambra at 2025-11-24T05:51:16+00:00
macosx: Add VLCLibraryAudioDataSourceHeaderDelegate

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
ce3ffce9 by Claudio Cambra at 2025-11-24T05:51:16+00:00
macosx: Add new header delegate property to audio data source

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
c5f37759 by Claudio Cambra at 2025-11-24T05:51:16+00:00
macosx: Add a audio group table header view

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
7b418774 by Claudio Cambra at 2025-11-24T05:51:16+00:00
macosx: Configure audio group table header view and delegation for it in VLCLibraryAudioViewController

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
f04b622e by Claudio Cambra at 2025-11-24T05:51:16+00:00
macosx: Use an NSGlassEffectView for the audio group table header view on macOS 26

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
05f437f9 by Claudio Cambra at 2025-11-24T05:51:16+00:00
macosx: Add VLCLibraryAudioGroupTableHeaderCell

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -


10 changed files:

- modules/gui/macosx/Makefile.am
- modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSource.h
- modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSource.m
- + modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSourceHeaderDelegate.h
- + modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderCell.h
- + modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderCell.m
- + modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderView.h
- + modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderView.m
- modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.h
- modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.m


Changes:

=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -276,11 +276,16 @@ libmacosx_plugin_la_SOURCES = \
 	gui/macosx/library/audio-library/VLCLibraryAllAudioGroupsMediaLibraryItem.h \
 	gui/macosx/library/audio-library/VLCLibraryAllAudioGroupsMediaLibraryItem.m \
 	gui/macosx/library/audio-library/VLCLibraryAudioDataSource.h \
+	gui/macosx/library/audio-library/VLCLibraryAudioDataSourceHeaderDelegate.h \
 	gui/macosx/library/audio-library/VLCLibraryAudioDataSource.m \
 	gui/macosx/library/audio-library/VLCLibraryAudioGroupDataSource.h \
 	gui/macosx/library/audio-library/VLCLibraryAudioGroupDataSource.m \
 	gui/macosx/library/audio-library/VLCLibraryAudioGroupHeaderView.h \
 	gui/macosx/library/audio-library/VLCLibraryAudioGroupHeaderView.m \
+	gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderCell.h \
+	gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderCell.m \
+	gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderView.h \
+	gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderView.m \
 	gui/macosx/library/audio-library/VLCLibraryAudioGroupTableViewDelegate.h \
 	gui/macosx/library/audio-library/VLCLibraryAudioGroupTableViewDelegate.m \
 	gui/macosx/library/audio-library/VLCLibraryAudioTableViewDelegate.h \


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSource.h
=====================================
@@ -24,6 +24,7 @@
 
 #import "library/VLCLibraryCollectionViewDataSource.h"
 #import "library/VLCLibraryTableViewDataSource.h"
+#import "library/audio-library/VLCLibraryAudioDataSourceHeaderDelegate.h"
 
 #include "views/iCarousel/iCarousel.h"
 
@@ -60,6 +61,8 @@ extern NSString * const VLCLibraryYearSortDescriptorKey;
 
 extern NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification;
 
+ at class VLCLibraryRepresentedItem;
+
 @interface VLCLibraryAudioDataSource : NSObject <VLCLibraryTableViewDataSource, VLCLibraryCollectionViewDataSource, iCarouselDataSource>
 
 @property (readwrite, weak) VLCLibraryModel *libraryModel;
@@ -68,6 +71,7 @@ extern NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotif
 @property (readwrite, weak) NSCollectionView *collectionView;
 @property (readwrite, weak) iCarousel *carouselView;
 @property (readwrite, weak) NSTableView *gridModeListTableView;
+ at property (readwrite, weak, nullable) id<VLCLibraryAudioDataSourceHeaderDelegate> headerDelegate;
 
 @property (nonatomic, readwrite, assign) VLCAudioLibrarySegment audioLibrarySegment;
 @property (readwrite, strong) VLCLibraryAudioGroupDataSource *audioGroupDataSource;
@@ -80,6 +84,7 @@ extern NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotif
 - (void)setup;
 - (void)reloadData;
 - (void)tableView:(NSTableView * const)tableView selectRowIndices:(NSIndexSet * const)indices;
+- (void)applySelectionForTableView:(NSTableView *)tableView;
 
 @end
 


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSource.m
=====================================
@@ -693,6 +693,48 @@ NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification
     return self.displayedCollection[row];
 }
 
+- (void)applySelectionForTableView:(NSTableView *)tableView
+{
+    if (tableView == nil ||
+        (tableView != self.collectionSelectionTableView && tableView != self.gridModeListTableView)) {
+        return;
+    }
+
+    const NSInteger selectedRow = tableView.selectedRow;
+    if (selectedRow >= 0 && (NSUInteger)selectedRow >= self.displayedCollection.count) {
+        return;
+    }
+
+    const BOOL shouldClearSelection = self.currentParentType == VLCMediaLibraryParentGroupTypeAudioLibrary ||
+                                      self.currentParentType == VLCMediaLibraryParentGroupTypeRecentAudios ||
+                                      selectedRow < 0 ||
+                                      self.displayedCollectionUpdating;
+
+    const id<VLCMediaLibraryAudioGroupProtocol> selectedItem =
+        shouldClearSelection ? nil : self.displayedCollection[selectedRow];
+    self.audioGroupDataSource.representedAudioGroup = selectedItem;
+
+    VLCLibraryRepresentedItem *representedItem = nil;
+    NSString *fallbackTitle = nil;
+    NSString *fallbackDetail = nil;
+
+    if (self.displayAllArtistsGenresTableEntry && selectedRow == 0) {
+        fallbackTitle = (self.currentParentType == VLCMediaLibraryParentGroupTypeGenre)
+            ? _NS("All genres")
+            : _NS("All artists");
+    } else if (selectedItem != nil) {
+        representedItem = [[VLCLibraryRepresentedItem alloc] initWithItem:selectedItem parentType:self.currentParentType];
+        fallbackTitle = selectedItem.displayString;
+        fallbackDetail = selectedItem.primaryDetailString;
+    }
+
+    [self.headerDelegate audioDataSource:self
+                updateHeaderForTableView:tableView
+                     withRepresentedItem:representedItem
+                           fallbackTitle:fallbackTitle
+                          fallbackDetail:fallbackDetail];
+}
+
 - (void)tableView:(NSTableView * const)tableView selectRowIndices:(NSIndexSet * const)indices
 {
     NSParameterAssert(tableView);
@@ -711,14 +753,7 @@ NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification
         return;
     }
 
-    if (self.currentParentType == VLCMediaLibraryParentGroupTypeAudioLibrary ||
-        self.currentParentType == VLCMediaLibraryParentGroupTypeRecentAudios ||
-        selectedRow < 0 ||
-        self.displayedCollectionUpdating) {
-        self.audioGroupDataSource.representedAudioGroup = nil;
-    } else {
-        self.audioGroupDataSource.representedAudioGroup = self.displayedCollection[selectedRow];
-    }
+    [self applySelectionForTableView:tableView];
 }
 
 - (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray<NSSortDescriptor *> *)oldDescriptors


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSourceHeaderDelegate.h
=====================================
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * VLCLibraryAudioDataSourceHeaderDelegate.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2025 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.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>
+
+ at class VLCLibraryAudioDataSource;
+ at class VLCLibraryRepresentedItem;
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at protocol VLCLibraryAudioDataSourceHeaderDelegate <NSObject>
+
+- (void)audioDataSource:(VLCLibraryAudioDataSource *)dataSource
+    updateHeaderForTableView:(NSTableView *)tableView
+         withRepresentedItem:(VLCLibraryRepresentedItem *)representedItem
+               fallbackTitle:(NSString *)fallbackTitle
+              fallbackDetail:(NSString *)fallbackDetail;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderCell.h
=====================================
@@ -0,0 +1,32 @@
+/*****************************************************************************
+ * VLCLibraryAudioGroupTableHeaderCell.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2025 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.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
+
+ at interface VLCLibraryAudioGroupTableHeaderCell : NSTableHeaderCell
+
+ at end
+
+NS_ASSUME_NONNULL_END
+


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderCell.m
=====================================
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * VLCLibraryAudioGroupTableHeaderCell.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2025 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.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 "VLCLibraryAudioGroupTableHeaderCell.h"
+
+ at implementation VLCLibraryAudioGroupTableHeaderCell
+
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
+{
+    // Intentionally do not call super to prevent AppKit from drawing its default background.
+    // The header view hosts its own background visuals (glass/effect/solid) and draws content there.
+    [NSColor.clearColor setFill];
+    NSRectFillUsingOperation(cellFrame, NSCompositingOperationClear);
+}
+
+ at end


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderView.h
=====================================
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * VLCLibraryAudioGroupTableHeaderView.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2025 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.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>
+
+ at class VLCLibraryRepresentedItem;
+
+NS_ASSUME_NONNULL_BEGIN
+
+extern const CGFloat VLCLibraryAudioGroupTableHeaderViewHeight;
+
+ at interface VLCLibraryAudioGroupTableHeaderView : NSTableHeaderView
+
+ at property (nullable, nonatomic) VLCLibraryRepresentedItem *representedItem;
+
+- (void)updateWithRepresentedItem:(nullable VLCLibraryRepresentedItem *)representedItem
+                    fallbackTitle:(nullable NSString *)fallbackTitle
+                   fallbackDetail:(nullable NSString *)fallbackDetail;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupTableHeaderView.m
=====================================
@@ -0,0 +1,268 @@
+/*****************************************************************************
+ * VLCLibraryAudioGroupTableHeaderView.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2025 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.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 "VLCLibraryAudioGroupTableHeaderView.h"
+
+#import "library/VLCLibraryRepresentedItem.h"
+#import "library/VLCLibraryUIUnits.h"
+
+#import "extensions/NSColor+VLCAdditions.h"
+#import "extensions/NSFont+VLCAdditions.h"
+#import "extensions/NSString+Helpers.h"
+
+const CGFloat VLCLibraryAudioGroupTableHeaderViewHeight = 86.f;
+
+ at interface VLCLibraryAudioGroupTableHeaderView ()
+
+ at property NSView *backgroundView;
+ at property NSStackView *rootStackView;
+ at property NSStackView *labelsStackView;
+ at property NSStackView *buttonsStackView;
+ at property NSTextField *titleField;
+ at property NSTextField *detailField;
+ at property NSButton *playButton;
+ at property NSButton *queueButton;
+ at property CGFloat backgroundEdgeInset;
+
+ at end
+
+ at implementation VLCLibraryAudioGroupTableHeaderView
+
+- (instancetype)initWithFrame:(NSRect)frameRect
+{
+    self = [super initWithFrame:frameRect];
+    if (self) {
+        [self commonInit];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)coder
+{
+    self = [super initWithCoder:coder];
+    if (self) {
+        [self commonInit];
+    }
+    return self;
+}
+
+
+- (void)commonInit
+{
+    NSView *contentHostView = self;
+    self.backgroundEdgeInset = 0.f;
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 260000
+    if (@available(macOS 26.0, *)) {
+        NSGlassEffectView * const glassView = [[NSGlassEffectView alloc] initWithFrame:self.bounds];
+        glassView.translatesAutoresizingMaskIntoConstraints = NO;
+        NSView * const glassContentView = [[NSView alloc] initWithFrame:glassView.bounds];
+        glassContentView.translatesAutoresizingMaskIntoConstraints = NO;
+        glassView.contentView = glassContentView;
+        self.backgroundView = glassView;
+        contentHostView = glassContentView;
+        self.backgroundEdgeInset = VLCLibraryUIUnits.largeSpacing * 1.75;
+    }
+#endif
+    if (self.backgroundView == nil) {
+        self.wantsLayer = YES;
+
+        if (@available(macOS 10.14, *)) {
+            NSVisualEffectView * const visualEffectView = [[NSVisualEffectView alloc] initWithFrame:self.bounds];
+            visualEffectView.translatesAutoresizingMaskIntoConstraints = NO;
+            visualEffectView.material = NSVisualEffectMaterialHeaderView;
+            visualEffectView.blendingMode = NSVisualEffectBlendingModeWithinWindow;
+            visualEffectView.state = NSVisualEffectStateFollowsWindowActiveState;
+            self.backgroundView = visualEffectView;
+        }
+    }
+    if (self.backgroundView == nil) {
+        NSView * const fallbackBackgroundView = [[NSView alloc] initWithFrame:self.bounds];
+        fallbackBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
+        fallbackBackgroundView.wantsLayer = YES;
+        fallbackBackgroundView.layer.backgroundColor = NSColor.windowBackgroundColor.CGColor;
+        self.backgroundView = fallbackBackgroundView;
+    }
+
+    [self addSubview:self.backgroundView];
+
+    self.titleField = [self buildLabelWithFont:NSFont.VLClibrarySectionHeaderFont
+                                      textColor:NSColor.labelColor
+                                      alignment:NSTextAlignmentLeft];
+    self.detailField = [self buildLabelWithFont:NSFont.VLCLibrarySubsectionSubheaderFont
+                                       textColor:NSColor.secondaryLabelColor
+                                       alignment:NSTextAlignmentLeft];
+    self.playButton = [self buildActionButtonWithTitle:_NS("Play") action:@selector(play:)];
+    self.queueButton = [self buildActionButtonWithTitle:_NS("Queue") action:@selector(enqueue:)];
+
+    NSStackView * const labelsStack = [NSStackView stackViewWithViews:@[self.titleField, self.detailField]];
+    labelsStack.translatesAutoresizingMaskIntoConstraints = NO;
+    labelsStack.orientation = NSUserInterfaceLayoutOrientationVertical;
+    labelsStack.alignment = NSLayoutAttributeLeading;
+    labelsStack.spacing = VLCLibraryUIUnits.smallSpacing;
+    [labelsStack setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
+    [labelsStack setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal];
+    self.labelsStackView = labelsStack;
+
+    NSStackView * const buttonsStack = [NSStackView stackViewWithViews:@[self.playButton, self.queueButton]];
+    buttonsStack.translatesAutoresizingMaskIntoConstraints = NO;
+    buttonsStack.orientation = NSUserInterfaceLayoutOrientationHorizontal;
+    buttonsStack.alignment = NSLayoutAttributeCenterY;
+    buttonsStack.spacing = VLCLibraryUIUnits.smallSpacing;
+    [buttonsStack setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal];
+    [buttonsStack setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal];
+    self.buttonsStackView = buttonsStack;
+
+    [contentHostView addSubview:labelsStack];
+    [contentHostView addSubview:buttonsStack];
+
+    const CGFloat backgroundInset = self.backgroundEdgeInset;
+    const CGFloat horizontalContentInset = VLCLibraryUIUnits.mediumSpacing;
+    const CGFloat verticalContentInset = VLCLibraryUIUnits.smallSpacing;
+
+    [NSLayoutConstraint activateConstraints:@[
+        [self.backgroundView.topAnchor constraintEqualToAnchor:self.topAnchor constant:backgroundInset * 0.66],
+        [self.backgroundView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
+        [self.backgroundView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
+        [self.backgroundView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-backgroundInset],
+        [labelsStack.leadingAnchor constraintEqualToAnchor:contentHostView.leadingAnchor constant:horizontalContentInset],
+        [labelsStack.centerYAnchor constraintEqualToAnchor:contentHostView.centerYAnchor],
+        [contentHostView.trailingAnchor constraintEqualToAnchor:buttonsStack.trailingAnchor constant:horizontalContentInset],
+        [buttonsStack.centerYAnchor constraintEqualToAnchor:contentHostView.centerYAnchor],
+        [buttonsStack.leadingAnchor constraintGreaterThanOrEqualToAnchor:labelsStack.trailingAnchor constant:VLCLibraryUIUnits.largeSpacing],
+    ]];
+
+    if (@available(macOS 26.0, *)) {
+    } else {
+        self.layer.cornerRadius = VLCLibraryUIUnits.smallSpacing;
+        self.layer.masksToBounds = YES;
+        self.layer.borderWidth = VLCLibraryUIUnits.borderThickness;
+        [self updateAppearance];
+    }
+}
+
+- (NSTextField *)buildLabelWithFont:(NSFont *)font textColor:(NSColor *)color alignment:(NSTextAlignment)alignment
+{
+    NSTextField *label;
+    if (@available(macOS 10.12, *)) {
+        label = [NSTextField labelWithString:@""];
+    } else {
+        label = [[NSTextField alloc] initWithFrame:NSZeroRect];
+        label.editable = NO;
+        label.bezeled = NO;
+        label.drawsBackground = NO;
+        label.selectable = NO;
+    }
+    label.font = font;
+    label.textColor = color;
+    label.alignment = alignment;
+    label.lineBreakMode = NSLineBreakByTruncatingTail;
+    label.translatesAutoresizingMaskIntoConstraints = NO;
+    return label;
+}
+
+- (NSButton *)buildActionButtonWithTitle:(NSString *)title action:(SEL)selector
+{
+    NSButton *button;
+    if (@available(macOS 10.12, *)) {
+        button = [NSButton buttonWithTitle:title target:self action:selector];
+    } else {
+        button = [[NSButton alloc] initWithFrame:NSZeroRect];
+        button.title = title;
+        button.target = self;
+        button.action = selector;
+    }
+    button.bezelStyle = NSBezelStyleRounded;
+    button.translatesAutoresizingMaskIntoConstraints = NO;
+    if (@available(macOS 10.14, *))
+        button.contentTintColor = NSColor.VLCAccentColor;
+    return button;
+}
+
+- (void)updateAppearance
+{
+    if (@available(macOS 26.0, *))
+        return;
+
+    if (@available(macOS 10.14, *)) {
+        NSAppearance *appearance = self.effectiveAppearance;
+        BOOL isDark = NO;
+        if ([appearance.name isEqualToString:NSAppearanceNameDarkAqua] ||
+            [appearance.name isEqualToString:NSAppearanceNameVibrantDark]) {
+            isDark = YES;
+        }
+        self.layer.borderColor = (isDark ? NSColor.VLCDarkSubtleBorderColor : NSColor.VLCLightSubtleBorderColor).CGColor;
+    } else {
+        self.layer.borderColor = NSColor.VLCLightSubtleBorderColor.CGColor;
+    }
+}
+
+- (void)viewDidChangeEffectiveAppearance
+{
+    [super viewDidChangeEffectiveAppearance];
+    [self updateAppearance];
+}
+
+- (void)setRepresentedItem:(VLCLibraryRepresentedItem *)representedItem
+{
+    _representedItem = representedItem;
+    [self applyRepresentedItemWithFallbackTitle:nil fallbackDetail:nil];
+}
+
+- (void)applyRepresentedItemWithFallbackTitle:(NSString *)fallbackTitle fallbackDetail:(NSString *)fallbackDetail
+{
+    id<VLCMediaLibraryItemProtocol> const item = self.representedItem.item;
+    if (item == nil) {
+        self.titleField.stringValue = fallbackTitle ?: @"";
+        self.detailField.stringValue = fallbackDetail ?: @"";
+        self.playButton.enabled = NO;
+        self.queueButton.enabled = NO;
+        return;
+    }
+
+    self.titleField.stringValue = item.displayString ?: fallbackTitle ?: @"";
+    self.detailField.stringValue = item.primaryDetailString ?: fallbackDetail ?: @"";
+    self.playButton.enabled = YES;
+    self.queueButton.enabled = YES;
+}
+
+- (void)updateWithRepresentedItem:(VLCLibraryRepresentedItem *)representedItem
+                    fallbackTitle:(NSString *)fallbackTitle
+                   fallbackDetail:(NSString *)fallbackDetail
+{
+    self.representedItem = representedItem;
+    [self applyRepresentedItemWithFallbackTitle:fallbackTitle fallbackDetail:fallbackDetail];
+}
+
+#pragma mark - Actions
+
+- (void)play:(id)sender
+{
+    [self.representedItem play];
+}
+
+- (void)enqueue:(id)sender
+{
+    [self.representedItem queue];
+}
+
+ at end


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.h
=====================================
@@ -25,9 +25,11 @@
 #import "library/VLCLibrarySegment.h"
 #import "library/VLCLibraryAbstractMediaLibrarySegmentViewController.h"
 #import "library/VLCLibraryItemPresentingCapable.h"
+#import "library/audio-library/VLCLibraryAudioDataSourceHeaderDelegate.h"
 
 @class VLCLibraryAudioDataSource;
 @class VLCLibraryAudioGroupDataSource;
+ at class VLCLibraryAudioGroupTableHeaderView;
 @class VLCLibraryCollectionView;
 @class VLCLibraryWindow;
 
@@ -35,12 +37,13 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
- at interface VLCLibraryAudioViewController : VLCLibraryAbstractMediaLibrarySegmentViewController<VLCLibraryItemPresentingCapable>
+ at interface VLCLibraryAudioViewController : VLCLibraryAbstractMediaLibrarySegmentViewController<VLCLibraryItemPresentingCapable, VLCLibraryAudioDataSourceHeaderDelegate>
 
 @property (readonly, weak) NSView *audioLibraryView;
 @property (readonly, weak) NSSplitView *audioLibrarySplitView;
 @property (readonly, weak) NSScrollView *audioCollectionSelectionTableViewScrollView;
 @property (readonly, weak) NSTableView *audioCollectionSelectionTableView;
+ at property (readonly, strong) VLCLibraryAudioGroupTableHeaderView *audioCollectionHeaderView;
 @property (readonly, weak) NSScrollView *audioGroupSelectionTableViewScrollView;
 @property (readonly, weak) NSTableView *audioGroupSelectionTableView;
 @property (readonly, weak) NSScrollView *audioSongTableViewScrollView;


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.m
=====================================
@@ -42,7 +42,9 @@
 #import "library/audio-library/VLCLibraryAudioDataSource.h"
 #import "library/audio-library/VLCLibraryAudioGroupDataSource.h"
 #import "library/audio-library/VLCLibraryAudioGroupHeaderView.h"
+#import "library/audio-library/VLCLibraryAudioGroupTableHeaderView.h"
 #import "library/audio-library/VLCLibraryAudioGroupTableViewDelegate.h"
+#import "library/audio-library/VLCLibraryAudioGroupTableHeaderCell.h"
 #import "library/audio-library/VLCLibraryAudioTableViewDelegate.h"
 
 #import "library/playlist-library/VLCLibraryPlaylistViewController.h"
@@ -159,6 +161,7 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
     _audioDataSource.songsTableView = _audioSongTableView;
     _audioDataSource.collectionView = _audioLibraryCollectionView;
     _audioDataSource.gridModeListTableView = _audioLibraryGridModeSplitViewListTableView;
+    _audioDataSource.headerDelegate = self;
     [_audioDataSource setup];
 
     _audioGroupDataSource = [[VLCLibraryAudioGroupDataSource alloc] init];
@@ -185,6 +188,21 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
     _audioCollectionSelectionTableView.dataSource = _audioDataSource;
     _audioCollectionSelectionTableView.delegate = _audioLibraryTableViewDelegate;
 
+    CGFloat headerHeight = VLCLibraryAudioGroupTableHeaderViewHeight;
+    if (@available(macOS 26.0, *)) {
+        headerHeight += VLCLibraryUIUnits.largeSpacing * 2.f;
+    }
+
+    const NSRect headerFrame = NSMakeRect(0.f,
+                                          0.f,
+                                          _audioGroupSelectionTableView.bounds.size.width,
+                                          headerHeight);
+    _audioCollectionHeaderView = [[VLCLibraryAudioGroupTableHeaderView alloc] initWithFrame:headerFrame];
+    _audioCollectionHeaderView.autoresizingMask = NSViewWidthSizable;
+
+    _audioGroupSelectionTableView.headerView = self.audioCollectionHeaderView;
+    _audioGroupSelectionTableView.tableColumns.firstObject.headerCell = [VLCLibraryAudioGroupTableHeaderCell new];
+
     _audioGroupSelectionTableView.dataSource = _audioGroupDataSource;
     _audioGroupSelectionTableView.delegate = _audioGroupLibraryTableViewDelegate;
 
@@ -194,6 +212,8 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
 
     _audioSongTableView.dataSource = _audioDataSource;
     _audioSongTableView.delegate = _audioLibraryTableViewDelegate;
+
+    [_audioDataSource applySelectionForTableView:_audioCollectionSelectionTableView];
 }
 
 - (void)setupGridModeSplitView
@@ -565,4 +585,24 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
     [self.libraryWindow hideLoadingOverlay];
 }
 
+- (void)audioDataSource:(VLCLibraryAudioDataSource *)dataSource
+updateHeaderForTableView:(NSTableView *)tableView
+    withRepresentedItem:(VLCLibraryRepresentedItem *)representedItem
+          fallbackTitle:(NSString *)fallbackTitle
+         fallbackDetail:(NSString *)fallbackDetail
+{
+    if (tableView != self.audioCollectionSelectionTableView &&
+        tableView != self.audioGroupSelectionTableView &&
+        ![self.audioGroupDataSource.tableViews containsObject:tableView])
+        return;
+
+    if (representedItem != nil) {
+        self.audioCollectionHeaderView.representedItem = representedItem;
+    } else {
+        [self.audioCollectionHeaderView updateWithRepresentedItem:nil
+                                                    fallbackTitle:fallbackTitle
+                                                   fallbackDetail:fallbackDetail];
+    }
+}
+
 @end



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/31b9abc49c938252c24c05871468df5444ea4bed...05f437f98ec2b830315fe11e837049c227bf3662

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/31b9abc49c938252c24c05871468df5444ea4bed...05f437f98ec2b830315fe11e837049c227bf3662
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list