[vlc-commits] [Git][videolan/vlc][master] 2 commits: macosx: Implement basic completions for search

Steve Lhomme (@robUx4) gitlab at videolan.org
Mon Oct 20 06:08:50 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
ff98bcfd by Claudio Cambra at 2025-10-20T05:50:30+00:00
macosx: Implement basic completions for search

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

- - - - -
627296a3 by Claudio Cambra at 2025-10-20T05:50:30+00:00
macox: Cache and store list of media item titles in VLCLibraryModel

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

- - - - -


4 changed files:

- modules/gui/macosx/library/VLCLibraryModel.h
- modules/gui/macosx/library/VLCLibraryModel.m
- modules/gui/macosx/library/VLCLibraryWindow.h
- modules/gui/macosx/library/VLCLibraryWindow.m


Changes:

=====================================
modules/gui/macosx/library/VLCLibraryModel.h
=====================================
@@ -147,6 +147,8 @@ extern NSString * const VLCLibraryModelDiscoveryFailed;
 @property (readonly) size_t numberOfFavoriteGenres;
 @property (readonly) NSArray <VLCMediaLibraryGenre *> *listOfFavoriteGenres;
 
+ at property (readonly) NSArray <NSString *> *listOfMediaTitles;
+
 @end
 
 NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/VLCLibraryModel.m
=====================================
@@ -21,6 +21,7 @@
  *****************************************************************************/
 
 #import "VLCLibraryModel.h"
+#include <sys/qos.h>
 
 #import "VLCMediaLibraryFolderObserver.h"
 
@@ -103,6 +104,7 @@ NSString * const VLCLibraryModelDiscoveryFailed = @"VLCLibraryModelDiscoveryFail
     dispatch_queue_t _artistCacheModificationQueue;
     dispatch_queue_t _genreCacheModificationQueue;
     dispatch_queue_t _groupCacheModificationQueue;
+    dispatch_queue_t _mediaTitlesCacheModificationQueue;
 }
 
 @property (readwrite) NSArray<VLCMediaLibraryFolderObserver *> *folderObservers;
@@ -118,6 +120,7 @@ NSString * const VLCLibraryModelDiscoveryFailed = @"VLCLibraryModelDiscoveryFail
 @property (readwrite, nonatomic) NSArray *cachedRecentMedia;
 @property (readwrite, nonatomic) NSArray *cachedRecentAudioMedia;
 @property (readwrite, nonatomic) NSArray *cachedListOfMonitoredFolders;
+ at property (readwrite, nonatomic) NSArray *cachedMediaTitles;
 
 - (void)resetCachedListOfRecentMedia;
 - (void)resetCachedListOfRecentAudioMedia;
@@ -127,6 +130,7 @@ NSString * const VLCLibraryModelDiscoveryFailed = @"VLCLibraryModelDiscoveryFail
 - (void)resetCachedListOfShows;
 - (void)resetCachedListOfGroups;
 - (void)resetCachedListOfMonitoredFolders;
+- (void)resetCachedListOfMediaTitles;
 - (void)mediaItemThumbnailGenerated:(VLCMediaLibraryMediaItem *)mediaItem;
 - (void)handleMediaItemAddedEvent:(const vlc_ml_event_t * const)p_event;
 - (void)handlePlaylistAddedEvent:(const vlc_ml_event_t * const)p_event;
@@ -309,6 +313,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         _artistCacheModificationQueue = dispatch_queue_create("artistCacheModificationQueue", DISPATCH_QUEUE_CONCURRENT);
         _genreCacheModificationQueue = dispatch_queue_create("genreCacheModificationQueue", DISPATCH_QUEUE_CONCURRENT);
         _groupCacheModificationQueue = dispatch_queue_create("groupCacheModificationQueue", DISPATCH_QUEUE_CONCURRENT);
+        _mediaTitlesCacheModificationQueue = dispatch_queue_create("mediaTitlesCacheModificationQueue", DISPATCH_QUEUE_CONCURRENT);
 
         _defaultNotificationCenter = NSNotificationCenter.defaultCenter;
         [_defaultNotificationCenter addObserver:self
@@ -397,6 +402,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedAudioMedia = mediaArray;
             [self.changeDelegate notifyChange:VLCLibraryModelAudioMediaListReset withObject:self];
+            [self resetCachedListOfMediaTitles];
         });
     });
 }
@@ -575,6 +581,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedVideoMedia = [mutableArray copy];
             [self.changeDelegate notifyChange:VLCLibraryModelVideoMediaListReset withObject:self];
+            [self resetCachedListOfMediaTitles];
         });
     });
 }
@@ -588,6 +595,46 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
     return [self readCachedArray:_cachedVideoMedia fromQueue:_mediaItemCacheModificationQueue];
 }
 
