[vlc-commits] [Git][videolan/vlc][master] 34 commits: macosx: Set up loading overlay view and its constraints in library window

Steve Lhomme (@robUx4) gitlab at videolan.org
Wed Oct 9 08:59:35 UTC 2024



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
519f02bf by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Set up loading overlay view and its constraints in library window

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

- - - - -
35b23d05 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's loading overlay view in video view controller

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

- - - - -
b45d33d9 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's loading overlay view in playlist view controller

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

- - - - -
eff09db4 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's loading overlay view in home view controller

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

- - - - -
043fb0ec by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's loading overlay view in audio view controller

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

- - - - -
7301a852 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Add method to show loading overlay in library window

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

- - - - -
3663f7c3 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Add method to hide loading overlay in library window

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

- - - - -
37dcce74 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window method to show/hide loading overlay view in audio view controller

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

- - - - -
57adc3eb by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window method to show/hide loading overlay view in home view controller

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

- - - - -
a0cc8f25 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window method to show/hide loading overlay view in playlist view controller

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

- - - - -
e6916053 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Do not store loading overlay view property in audio view controller

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

- - - - -
bc66f87a by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Do not store loading overlay view property in home view controller

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

- - - - -
6c72e2f6 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Do not store loading overlay view property in playlist view controller

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

- - - - -
49822dbf by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: macosx: Use library window method to show/hide loading overlay view in video view controller

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

- - - - -
39873025 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Add method to handle displaying of library views in library window

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

- - - - -
17f98fd7 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Do not store loading overlay view property in video view controller

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

- - - - -
cfb7d8a9 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's displayLibraryView in audio view controller

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

- - - - -
3c9195d8 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's displayLibraryView in groups view controller

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

- - - - -
89a12669 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's displayLibraryView in home view controller

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

- - - - -
ebc9bf29 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's displayLibraryView in media source view controller

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

- - - - -
c89b51fb by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's displayLibraryView in playlist view controller

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

- - - - -
e700288c by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's displayLibraryView in video view controller

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

- - - - -
a4bb6e0c by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Add method in library window to display the placeholder message

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

- - - - -
e3bd111d by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window method to display placeholder view in audio view controller

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

- - - - -
8f2202fc by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window method to display placeholder view in home view controller

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

- - - - -
2e3d6c4e by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window method to display placeholder view in playlist view controller

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

- - - - -
78289c4f by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window method to display placeholder view in video view controller

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

- - - - -
731de3be by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Add method to display no results label in library window

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

- - - - -
8f56e470 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's displayNoResultsMessage in audio view controller

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

- - - - -
2cea24e1 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use library window's displayNoResultsMessage in video view controller

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

- - - - -
d5692b7f by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Display no results message if relevant in playlists view

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

- - - - -
ea9a3b13 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Remove playlist view controller todo comment now that it has been addressed

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

- - - - -
e7558569 by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use displayLibraryPlaceholderViewWithImage in placeholder presentation of groups view controller

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

- - - - -
07dab83c by Claudio Cambra at 2024-10-09T08:37:07+00:00
macosx: Use new methods to present views in groups view controller including no results

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

- - - - -


12 changed files:

- modules/gui/macosx/library/VLCLibraryWindow.h
- modules/gui/macosx/library/VLCLibraryWindow.m
- modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.h
- modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.m
- modules/gui/macosx/library/groups-library/VLCLibraryGroupsViewController.m
- modules/gui/macosx/library/home-library/VLCLibraryHomeViewController.h
- modules/gui/macosx/library/home-library/VLCLibraryHomeViewController.m
- modules/gui/macosx/library/media-source/VLCLibraryMediaSourceViewController.m
- modules/gui/macosx/library/playlist-library/VLCLibraryPlaylistViewController.h
- modules/gui/macosx/library/playlist-library/VLCLibraryPlaylistViewController.m
- modules/gui/macosx/library/video-library/VLCLibraryVideoViewController.h
- modules/gui/macosx/library/video-library/VLCLibraryVideoViewController.m


Changes:

=====================================
modules/gui/macosx/library/VLCLibraryWindow.h
=====================================
@@ -39,6 +39,8 @@ NS_ASSUME_NONNULL_BEGIN
 @class VLCCustomEmptyLibraryBrowseButton;
 @class VLCLibraryWindowSplitViewController;
 @class VLCLibraryWindowToolbarDelegate;
+ at class VLCLoadingOverlayView;
+ at class VLCNoResultsLabel;
 
 @protocol VLCMediaLibraryItemProtocol;
 
@@ -113,6 +115,11 @@ extern const NSUserInterfaceItemIdentifier VLCLibraryWindowIdentifier;
 @property (nonatomic, readwrite, strong) IBOutlet NSTextField *placeholderLabel;
 @property (nonatomic, readwrite, strong) IBOutlet VLCCustomEmptyLibraryBrowseButton *placeholderGoToBrowseButton;
 
+ at property (readonly) VLCLoadingOverlayView *loadingOverlayView;
+ at property (readonly) NSArray<NSLayoutConstraint *> *loadingOverlayViewConstraints;
+ at property (readonly) NSArray<NSLayoutConstraint *> *placeholderImageViewConstraints;
+ at property (readonly) VLCNoResultsLabel *noResultsLabel;
+
 @property (readwrite, nonatomic) NSInteger librarySegmentType;
 @property (readwrite) BOOL nonembedded;
 
@@ -130,7 +137,14 @@ extern const NSUserInterfaceItemIdentifier VLCLibraryWindowIdentifier;
 - (void)updateGridVsListViewModeSegmentedControl;
 - (void)updateFilterString;
 - (void)clearFilterString;
-
+- (void)showLoadingOverlay;
+- (void)hideLoadingOverlay;
+
+- (void)displayLibraryView:(NSView *)view;
+- (void)displayLibraryPlaceholderViewWithImage:(NSImage *)image
+                              usingConstraints:(NSArray<NSLayoutConstraint *> *)constraints
+                             displayingMessage:(NSString *)message;
+- (void)displayNoResultsMessage;
 - (void)presentLibraryItem:(id<VLCMediaLibraryItemProtocol>)libraryItem;
 - (void)goToLocalFolderMrl:(NSString *)mrl;
 


=====================================
modules/gui/macosx/library/VLCLibraryWindow.m
=====================================
@@ -71,6 +71,8 @@
 #import "views/VLCBottomBarView.h"
 #import "views/VLCCustomWindowButton.h"
 #import "views/VLCDragDropView.h"
