[Sandbox] Support bookmarking individual files
Individually added files, directly opened by the user, may now store bookmarks in settings. Signed-off-by: Christopher Snowhill <kode54@gmail.com>lastfm
parent
02ec735687
commit
82179a5f10
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21223.12" systemVersion="22A5286j" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="20086" systemVersion="21F79" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="AlbumArtwork" representedClassName="AlbumArtwork" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="artData" optional="YES" attributeType="Binary"/>
|
||||
<attribute name="artHash" optional="YES" attributeType="String"/>
|
||||
|
@ -64,12 +64,13 @@
|
|||
</entity>
|
||||
<entity name="SandboxToken" representedClassName="SandboxToken" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="bookmark" optional="YES" attributeType="Binary"/>
|
||||
<attribute name="folder" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="path" optional="YES" attributeType="String"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="AlbumArtwork" positionX="0" positionY="207" width="128" height="59"/>
|
||||
<element name="PlayCount" positionX="-18" positionY="171" width="128" height="149"/>
|
||||
<element name="PlaylistEntry" positionX="-36" positionY="9" width="128" height="719"/>
|
||||
<element name="SandboxToken" positionX="-18" positionY="171" width="128" height="59"/>
|
||||
<element name="SandboxToken" positionX="-18" positionY="171" width="128" height="74"/>
|
||||
</elements>
|
||||
</model>
|
|
@ -399,6 +399,7 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
|
|||
[[SandboxBroker sharedSandboxBroker] addFolderIfMissing:url];
|
||||
[expandedURLs addObjectsFromArray:[self fileURLsAtPath:[url path]]];
|
||||
} else {
|
||||
[[SandboxBroker sharedSandboxBroker] addFileIfMissing:url];
|
||||
[expandedURLs addObject:[NSURL fileURLWithPath:[url path]]];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
@interface SandboxToken : NSManagedObject
|
||||
@property(nonatomic, strong) NSString *path;
|
||||
@property(nonatomic, strong) NSData *bookmark;
|
||||
@property(nonatomic) BOOL folder;
|
||||
@end
|
||||
|
||||
@implementation SandboxPathBehaviorController
|
||||
|
|
|
@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (void)shutdown;
|
||||
|
||||
- (void)addFolderIfMissing:(NSURL *)folderUrl;
|
||||
- (void)addFileIfMissing:(NSURL *)fileUrl;
|
||||
|
||||
- (const void *)beginFolderAccess:(NSURL *)fileUrl;
|
||||
- (void)endFolderAccess:(const void *)handle;
|
||||
|
|
|
@ -24,6 +24,7 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
NSInteger _refCount;
|
||||
NSURL *_secureUrl;
|
||||
NSString *_path;
|
||||
BOOL _isFolder;
|
||||
};
|
||||
|
||||
@property(readonly) SandboxToken *token;
|
||||
|
@ -34,6 +35,8 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
|
||||
@property NSInteger refCount;
|
||||
|
||||
@property(readonly) BOOL isFolder;
|
||||
|
||||
- (id)initWithToken:(SandboxToken *)token;
|
||||
@end
|
||||
|
||||
|
@ -45,6 +48,7 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
obj->_secureUrl = nil;
|
||||
obj->_token = token;
|
||||
obj->_path = token.path;
|
||||
obj->_isFolder = token.folder;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
@ -72,6 +76,10 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
- (NSString *)path {
|
||||
return _path;
|
||||
}
|
||||
|
||||
- (BOOL)isFolder {
|
||||
return _isFolder;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation SandboxBroker
|
||||
|
@ -99,8 +107,10 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
|
||||
NSString *s = [url path];
|
||||
|
||||
NSString *lastComponent = [url lastPathComponent];
|
||||
NSString *lastComponent = [url fragment];
|
||||
|
||||
if(lastComponent) {
|
||||
lastComponent = @"#";
|
||||
// Find that last component in the string from the end to make sure
|
||||
// to get the last one
|
||||
NSRange fragmentRange = [s rangeOfString:lastComponent
|
||||
|
@ -110,6 +120,9 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
NSString *newURLString = [s substringToIndex:fragmentRange.location + fragmentRange.length];
|
||||
|
||||
return [NSURL fileURLWithPath:newURLString];
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
|
@ -149,13 +162,30 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
|
||||
NSPersistentContainer *pc = [SandboxBroker sharedPersistentContainer];
|
||||
|
||||
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"path.length" ascending:NO];
|
||||
NSPredicate *folderPredicate = [NSPredicate predicateWithFormat:@"folder == NO"];
|
||||
NSPredicate *filePredicate = [NSPredicate predicateWithFormat:@"path == %@", [url path]];
|
||||
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[folderPredicate, filePredicate]];
|
||||
|
||||
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
|
||||
request.sortDescriptors = @[sortDescriptor];
|
||||
request.predicate = predicate;
|
||||
|
||||
NSError *error = nil;
|
||||
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
|
||||
if(results && [results count] > 0) {
|
||||
ret = [[SandboxEntry alloc] initWithToken:results[0]];
|
||||
}
|
||||
|
||||
if(!ret) {
|
||||
predicate = [NSPredicate predicateWithFormat:@"folder == YES"];
|
||||
|
||||
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"path.length" ascending:NO];
|
||||
|
||||
request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
|
||||
request.sortDescriptors = @[sortDescriptor];
|
||||
request.predicate = predicate;
|
||||
|
||||
error = nil;
|
||||
results = [pc.viewContext executeFetchRequest:request error:&error];
|
||||
if(results) results = [results copy];
|
||||
|
||||
if(results && [results count] > 0) {
|
||||
|
@ -168,6 +198,7 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ret) {
|
||||
BOOL isStale;
|
||||
|
@ -193,7 +224,7 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
SandboxEntry *_entry = nil;
|
||||
|
||||
for(SandboxEntry *entry in storage) {
|
||||
if(entry.path && [SandboxBroker isPath:folderUrl aSubdirectoryOf:[NSURL fileURLWithPath:entry.path]]) {
|
||||
if(entry.path && entry.isFolder && [SandboxBroker isPath:folderUrl aSubdirectoryOf:[NSURL fileURLWithPath:entry.path]]) {
|
||||
_entry = entry;
|
||||
break;
|
||||
}
|
||||
|
@ -227,20 +258,72 @@ static SandboxBroker *kSharedSandboxBroker = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)addFileIfMissing:(NSURL *)fileUrl {
|
||||
if(![fileUrl isFileURL]) return;
|
||||
|
||||
NSURL *url = [SandboxBroker urlWithoutFragment:fileUrl];
|
||||
|
||||
@synchronized (self) {
|
||||
SandboxEntry *_entry = nil;
|
||||
|
||||
for(SandboxEntry *entry in storage) {
|
||||
if(entry.path) {
|
||||
if((entry.isFolder && [SandboxBroker isPath:url aSubdirectoryOf:[NSURL fileURLWithPath:entry.path]]) ||
|
||||
(!entry.isFolder && [url isEqualTo:[NSURL fileURLWithPath:entry.path]])) {
|
||||
_entry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!_entry) {
|
||||
_entry = [self recursivePathTest:url];
|
||||
}
|
||||
|
||||
if(!_entry) {
|
||||
NSError *err = nil;
|
||||
NSData *bookmark = [fileUrl bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&err];
|
||||
if(!bookmark && err) {
|
||||
ALog(@"Failed to add bookmark for URL: %@, with error: %@", url, [err localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
NSPersistentContainer *pc = [NSClassFromString(@"PlaylistController") sharedPersistentContainer];
|
||||
|
||||
SandboxToken *token = [NSEntityDescription insertNewObjectForEntityForName:@"SandboxToken" inManagedObjectContext:pc.viewContext];
|
||||
|
||||
if(token) {
|
||||
token.path = [url path];
|
||||
token.bookmark = bookmark;
|
||||
token.folder = NO;
|
||||
[pc.viewContext save:&err];
|
||||
if(err) {
|
||||
ALog(@"Error saving bookmark: %@", [err localizedDescription]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (const void *)beginFolderAccess:(NSURL *)fileUrl {
|
||||
NSURL *folderUrl = [[SandboxBroker urlWithoutFragment:fileUrl] URLByDeletingLastPathComponent];
|
||||
NSURL *folderUrl = [SandboxBroker urlWithoutFragment:fileUrl];
|
||||
if(![folderUrl isFileURL]) return NULL;
|
||||
|
||||
SandboxEntry *_entry = nil;
|
||||
|
||||
NSString *sandboxPath = [folderUrl path];
|
||||
|
||||
@synchronized(self) {
|
||||
for(SandboxEntry *entry in storage) {
|
||||
if(entry.path && [SandboxBroker isPath:folderUrl aSubdirectoryOf:[NSURL fileURLWithPath:entry.path]]) {
|
||||
if(entry.path) {
|
||||
if((entry.isFolder && [SandboxBroker isPath:folderUrl aSubdirectoryOf:[NSURL fileURLWithPath:entry.path]]) ||
|
||||
(!entry.isFolder && [entry.path isEqualToString:sandboxPath])) {
|
||||
entry.refCount += 1;
|
||||
_entry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!_entry) {
|
||||
_entry = [self recursivePathTest:folderUrl];
|
||||
|
|
Loading…
Reference in New Issue