[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