+#import "views/VLCLoadingOverlayView.h"
+#import "views/VLCNoResultsLabel.h"
 #import "views/VLCRoundedCornerTextField.h"
 
 #import "windows/controlsbar/VLCControlsBarCommon.h"
@@ -186,6 +188,7 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     _libraryMediaSourceViewController = [[VLCLibraryMediaSourceViewController alloc] initWithLibraryWindow:self];
 
     [self setViewForSelectedSegment];
+    [self setupLoadingOverlayView];
 }
 
 - (void)dealloc
@@ -206,6 +209,42 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     [coder encodeInteger:_librarySegmentType forKey:@"macosx-library-selected-segment"];
 }
 
+- (void)setupLoadingOverlayView
+{
+    _loadingOverlayView = [[VLCLoadingOverlayView alloc] init];
+    self.loadingOverlayView.translatesAutoresizingMaskIntoConstraints = NO;
+    _loadingOverlayViewConstraints = @[
+        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
+                                     attribute:NSLayoutAttributeTop
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self.libraryTargetView
+                                     attribute:NSLayoutAttributeTop
+                                    multiplier:1
+                                      constant:0],
+        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
+                                     attribute:NSLayoutAttributeRight
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self.libraryTargetView
+                                     attribute:NSLayoutAttributeRight
+                                    multiplier:1
+                                      constant:0],
+        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
+                                     attribute:NSLayoutAttributeBottom
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self.libraryTargetView
+                                     attribute:NSLayoutAttributeBottom
+                                    multiplier:1
+                                      constant:0],
+        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
+                                     attribute:NSLayoutAttributeLeft
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self.libraryTargetView
+                                     attribute:NSLayoutAttributeLeft
+                                    multiplier:1
+                                      constant:0]
+    ];
+}
+
 #pragma mark - misc. user interactions
 
 - (void)updateGridVsListViewModeSegmentedControl
@@ -449,6 +488,59 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     _librarySegmentViewController = lvc;
 }
 
+- (void)displayLibraryView:(NSView *)view
+{
+    view.translatesAutoresizingMaskIntoConstraints = NO;
+    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
+        self.libraryTargetView.subviews = @[view, self.loadingOverlayView];
+    } else {
+        self.libraryTargetView.subviews = @[view];
+    }
+
+    [NSLayoutConstraint activateConstraints:@[
+        [view.topAnchor constraintEqualToAnchor:self.libraryTargetView.topAnchor],
+        [view.bottomAnchor constraintEqualToAnchor:self.libraryTargetView.bottomAnchor],
+        [view.leftAnchor constraintEqualToAnchor:self.libraryTargetView.leftAnchor],
+        [view.rightAnchor constraintEqualToAnchor:self.libraryTargetView.rightAnchor]
+    ]];
+}
+
+- (void)displayLibraryPlaceholderViewWithImage:(NSImage *)image
+                              usingConstraints:(NSArray<NSLayoutConstraint *> *)constraints
+                             displayingMessage:(NSString *)message
+{
+    for (NSLayoutConstraint * const constraint in self.placeholderImageViewConstraints) {
+        constraint.active = NO;
+    }
+    _placeholderImageViewConstraints = constraints;
+    for (NSLayoutConstraint * const constraint in constraints) {
+        constraint.active = YES;
+    }
+
+    [self displayLibraryView:self.emptyLibraryView];
+    self.placeholderImageView.image = image;
+    self.placeholderLabel.stringValue = message;
+}
+
+- (void)displayNoResultsMessage
+{
+    if (self.noResultsLabel == nil) {
+        _noResultsLabel = [[VLCNoResultsLabel alloc] init];
+        _noResultsLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    }
+    
+    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
+        self.libraryTargetView.subviews = @[self.noResultsLabel, self.loadingOverlayView];
+    } else {
+        self.libraryTargetView.subviews = @[_noResultsLabel];
+    }
+
+    [NSLayoutConstraint activateConstraints:@[
+        [self.noResultsLabel.centerXAnchor constraintEqualToAnchor:self.libraryTargetView.centerXAnchor],
+        [self.noResultsLabel.centerYAnchor constraintEqualToAnchor:self.libraryTargetView.centerYAnchor]
+    ]];
+}
+
 - (void)presentAudioLibraryItem:(id<VLCMediaLibraryItemProtocol>)libraryItem
 {
     [self showAudioLibrary];
@@ -743,6 +835,48 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     self.splitViewController.multifunctionSidebarViewController.mainVideoModeEnabled = NO;
 }
 
+- (void)showLoadingOverlay
+{
+    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
+        return;
+    }
+
+    self.loadingOverlayView.wantsLayer = YES;
+    self.loadingOverlayView.alphaValue = 0.0;
+
+    NSArray * const views = [self.libraryTargetView.subviews arrayByAddingObject:self.loadingOverlayView];
+    self.libraryTargetView.subviews = views;
+    [self.libraryTargetView addConstraints:self.loadingOverlayViewConstraints];
+
+    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
+        context.duration = 0.5;
+        self.loadingOverlayView.animator.alphaValue = 1.0;
+    } completionHandler:nil];
+    [self.loadingOverlayView.indicator startAnimation:self];
+
+}
+
+- (void)hideLoadingOverlay
+{
+    if (![self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
+        return;
+    }
+
+    self.loadingOverlayView.wantsLayer = YES;
+    self.loadingOverlayView.alphaValue = 1.0;
+
+    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
+        context.duration = 1.0;
+        self.loadingOverlayView.animator.alphaValue = 0.0;
+    } completionHandler:^{
+        [self.libraryTargetView removeConstraints:self.loadingOverlayViewConstraints];
+        NSMutableArray * const views = self.libraryTargetView.subviews.mutableCopy;
+        [views removeObject:self.loadingOverlayView];
+        self.libraryTargetView.subviews = views.copy;
+        [self.loadingOverlayView.indicator stopAnimation:self];
+    }];
+}
+
 - (void)mouseMoved:(NSEvent *)o_event
 {
     if (!self.videoViewController.view.hidden) {


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.h
=====================================
@@ -27,7 +27,6 @@
 
 @class VLCLibraryAudioDataSource;
 @class VLCLibraryAudioGroupDataSource;
- at class VLCLoadingOverlayView;
 @class VLCLibraryWindow;
 
 @protocol VLCMediaLibraryItemProtocol;
@@ -52,8 +51,6 @@ NS_ASSUME_NONNULL_BEGIN
 @property (readonly, weak) NSScrollView *audioLibraryGridModeSplitViewListSelectionCollectionViewScrollView;
 @property (readonly, weak) NSCollectionView *audioLibraryGridModeSplitViewListSelectionCollectionView;
 
- at property (readonly) VLCLoadingOverlayView *loadingOverlayView;
-
 @property (readonly) VLCLibraryAudioDataSource *audioDataSource;
 @property (readonly) VLCLibraryAudioGroupDataSource *audioGroupDataSource;
 


=====================================
modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.m
=====================================
@@ -51,9 +51,6 @@
 
 #import "main/VLCMain.h"
 
-#import "views/VLCLoadingOverlayView.h"
-#import "views/VLCNoResultsLabel.h"
-
 #import "windows/video/VLCVoutView.h"
 #import "windows/video/VLCMainVideoViewController.h"
 
@@ -71,10 +68,6 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
     VLCLibraryAudioTableViewDelegate *_audioLibraryTableViewDelegate;
     VLCLibraryAudioGroupTableViewDelegate *_audioGroupLibraryTableViewDelegate;
     VLCLibraryTwoPaneSplitViewDelegate *_splitViewDelegate;
-
-    NSArray<NSLayoutConstraint *> *_loadingOverlayViewConstraints;
-
-    VLCNoResultsLabel *_noResultsLabel;
 }
 @end
 
@@ -96,7 +89,6 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
         _splitViewDelegate = [[VLCLibraryTwoPaneSplitViewDelegate alloc] init];
 
         [self setupAudioPlaceholderView];
-        [self setupLoadingOverlayView];
         [self setupAudioCollectionView];
         [self setupGridModeSplitView];
         [self setupAudioTableViews];
@@ -261,42 +253,6 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
     ];
 }
 