+- (void)resetCachedListOfMediaTitles
+{
+    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
+        NSMutableSet<NSString *> * const titleSet = NSMutableSet.set;
+        
+        NSArray<VLCMediaLibraryMediaItem *> * const videos = self.listOfVideoMedia;
+        for (VLCMediaLibraryMediaItem * const video in videos) {
+            NSString * const title = video.displayString;
+            if (title) {
+                [titleSet addObject:title];
+            }
+        }
+        
+        NSArray<VLCMediaLibraryMediaItem *> * const audioMedia = self.listOfAudioMedia;
+        for (VLCMediaLibraryMediaItem * const audio in audioMedia) {
+            NSString * const title = audio.displayString;
+            if (title) {
+                [titleSet addObject:title];
+            }
+        }
+
+        NSArray<NSString *> * const sortedTitles = [titleSet.allObjects sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
+
+        dispatch_barrier_async(self->_mediaTitlesCacheModificationQueue, ^{
+            dispatch_sync(dispatch_get_main_queue(), ^{
+                self.cachedMediaTitles = sortedTitles;
+            });
+        });
+    });
+}
+
+- (NSArray<NSString *> *)listOfMediaTitles
+{
+    if (!_cachedMediaTitles) {
+        [self resetCachedListOfMediaTitles];
+    }
+    
+    return [self readCachedArray:_cachedMediaTitles fromQueue:_mediaTitlesCacheModificationQueue];
+}
+
 - (void)getListOfRecentMediaOfType:(vlc_ml_media_type_t)type
                     withCountLimit:(size_t)countLimit
                     withCompletion:(void (^)(NSArray *recentMediaArray))completionHandler


=====================================
modules/gui/macosx/library/VLCLibraryWindow.h
=====================================
@@ -52,7 +52,7 @@ typedef NS_ENUM(NSInteger, VLCLibraryViewModeSegment) {
     VLCLibraryLargestSentinelViewModeSegment
 };
 
- at interface VLCLibraryWindow : VLCFullVideoViewWindow<NSUserInterfaceItemIdentification, VLCDragDropTarget, VLCLibraryItemPresentingCapable>
+ at interface VLCLibraryWindow : VLCFullVideoViewWindow<NSUserInterfaceItemIdentification, VLCDragDropTarget, VLCLibraryItemPresentingCapable, NSSearchFieldDelegate>
 
 extern const CGFloat VLCLibraryWindowMinimalWidth;
 extern const CGFloat VLCLibraryWindowMinimalHeight;


=====================================
modules/gui/macosx/library/VLCLibraryWindow.m
=====================================
@@ -101,7 +101,7 @@ const CGFloat VLCLibraryWindowMinimalWidth = 604.;
 const CGFloat VLCLibraryWindowMinimalHeight = 307.;
 const NSUserInterfaceItemIdentifier VLCLibraryWindowIdentifier = @"VLCLibraryWindow";
 
- at interface VLCLibraryWindow ()
+ at interface VLCLibraryWindow () <NSControlTextEditingDelegate>
 {
     NSInteger _currentSelectedViewModeSegment;
     VLCVideoWindowCommon *_temporaryAudioDecorativeWindow;
@@ -206,6 +206,8 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
 
     [self setViewForSelectedSegment];
     [self setupLoadingOverlayView];
+
+    self.librarySearchField.delegate = self;
 }
 
 - (void)dealloc
@@ -374,6 +376,12 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
                                                            selector:@selector(updateFilterString)
                                                            userInfo:nil
                                                             repeats:NO];
+    
+    // Trigger completions
+    NSText * const fieldEditor = self.librarySearchField.currentEditor;
+    if (fieldEditor) {
+        [fieldEditor complete:sender];
+    }
 }
 
 - (void)updateFilterString
@@ -692,6 +700,46 @@ static void addShadow(NSImageView *__unsafe_unretained imageView)
     [super mouseMoved:o_event];
 }
 
+#pragma mark - NSControlTextEditingDelegate
+
+- (NSArray<NSString *> *)control:(NSControl *)control
+                         textView:(NSTextView *)textView
+                      completions:(NSArray<NSString *> *)words
+              forPartialWordRange:(NSRange)charRange
+              indexOfSelectedItem:(NSInteger *)index
+{
+    // Get the partial word being completed
+    NSString * const currentText = textView.string;
+    NSString * const partialWord = [currentText substringWithRange:charRange];
+    
+    if (partialWord.length == 0) {
+        return @[];
+    }
+    
+    // Get cached titles from library model
+    VLCLibraryModel * const libraryModel = VLCMain.sharedInstance.libraryController.libraryModel;
+    if (!libraryModel) {
+        return @[];
+    }
+    
+    NSArray<NSString *> * const allTitles = libraryModel.listOfMediaTitles;
+    NSMutableArray<NSString *> * const matchingTitles = [NSMutableArray array];
+    
+    // Filter titles that match the partial word
+    for (NSString * const title in allTitles) {
+        if (![title.lowercaseString hasPrefix:partialWord.lowercaseString]) {
+            continue;
+        }
+        [matchingTitles addObject:title];
+        if (matchingTitles.count >= 5) {
+            break;
+        }
+    }
+    
+    *index = -1;
+    return matchingTitles;
+}
+
 #pragma mark -
 #pragma mark respond to core events
 



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c9af0b78afddc0ce13e759335e3af1431be08719...627296a36e86c6a3b7f2ec42af12f09fc662cede

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c9af0b78afddc0ce13e759335e3af1431be08719...627296a36e86c6a3b7f2ec42af12f09fc662cede
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