-- (void)setupLoadingOverlayView
-{
-    _loadingOverlayView = [[VLCLoadingOverlayView alloc] init];
-    self.loadingOverlayView.translatesAutoresizingMaskIntoConstraints = NO;
-    _loadingOverlayViewConstraints = @[
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeTop
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeTop
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeRight
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeRight
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeBottom
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeBottom
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeLeft
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeLeft
-                                    multiplier:1
-                                      constant:0]
-    ];
-}
-
 - (void)setupAudioLibraryViews
 {
     _audioCollectionSelectionTableView.rowHeight = VLCLibraryUIUnits.mediumTableViewRowHeight;
@@ -341,78 +297,18 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
 
 - (void)presentAudioView
 {
-    self.libraryTargetView.subviews = @[];
     [self updatePresentedView];
 }
 
 - (void)presentPlaceholderAudioView
 {
-    NSArray<NSLayoutConstraint *> * const oldViewPlaceholderConstraints =
-        self.libraryWindow.librarySegmentViewController.placeholderImageViewSizeConstraints;
-    for (NSLayoutConstraint * const constraint in oldViewPlaceholderConstraints) {
-        constraint.active = NO;
-    }
-    for (NSLayoutConstraint * const constraint in self.placeholderImageViewSizeConstraints) {
-        constraint.active = YES;
-    }
-
     const NSInteger selectedLibrarySegment = self.audioDataSource.audioLibrarySegment;
     NSAssert(selectedLibrarySegment != VLCAudioLibraryRecentsSegment &&
              selectedLibrarySegment != VLCAudioLibraryUnknownSegment,
              @"Received invalid audio library segment from audio data source!");
-
-    if(selectedLibrarySegment < _placeholderImageNames.count && selectedLibrarySegment >= 0) {
-        self.placeholderImageView.image = [NSImage imageNamed:_placeholderImageNames[selectedLibrarySegment]];
-    }
-
-    if(selectedLibrarySegment < _placeholderLabelStrings.count && selectedLibrarySegment >= 0) {
-        self.placeholderLabel.stringValue = _placeholderLabelStrings[selectedLibrarySegment];
-    }
-
-    self.emptyLibraryView.translatesAutoresizingMaskIntoConstraints = NO;
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        self.libraryTargetView.subviews = @[self.emptyLibraryView, self.loadingOverlayView];
-    } else {
-        self.libraryTargetView.subviews = @[self.emptyLibraryView];
-    }
-    NSView * const emptyLibraryView = self.emptyLibraryView;
-    NSDictionary * const dict = NSDictionaryOfVariableBindings(emptyLibraryView);
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[emptyLibraryView(>=572.)]|" options:0 metrics:0 views:dict]];
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[emptyLibraryView(>=444.)]|" options:0 metrics:0 views:dict]];
-
-    self.emptyLibraryView.identifier = VLCLibraryPlaceholderAudioViewIdentifier;
-}
-
-- (void)presentNoResultsView
-{
-    if (_noResultsLabel == nil) {
-        _noResultsLabel = [[VLCNoResultsLabel alloc] init];
-        _noResultsLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    }
-
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        self.libraryTargetView.subviews = @[_noResultsLabel, self.loadingOverlayView];
-    } else {
-        self.libraryTargetView.subviews = @[_noResultsLabel];
-    }
-
-    [NSLayoutConstraint activateConstraints:@[
-        [_noResultsLabel.centerXAnchor constraintEqualToAnchor:self.libraryTargetView.centerXAnchor],
-        [_noResultsLabel.centerYAnchor constraintEqualToAnchor:self.libraryTargetView.centerYAnchor]
-    ]];
-}
-
-- (void)prepareAudioLibraryView
-{
-    self.audioLibraryView.translatesAutoresizingMaskIntoConstraints = NO;
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        self.libraryTargetView.subviews = @[self.audioLibraryView, self.loadingOverlayView];
-    } else {
-        self.libraryTargetView.subviews = @[self.audioLibraryView];
-    }
-    NSDictionary *dict = NSDictionaryOfVariableBindings(_audioLibraryView);
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_audioLibraryView(>=572.)]|" options:0 metrics:0 views:dict]];
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_audioLibraryView(>=444.)]|" options:0 metrics:0 views:dict]];
+    [self.libraryWindow displayLibraryPlaceholderViewWithImage:[NSImage imageNamed:_placeholderImageNames[selectedLibrarySegment]]
+                                              usingConstraints:self.placeholderImageViewSizeConstraints
+                                             displayingMessage:_placeholderLabelStrings[selectedLibrarySegment]];
 }
 
 - (void)hideAllViews
@@ -489,7 +385,7 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
     const BOOL anyAudioMedia = self.audioDataSource.libraryModel.numberOfAudioMedia > 0;
 
     if (anyAudioMedia) {
-        [self prepareAudioLibraryView];
+        [self.libraryWindow displayLibraryView:self.audioLibraryView];
         [self hideAllViews];
 
         const VLCLibraryViewModeSegment viewModeSegment = [self viewModeSegmentForCurrentLibrarySegment];
@@ -504,7 +400,7 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
 
         [VLCMain.sharedInstance.libraryWindow updateGridVsListViewModeSegmentedControl];
     } else if (self.audioDataSource.libraryModel.filterString.length > 0) {
-        [self presentNoResultsView];
+        [self.libraryWindow displayNoResultsMessage];
     } else {
         [self presentPlaceholderAudioView];
     }
@@ -638,53 +534,22 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi
 
 - (void)libraryModelLongLoadStarted:(NSNotification *)notification
 {
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        return;
-    }
-
     if (self.connected) {
         [self.audioDataSource disconnect];
         [self.audioGroupDataSource disconnect];
     }
 
-    self.loadingOverlayView.wantsLayer = YES;
-    self.loadingOverlayView.alphaValue = 0.0;
-
-    NSArray * const views = [self.libraryTargetView.subviews arrayByAddingObject:self.loadingOverlayView];
-    self.libraryTargetView.subviews = views;
-    [self.libraryTargetView addConstraints:_loadingOverlayViewConstraints];
-
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
-        context.duration = 0.5;
-        self.loadingOverlayView.animator.alphaValue = 1.0;
-    } completionHandler:nil];
-    [self.loadingOverlayView.indicator startAnimation:self];
+    [self.libraryWindow showLoadingOverlay];
 }
 
 - (void)libraryModelLongLoadFinished:(NSNotification *)notification
 {
-    if (![self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        return;
-    }
-
     if (self.connected) {
         [self.audioDataSource connect];
         [self.audioGroupDataSource connect];
     }
 
-    self.loadingOverlayView.wantsLayer = YES;
-    self.loadingOverlayView.alphaValue = 1.0;
-
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
-        context.duration = 1.0;
-        self.loadingOverlayView.animator.alphaValue = 0.0;
-    } completionHandler:^{
-        [self.libraryTargetView removeConstraints:_loadingOverlayViewConstraints];
-        NSMutableArray * const views = self.libraryTargetView.subviews.mutableCopy;
-        [views removeObject:self.loadingOverlayView];
-        self.libraryTargetView.subviews = views.copy;
-        [self.loadingOverlayView.indicator stopAnimation:self];
-    }];
+    [self.libraryWindow hideLoadingOverlay];
 }
 
 @end


=====================================
modules/gui/macosx/library/groups-library/VLCLibraryGroupsViewController.m
=====================================
@@ -230,51 +230,27 @@
 
 - (void)presentPlaceholderGroupsView
 {
-    NSArray<NSLayoutConstraint *> * const oldViewPlaceholderConstraints =
-        self.libraryWindow.librarySegmentViewController.placeholderImageViewSizeConstraints;
-    for (NSLayoutConstraint * const constraint in oldViewPlaceholderConstraints) {
-        constraint.active = NO;
-    }
-    for (NSLayoutConstraint *constraint in self.placeholderImageViewSizeConstraints) {
-        constraint.active = YES;
-    }
-
-    self.emptyLibraryView.translatesAutoresizingMaskIntoConstraints = NO;
-    self.libraryTargetView.subviews = @[self.emptyLibraryView];
-    NSView * const emptyLibraryView = self.emptyLibraryView;
-    NSDictionary * const dict = NSDictionaryOfVariableBindings(emptyLibraryView);
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[emptyLibraryView(>=572.)]|" options:0 metrics:0 views:dict]];
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[emptyLibraryView(>=444.)]|" options:0 metrics:0 views:dict]];
-
-    self.placeholderImageView.image = [NSImage imageNamed:@"placeholder-video"];
-    self.placeholderLabel.stringValue = _NS("Your favorite groups will appear here.");
+    [self.libraryWindow displayLibraryPlaceholderViewWithImage:[NSImage imageNamed:@"placeholder-video"]
+                                              usingConstraints:self.placeholderImageViewSizeConstraints
+                                             displayingMessage:_NS("Your favorite groups will appear here.")];
 }
 
 - (void)presentGroupsView
 {
-    if (self.dataSource.libraryModel.numberOfGroups == 0) {
-        [self presentPlaceholderGroupsView];
-        return;
-    }
-
     const VLCLibraryViewModeSegment viewModeSegment =
         VLCLibraryWindowPersistentPreferences.sharedInstance.groupsLibraryViewMode;
-    NSView *viewToPresent = nil;
 
-    if (viewModeSegment == VLCLibraryGridViewModeSegment) {
-        viewToPresent = self.collectionViewScrollView;
+    if (self.dataSource.libraryModel.numberOfGroups > 0) {
+        if (viewModeSegment == VLCLibraryGridViewModeSegment) {
+            [self.libraryWindow displayLibraryView:self.collectionViewScrollView];
+        } else {
+            [self.libraryWindow displayLibraryView:self.listViewSplitView];
+        }
+    } else if (self.dataSource.libraryModel.filterString.length > 0) {
+        [self.libraryWindow displayNoResultsMessage];
     } else {
-        viewToPresent = self.listViewSplitView;
+        [self presentPlaceholderGroupsView];
     }
-    NSParameterAssert(viewToPresent != nil);
-
-    self.libraryTargetView.subviews = @[viewToPresent];
-    [NSLayoutConstraint activateConstraints:@[
-        [self.libraryTargetView.topAnchor constraintEqualToAnchor:viewToPresent.topAnchor],
-        [self.libraryTargetView.bottomAnchor constraintEqualToAnchor:viewToPresent.bottomAnchor],
-        [self.libraryTargetView.leadingAnchor constraintEqualToAnchor:viewToPresent.leadingAnchor],
-        [self.libraryTargetView.trailingAnchor constraintEqualToAnchor:viewToPresent.trailingAnchor]
-    ]];
 }
 
 - (void)presentGroup:(VLCMediaLibraryGroup *)group


=====================================
modules/gui/macosx/library/home-library/VLCLibraryHomeViewController.h
=====================================
@@ -24,7 +24,6 @@
 
 #import "library/VLCLibraryAbstractSegmentViewController.h"
 
- at class VLCLoadingOverlayView;
 @class VLCLibraryWindow;
 @class VLCLibraryHomeViewStackViewController;
 
@@ -40,7 +39,6 @@ NS_ASSUME_NONNULL_BEGIN
 @property (readonly, weak) NSScrollView *homeLibraryStackViewScrollView;
 @property (readonly, weak) NSStackView *homeLibraryStackView;
 
- at property (readonly) VLCLoadingOverlayView *loadingOverlayView;
 @property (readonly) VLCLibraryHomeViewStackViewController *stackViewController;
 
 - (instancetype)initWithLibraryWindow:(VLCLibraryWindow *)libraryWindow;


=====================================
modules/gui/macosx/library/home-library/VLCLibraryHomeViewController.m
=====================================
@@ -43,15 +43,12 @@
 
 #import "main/VLCMain.h"
 
-#import "views/VLCLoadingOverlayView.h"
-
 #import "windows/video/VLCMainVideoViewController.h"
 
 @interface VLCLibraryHomeViewController ()
 {
     id<VLCMediaLibraryItemProtocol> _awaitingPresentingLibraryItem;
     NSMutableSet<NSString *> *_ongoingLongLoadingNotifications;
-    NSArray<NSLayoutConstraint *> *_loadingOverlayViewConstraints;
     NSArray<NSLayoutConstraint *> *_internalPlaceholderImageViewSizeConstraints;
 }
 @end
@@ -64,7 +61,6 @@
 
     if(self) {
         [self setupPropertiesFromLibraryWindow:libraryWindow];
-        [self setupLoadingOverlayView];
         [self setupGridViewController];
         [self setupHomePlaceholderView];
         [self setupHomeLibraryViews];
@@ -110,42 +106,6 @@
     _homeLibraryStackView = libraryWindow.homeLibraryStackView;
 }
 
-- (void)setupLoadingOverlayView
-{
-    _loadingOverlayView = [[VLCLoadingOverlayView alloc] init];
-    self.loadingOverlayView.translatesAutoresizingMaskIntoConstraints = NO;
-    _loadingOverlayViewConstraints = @[
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeTop
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeTop
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeRight
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeRight
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeBottom
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeBottom
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeLeft
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeLeft
-                                    multiplier:1
-                                      constant:0]
-    ];
-}
-
 - (void)setupGridViewController
 {
     _stackViewController = [[VLCLibraryHomeViewStackViewController alloc] init];
@@ -201,51 +161,19 @@
 
 - (void)presentHomeView
 {
-    self.libraryTargetView.subviews = @[];
     [self updatePresentedView];
 }
 
 - (void)presentPlaceholderHomeLibraryView
 {
-    NSArray<NSLayoutConstraint *> * const oldViewPlaceholderConstraints =
-        self.libraryWindow.librarySegmentViewController.placeholderImageViewSizeConstraints;
-    for (NSLayoutConstraint * const constraint in oldViewPlaceholderConstraints) {
-        constraint.active = NO;
-    }
-    for (NSLayoutConstraint *constraint in self.placeholderImageViewSizeConstraints) {
-        constraint.active = YES;
-    }
-
-    self.emptyLibraryView.translatesAutoresizingMaskIntoConstraints = NO;
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        self.libraryTargetView.subviews = @[self.emptyLibraryView, self.loadingOverlayView];
-    } else {
-        self.libraryTargetView.subviews = @[self.emptyLibraryView];
-    }
-    NSView * const emptyLibraryView = self.emptyLibraryView;
-    NSDictionary * const dict = NSDictionaryOfVariableBindings(emptyLibraryView);
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[emptyLibraryView(>=572.)]|" options:0 metrics:0 views:dict]];
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[emptyLibraryView(>=444.)]|" options:0 metrics:0 views:dict]];
-
-    self.placeholderImageView.image = [NSImage imageNamed:@"placeholder-video"];
-    self.placeholderLabel.stringValue = _NS("Your favorite videos will appear here.\nGo to the Browse section to add videos you love.");
+    [self.libraryWindow displayLibraryPlaceholderViewWithImage:[NSImage imageNamed:@"placeholder-video"]
+                                              usingConstraints:self.placeholderImageViewSizeConstraints
+                                             displayingMessage:_NS("Your favorite videos will appear here.\nGo to the Browse section to add videos you love.")];
 }
 
 - (void)presentHomeLibraryView
 {
-    self.homeLibraryView.translatesAutoresizingMaskIntoConstraints = NO;
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        self.libraryTargetView.subviews = @[self.homeLibraryView, self.loadingOverlayView];
-    } else {
-        self.libraryTargetView.subviews = @[self.homeLibraryView];
-    }
-
-    NSDictionary * const dict = NSDictionaryOfVariableBindings(_homeLibraryView);
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_homeLibraryView(>=572.)]|" options:0 metrics:0 views:dict]];
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_homeLibraryView(>=444.)]|" options:0 metrics:0 views:dict]];
-
-    const VLCLibraryViewModeSegment viewModeSegment = VLCLibraryWindowPersistentPreferences.sharedInstance.homeLibraryViewMode;
-
+    [self.libraryWindow displayLibraryView:self.homeLibraryView];
     self.homeLibraryStackViewScrollView.hidden = NO;
     [self.stackViewController reloadData];
 }
@@ -278,27 +206,10 @@
     }
 
     [_ongoingLongLoadingNotifications addObject:notification.name];
-
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        return;
-    }
-
     if (self.connected) {
         [self.stackViewController disconnectContainers];
     }
-
-    self.loadingOverlayView.wantsLayer = YES;
-    self.loadingOverlayView.alphaValue = 0.0;
-
-    NSArray * const views = [self.libraryTargetView.subviews arrayByAddingObject:self.loadingOverlayView];
-    self.libraryTargetView.subviews = views;
-    [self.libraryTargetView addConstraints:_loadingOverlayViewConstraints];
-
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
-        context.duration = 0.5;
-        self.loadingOverlayView.animator.alphaValue = 1.0;
-    } completionHandler:nil];
-    [self.loadingOverlayView.indicator startAnimation:self];
+    [self.libraryWindow showLoadingOverlay];
 }
 
 - (void)libraryModelLongLoadFinished:(NSNotification *)notification
@@ -307,28 +218,10 @@
     if (_ongoingLongLoadingNotifications.count > 0) {
         return;
     }
-
-    if (![self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        return;
-    }
-
     if (self.connected) {
         [self.stackViewController connectContainers];
     }
-
-    self.loadingOverlayView.wantsLayer = YES;
-    self.loadingOverlayView.alphaValue = 1.0;
-
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
-        context.duration = 1.0;
-        self.loadingOverlayView.animator.alphaValue = 0.0;
-    } completionHandler:^{
-        [self.libraryTargetView removeConstraints:_loadingOverlayViewConstraints];
-        NSMutableArray * const views = self.libraryTargetView.subviews.mutableCopy;
-        [views removeObject:self.loadingOverlayView];
-        self.libraryTargetView.subviews = views.copy;
-        [self.loadingOverlayView.indicator stopAnimation:self];
-    }];
+    [self.libraryWindow hideLoadingOverlay];
 }
 
 - (void)connect


=====================================
modules/gui/macosx/library/media-source/VLCLibraryMediaSourceViewController.m
=====================================
@@ -168,16 +168,7 @@
 
 - (void)presentMediaSourceView:(VLCLibrarySegmentType)viewSegment
 {
-    self.libraryTargetView.subviews = @[];
-
-    if (_mediaSourceView.superview == nil) {
-        _mediaSourceView.translatesAutoresizingMaskIntoConstraints = NO;
-        self.libraryTargetView.subviews = @[_mediaSourceView];
-        NSDictionary *dict = NSDictionaryOfVariableBindings(_mediaSourceView);
-        [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_mediaSourceView(>=572.)]|" options:0 metrics:0 views:dict]];
-        [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_mediaSourceView(>=444.)]|" options:0 metrics:0 views:dict]];
-    }
-
+    [self.libraryWindow displayLibraryView:self.mediaSourceView];
     _baseDataSource.mediaSourceMode = viewSegment == VLCLibraryBrowseSegment ? VLCMediaSourceModeLAN : VLCMediaSourceModeInternet;
     [_baseDataSource reloadViews];
 }


=====================================
modules/gui/macosx/library/playlist-library/VLCLibraryPlaylistViewController.h
=====================================
@@ -29,7 +29,6 @@
 NS_ASSUME_NONNULL_BEGIN
 
 @class VLCLibraryCollectionViewDelegate;
- at class VLCLoadingOverlayView;
 @class VLCLibraryMasterDetailViewTableViewDelegate;
 @class VLCLibraryPlaylistDataSource;
 @class VLCLibraryTableView;
@@ -44,8 +43,6 @@ NS_ASSUME_NONNULL_BEGIN
 @property (readonly) VLCLibraryTableView *detailTableView;
 @property (readonly) NSScrollView *collectionViewScrollView;
 @property (readonly) NSCollectionView *collectionView;
- at property (readonly) VLCLoadingOverlayView *loadingOverlayView;
- at property (readonly) NSArray<NSLayoutConstraint *> *loadingOverlayViewConstraints;
 
 @property (readonly) VLCLibraryPlaylistDataSource *dataSource;
 @property (readonly) VLCLibraryCollectionViewDelegate *collectionViewDelegate;


=====================================
modules/gui/macosx/library/playlist-library/VLCLibraryPlaylistViewController.m
=====================================
@@ -43,7 +43,6 @@
 
 #import "main/VLCMain.h"
 
-#import "views/VLCLoadingOverlayView.h"
 
 #import "windows/video/VLCMainVideoViewController.h"
 
@@ -214,42 +213,6 @@
     ];
 }
 
-- (void)setupLoadingOverlayView
-{
-    _loadingOverlayView = [[VLCLoadingOverlayView alloc] init];
-    self.loadingOverlayView.translatesAutoresizingMaskIntoConstraints = NO;
-    _loadingOverlayViewConstraints = @[
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeTop
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeTop
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeRight
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeRight
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeBottom
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeBottom
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeLeft
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeLeft
-                                    multiplier:1
-                                      constant:0]
-    ];
-}
-
 - (NSArray<NSLayoutConstraint *> *)placeholderImageViewSizeConstraints
 {
     return _internalPlaceholderImageViewSizeConstraints;
@@ -260,26 +223,8 @@
     return self.dataSource;
 }
 
-// TODO: This is duplicated almost verbatim across all the library view
-// controllers. Ideally we should have the placeholder view handle this
-// itself, or move this into a common superclass
 - (void)presentPlaceholderPlaylistLibraryView
 {
-    NSArray<NSLayoutConstraint *> * const oldViewPlaceholderConstraints =
-        self.libraryWindow.librarySegmentViewController.placeholderImageViewSizeConstraints;
-    for (NSLayoutConstraint * const constraint in oldViewPlaceholderConstraints) {
-        constraint.active = NO;
-    }
-    for (NSLayoutConstraint * const constraint in self.placeholderImageViewSizeConstraints) {
-        constraint.active = YES;
-    }
-
-    self.libraryWindow.emptyLibraryView.translatesAutoresizingMaskIntoConstraints = NO;
-    self.libraryWindow.libraryTargetView.subviews = @[self.libraryWindow.emptyLibraryView];
-    NSDictionary * const dict = @{@"emptyLibraryView": self.libraryWindow.emptyLibraryView};
-    [self.libraryWindow.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[emptyLibraryView(>=572.)]|" options:0 metrics:0 views:dict]];
-    [self.libraryWindow.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[emptyLibraryView(>=444.)]|" options:0 metrics:0 views:dict]];
-
     const vlc_ml_playlist_type_t playlistType = self.dataSource.playlistType;
     NSString *placeholderPlaylistsString = nil;
     switch (playlistType) {
@@ -302,8 +247,9 @@
             break;
     }
 
-    self.libraryWindow.placeholderImageView.image = [NSImage imageNamed:@"placeholder-group2"];
-    self.libraryWindow.placeholderLabel.stringValue = placeholderPlaylistsString;
+    [self.libraryWindow displayLibraryPlaceholderViewWithImage:[NSImage imageNamed:@"placeholder-group2"]
+                                              usingConstraints:self.placeholderImageViewSizeConstraints
+                                             displayingMessage:placeholderPlaylistsString];
 }
 
 - (void)presentPlaylistLibraryView
@@ -318,30 +264,24 @@
         viewToPresent = self.listViewSplitView;
     }
     NSParameterAssert(viewToPresent != nil);
-
-    self.libraryTargetView.subviews = @[viewToPresent];
-    [NSLayoutConstraint activateConstraints:@[
-        [self.libraryTargetView.topAnchor constraintEqualToAnchor:viewToPresent.topAnchor],
-        [self.libraryTargetView.bottomAnchor constraintEqualToAnchor:viewToPresent.bottomAnchor],
-        [self.libraryTargetView.leadingAnchor constraintEqualToAnchor:viewToPresent.leadingAnchor],
-        [self.libraryTargetView.trailingAnchor constraintEqualToAnchor:viewToPresent.trailingAnchor]
-    ]];
+    [self.libraryWindow displayLibraryView:viewToPresent];
 }
 
 - (void)updatePresentedView
 {
     const vlc_ml_playlist_type_t playlistType = self.dataSource.playlistType;
     VLCLibraryModel * const libraryModel = VLCMain.sharedInstance.libraryController.libraryModel;
-    if ([libraryModel numberOfPlaylistsOfType:playlistType] <= 0) {
-        [self presentPlaceholderPlaylistLibraryView];
-    } else {
+    if ([libraryModel numberOfPlaylistsOfType:playlistType] > 0) {
         [self presentPlaylistLibraryView];
+    } else if (self.dataSource.libraryModel.filterString.length > 0) {
+        [self.libraryWindow displayNoResultsMessage];
+    } else {
+        [self presentPlaceholderPlaylistLibraryView];
     }
 }
 
 - (void)presentPlaylistsView
 {
-    self.libraryWindow.libraryTargetView.subviews = @[];
     [self updatePresentedView];
 }
 
@@ -368,54 +308,20 @@
     }
 }
 
-// TODO: Duplicated a lot, move to abstract view controller?
 - (void)libraryModelLongLoadStarted:(NSNotification *)notification
 {
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        return;
-    }
-
     if (self.connected) {
         [self.dataSource disconnect];
     }
-
-    self.loadingOverlayView.wantsLayer = YES;
-    self.loadingOverlayView.alphaValue = 0.0;
-
-    NSArray * const views = [self.libraryTargetView.subviews arrayByAddingObject:self.loadingOverlayView];
-    self.libraryTargetView.subviews = views;
-    [self.libraryTargetView addConstraints:_loadingOverlayViewConstraints];
-
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
-        context.duration = 0.5;
-        self.loadingOverlayView.animator.alphaValue = 1.0;
-    } completionHandler:nil];
-    [self.loadingOverlayView.indicator startAnimation:self];
+    [self.libraryWindow showLoadingOverlay];
 }
 
 - (void)libraryModelLongLoadFinished:(NSNotification *)notification
 {
-    if (![self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        return;
-    }
-
     if (self.connected) {
         [self.dataSource connect];
     }
-
-    self.loadingOverlayView.wantsLayer = YES;
-    self.loadingOverlayView.alphaValue = 1.0;
-
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
-        context.duration = 1.0;
-        self.loadingOverlayView.animator.alphaValue = 0.0;
-    } completionHandler:^{
-        [self.libraryTargetView removeConstraints:_loadingOverlayViewConstraints];
-        NSMutableArray * const views = self.libraryTargetView.subviews.mutableCopy;
-        [views removeObject:self.loadingOverlayView];
-        self.libraryTargetView.subviews = views.copy;
-        [self.loadingOverlayView.indicator stopAnimation:self];
-    }];
+    [self.libraryWindow hideLoadingOverlay];
 }
 
 #pragma mark - NSSplitViewDelegate


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoViewController.h
=====================================
@@ -24,7 +24,6 @@
 
 #import "library/VLCLibraryAbstractSegmentViewController.h"
 
- at class VLCLoadingOverlayView;
 @class VLCLibraryWindow;
 @class VLCLibraryVideoDataSource;
 @class VLCLibraryShowsDataSource;
@@ -46,8 +45,6 @@ NS_ASSUME_NONNULL_BEGIN
 @property (readonly, weak) NSScrollView *videoLibraryGroupsTableViewScrollView;
 @property (readonly, weak) NSTableView *videoLibraryGroupsTableView;
 
- at property (readonly) VLCLoadingOverlayView *loadingOverlayView;
-
 @property (readonly, nullable) VLCLibraryVideoDataSource *libraryVideoDataSource;
 @property (readonly, nullable) VLCLibraryShowsDataSource *libraryShowsDataSource;
 


=====================================
modules/gui/macosx/library/video-library/VLCLibraryVideoViewController.m
=====================================
@@ -50,9 +50,6 @@
 
 #import "main/VLCMain.h"
 
-#import "views/VLCLoadingOverlayView.h"
-#import "views/VLCNoResultsLabel.h"
-
 #import "windows/video/VLCVoutView.h"
 #import "windows/video/VLCMainVideoViewController.h"
 
@@ -66,9 +63,6 @@
     id<VLCMediaLibraryItemProtocol> _awaitingPresentingLibraryItem;
 
     NSArray<NSLayoutConstraint *> *_internalPlaceholderImageViewSizeConstraints;
-    NSArray<NSLayoutConstraint *> *_loadingOverlayViewConstraints;
-
-    VLCNoResultsLabel *_noResultsLabel;
 }
 @end
 
@@ -87,7 +81,6 @@
         [self setupCollectionView];
         [self setupVideoPlaceholderView];
         [self setupVideoLibraryViews];
-        [self setupLoadingOverlayView];
 
         NSNotificationCenter *notificationCenter = NSNotificationCenter.defaultCenter;
         [notificationCenter addObserver:self
@@ -248,42 +241,6 @@
     _videoLibraryGroupSelectionTableViewScrollView.scrollerInsets = scrollerInsets;
 }
 
-- (void)setupLoadingOverlayView
-{
-    _loadingOverlayView = [[VLCLoadingOverlayView alloc] init];
-    self.loadingOverlayView.translatesAutoresizingMaskIntoConstraints = NO;
-    _loadingOverlayViewConstraints = @[
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeTop
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeTop
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeRight
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeRight
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeBottom
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeBottom
-                                    multiplier:1
-                                      constant:0],
-        [NSLayoutConstraint constraintWithItem:self.loadingOverlayView
-                                     attribute:NSLayoutAttributeLeft
-                                     relatedBy:NSLayoutRelationEqual
-                                        toItem:self.libraryTargetView
-                                     attribute:NSLayoutAttributeLeft
-                                    multiplier:1
-                                      constant:0]
-    ];
-}
-
 #pragma mark - Show the video library view
 
 - (NSArray<NSLayoutConstraint *> *)placeholderImageViewSizeConstraints
@@ -324,7 +281,7 @@
         const VLCLibraryViewModeSegment viewModeSegment = VLCLibraryWindowPersistentPreferences.sharedInstance.videoLibraryViewMode;
         [self presentVideoLibraryView:viewModeSegment];
     } else if (self.libraryVideoDataSource.libraryModel.filterString.length > 0) {
-        [self presentNoResultsView];
+        [self.libraryWindow displayNoResultsMessage];
     } else {
         [self presentPlaceholderVideoLibraryView];
     }
@@ -351,7 +308,7 @@
         const VLCLibraryViewModeSegment viewModeSegment = VLCLibraryWindowPersistentPreferences.sharedInstance.showsLibraryViewMode;
         [self presentVideoLibraryView:viewModeSegment];
     } else if (self.libraryShowsDataSource.libraryModel.filterString.length > 0) {
-        [self presentNoResultsView];
+        [self.libraryWindow displayNoResultsMessage];
     } else {
         [self presentPlaceholderVideoLibraryView];
     }
@@ -359,80 +316,30 @@
 
 - (void)presentVideoView
 {
-    self.libraryTargetView.subviews = @[];
     [self updatePresentedVideoLibraryView];
 }
 
 - (void)presentShowsView
 {
-    self.libraryTargetView.subviews = @[];
     [self updatePresentedShowsLibraryView];
 }
 
 - (void)presentPlaceholderVideoLibraryView
 {
-    NSArray<NSLayoutConstraint *> * const oldViewPlaceholderConstraints =
-        self.libraryWindow.librarySegmentViewController.placeholderImageViewSizeConstraints;
-    for (NSLayoutConstraint * const constraint in oldViewPlaceholderConstraints) {
-        constraint.active = NO;
-    }
-    for (NSLayoutConstraint * const constraint in self.placeholderImageViewSizeConstraints) {
-        constraint.active = YES;
-    }
-
-    self.emptyLibraryView.translatesAutoresizingMaskIntoConstraints = NO;
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        self.libraryTargetView.subviews = @[self.emptyLibraryView, self.loadingOverlayView];
-    } else {
-        self.libraryTargetView.subviews = @[self.emptyLibraryView];
-    }
-    NSView * const emptyLibraryView = self.emptyLibraryView;
-    NSDictionary *dict = NSDictionaryOfVariableBindings(emptyLibraryView);
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[emptyLibraryView(>=572.)]|" options:0 metrics:0 views:dict]];
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[emptyLibraryView(>=444.)]|" options:0 metrics:0 views:dict]];
-
-    self.placeholderImageView.image = [NSImage imageNamed:@"placeholder-video"];
-    self.placeholderLabel.stringValue = _NS("Your favorite videos will appear here.\nGo to the Browse section to add videos you love.");
-}
-
-- (void)presentNoResultsView
-{
-    if (_noResultsLabel == nil) {
-        _noResultsLabel = [[VLCNoResultsLabel alloc] init];
-        _noResultsLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    }
-
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        self.libraryTargetView.subviews = @[_noResultsLabel, self.loadingOverlayView];
-    } else {
-        self.libraryTargetView.subviews = @[_noResultsLabel];
-    }
-
-    [NSLayoutConstraint activateConstraints:@[
-        [_noResultsLabel.centerXAnchor constraintEqualToAnchor:self.libraryTargetView.centerXAnchor],
-        [_noResultsLabel.centerYAnchor constraintEqualToAnchor:self.libraryTargetView.centerYAnchor]
-    ]];
+    [self.libraryWindow displayLibraryPlaceholderViewWithImage:[NSImage imageNamed:@"placeholder-video"]
+                                              usingConstraints:self.placeholderImageViewSizeConstraints
+                                             displayingMessage:_NS("Your favorite videos will appear here.\nGo to the Browse section to add videos you love.")];
 }
 
 - (void)presentVideoLibraryView:(VLCLibraryViewModeSegment)viewModeSegment
 {
-    _videoLibraryView.translatesAutoresizingMaskIntoConstraints = NO;
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        self.libraryTargetView.subviews = @[self.videoLibraryView, self.loadingOverlayView];
-    } else {
-        self.libraryTargetView.subviews = @[self.videoLibraryView];
-    }
-
-    NSDictionary *dict = NSDictionaryOfVariableBindings(_videoLibraryView);
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_videoLibraryView(>=572.)]|" options:0 metrics:0 views:dict]];
-    [self.libraryTargetView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_videoLibraryView(>=444.)]|" options:0 metrics:0 views:dict]];
-
+    [self.libraryWindow displayLibraryView:self.videoLibraryView];
     if (viewModeSegment == VLCLibraryGridViewModeSegment) {
-        _videoLibrarySplitView.hidden = YES;
-        _videoLibraryCollectionViewScrollView.hidden = NO;
+        self.videoLibrarySplitView.hidden = YES;
+        self.videoLibraryCollectionViewScrollView.hidden = NO;
     } else if (viewModeSegment == VLCLibraryListViewModeSegment) {
-        _videoLibrarySplitView.hidden = NO;
-        _videoLibraryCollectionViewScrollView.hidden = YES;
+        self.videoLibrarySplitView.hidden = NO;
+        self.videoLibraryCollectionViewScrollView.hidden = YES;
     } else {
         NSAssert(false, @"View mode must be grid or list mode");
     }
@@ -515,51 +422,18 @@
 
 - (void)libraryModelLongLoadStarted:(NSNotification *)notification
 {
-    if ([self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        return;
-    }
-
     if (self.connected) {
         [self.libraryVideoDataSource disconnect];
     }
-
-    self.loadingOverlayView.wantsLayer = YES;
-    self.loadingOverlayView.alphaValue = 0.0;
-
-    NSArray * const views = [self.libraryTargetView.subviews arrayByAddingObject:self.loadingOverlayView];
-    self.libraryTargetView.subviews = views;
-    [self.libraryTargetView addConstraints:_loadingOverlayViewConstraints];
-
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
-        context.duration = 0.5;
-        self.loadingOverlayView.animator.alphaValue = 1.0;
-    } completionHandler:nil];
-    [self.loadingOverlayView.indicator startAnimation:self];
+    [self.libraryWindow showLoadingOverlay];
 }
 
 - (void)libraryModelLongLoadFinished:(NSNotification *)notification
 {
-    if (![self.libraryTargetView.subviews containsObject:self.loadingOverlayView]) {
-        return;
-    }
-
     if (self.connected) {
         [self.libraryVideoDataSource connect];
     }
-
-    self.loadingOverlayView.wantsLayer = YES;
-    self.loadingOverlayView.alphaValue = 1.0;
-
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * const context) {
-        context.duration = 1.0;
-        self.loadingOverlayView.animator.alphaValue = 0.0;
-    } completionHandler:^{
-        [self.libraryTargetView removeConstraints:_loadingOverlayViewConstraints];
-        NSMutableArray * const views = self.libraryTargetView.subviews.mutableCopy;
-        [views removeObject:self.loadingOverlayView];
-        self.libraryTargetView.subviews = views.copy;
-        [self.loadingOverlayView.indicator stopAnimation:self];
-    }];
+    [self.libraryWindow hideLoadingOverlay];
 }
 
 @end



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/72b71432d2dd006491334be33fac72606995656e...07dab83c1dbe158d182dd9a6ca7de4b42ef741b6

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/72b71432d2dd006491334be33fac72606995656e...07dab83c1dbe158d182dd9a6ca7de4b42ef741b6
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