VLCPlaylistGridView.m 14.2 KB
Newer Older
1 2 3 4 5 6 7
//
//  VLCGridViewCell.m
//  AspenProject
//
//  Created by Felix Paul Kühne on 11.04.13.
//  Copyright (c) 2013 VideoLAN. All rights reserved.
//
8 9
//  Refer to the COPYING file of the official project for license.
//
10 11

#import "VLCPlaylistGridView.h"
12
#import "VLCLinearProgressIndicator.h"
13
#import "VLCAppDelegate.h"
Felix Paul Kühne's avatar
Felix Paul Kühne committed
14
#import "AQGridView.h"
15

16
#define MAX_CACHE_SIZE 27 // three times the number of items shown on iPad
17

18
@interface VLCPlaylistGridView (Hack)
19
@property (nonatomic, retain) NSString *reuseIdentifier;
20 21 22 23
@end

@implementation VLCPlaylistGridView

24 25 26 27 28
+ (CGSize)preferredSize
{
    return CGSizeMake(288, 220);
}

29 30 31
- (void)awakeFromNib {
    [super awakeFromNib];
    _contentView = self;
32
    self.backgroundColor = [UIColor clearColor];
33
    self.reuseIdentifier = @"AQPlaylistCell";
34
    self.albumNameLabel.text = self.artistNameLabel.text = self.seriesNameLabel.text = @"";
35 36 37 38 39 40
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    [super setEditing:editing animated:animated];
    self.removeMediaButton.hidden = !editing;
41
    [self _updatedDisplayedInformationForKeyPath:@"editing"];
42 43 44
}

- (void)prepareForReuse
45
{
46 47
    [super prepareForReuse];
    self.removeMediaButton.hidden = YES;
48 49
}

50 51
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
52
    [self _updatedDisplayedInformationForKeyPath:keyPath];
53 54
}

55
- (void)setMediaObject:(MLFile *)mediaObject
56
{
57 58 59 60 61 62 63
    if (_mediaObject != mediaObject) {
        [_mediaObject removeObserver:self forKeyPath:@"computedThumbnail"];
        [_mediaObject removeObserver:self forKeyPath:@"lastPosition"];
        [_mediaObject removeObserver:self forKeyPath:@"duration"];
        [_mediaObject removeObserver:self forKeyPath:@"fileSizeInBytes"];
        [_mediaObject removeObserver:self forKeyPath:@"title"];
        [_mediaObject removeObserver:self forKeyPath:@"thumbnailTimeouted"];
64
        [_mediaObject removeObserver:self forKeyPath:@"unread"];
65 66 67 68 69 70
        [_mediaObject removeObserver:self forKeyPath:@"albumTrackNumber"];
        [_mediaObject removeObserver:self forKeyPath:@"album"];
        [_mediaObject removeObserver:self forKeyPath:@"artist"];
        [_mediaObject removeObserver:self forKeyPath:@"genre"];
        if ([_mediaObject respondsToSelector:@selector(didHide)])
            [(MLFile*)_mediaObject didHide];
71 72

        _mediaObject = mediaObject;
73

74 75 76 77 78 79
        [_mediaObject addObserver:self forKeyPath:@"computedThumbnail" options:0 context:nil];
        [_mediaObject addObserver:self forKeyPath:@"lastPosition" options:0 context:nil];
        [_mediaObject addObserver:self forKeyPath:@"duration" options:0 context:nil];
        [_mediaObject addObserver:self forKeyPath:@"fileSizeInBytes" options:0 context:nil];
        [_mediaObject addObserver:self forKeyPath:@"title" options:0 context:nil];
        [_mediaObject addObserver:self forKeyPath:@"thumbnailTimeouted" options:0 context:nil];
80
        [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
81 82 83 84 85 86 87
        [_mediaObject addObserver:self forKeyPath:@"albumTrackNumber" options:0 context:nil];
        [_mediaObject addObserver:self forKeyPath:@"album" options:0 context:nil];
        [_mediaObject addObserver:self forKeyPath:@"artist" options:0 context:nil];
        [_mediaObject addObserver:self forKeyPath:@"genre" options:0 context:nil];

        if ([_mediaObject respondsToSelector:@selector(willDisplay)])
            [(MLFile*)_mediaObject willDisplay];
88 89
    }

90
    [self _updatedDisplayedInformationForKeyPath:NULL];
91 92
}

93
- (void)_updatedDisplayedInformationForKeyPath:(NSString *)keyPath
94
{
95 96 97 98 99 100
    static NSMutableArray *_thumbnailCacheIndex;
    static NSMutableDictionary *_thumbnailCache;
    if (!_thumbnailCache)
        _thumbnailCache = [[NSMutableDictionary alloc] initWithCapacity:MAX_CACHE_SIZE];
    if (!_thumbnailCacheIndex)
        _thumbnailCacheIndex = [[NSMutableArray alloc] initWithCapacity:MAX_CACHE_SIZE];
101

102 103
    self.albumNameLabel.text = self.artistNameLabel.text = self.seriesNameLabel.text = @"";

104 105 106 107 108 109
    if ([self.mediaObject isKindOfClass:[MLFile class]]) {
        MLFile *mediaObject = self.mediaObject;
        if ([mediaObject isAlbumTrack]) {
            self.artistNameLabel.text = mediaObject.albumTrack.artist;
            self.albumNameLabel.text = mediaObject.albumTrack.album.name;
            self.titleLabel.text = (mediaObject.albumTrack.title.length > 0) ? mediaObject.albumTrack.title : mediaObject.title;
110
            self.thumbnailView.image = nil;
111
        } else if ([mediaObject isShowEpisode]) {
112 113 114
            MLShowEpisode *episode = mediaObject.showEpisode;
            self.seriesNameLabel.text = episode.show.name;
            self.titleLabel.text = (episode.name.length > 0) ? [NSString stringWithFormat:@"%@ - S%02dE%02d", episode.name, mediaObject.showEpisode.seasonNumber.intValue, episode.episodeNumber.intValue] : [NSString stringWithFormat:@"S%02dE%02d", episode.seasonNumber.intValue, episode.episodeNumber.intValue];
115 116 117 118 119 120 121 122 123 124 125 126 127
        } else
            self.titleLabel.text = mediaObject.title;

        if (self.isEditing)
            self.subtitleLabel.text = [NSString stringWithFormat:@"%@ — %i MB", [VLCTime timeWithNumber:[mediaObject duration]], (int)([mediaObject fileSizeInBytes] / 1e6)];
        else {
            self.subtitleLabel.text = [NSString stringWithFormat:@"%@", [VLCTime timeWithNumber:[mediaObject duration]]];
            if (mediaObject.videoTrack) {
                NSString *width = [[mediaObject videoTrack] valueForKey:@"width"];
                NSString *height = [[mediaObject videoTrack] valueForKey:@"height"];
                if (width.intValue > 0 && height.intValue > 0)
                    self.subtitleLabel.text = [self.subtitleLabel.text stringByAppendingFormat:@" — %@x%@", width, height];
            }
128
        }
129
        if (([keyPath isEqualToString:@"computedThumbnail"] || !keyPath) && !mediaObject.isAlbumTrack) {
130 131 132 133 134 135
            NSManagedObjectID *objID = mediaObject.objectID;
            UIImage *displayedImage;
            if ([_thumbnailCacheIndex containsObject:objID]) {
                [_thumbnailCacheIndex removeObject:objID];
                [_thumbnailCacheIndex insertObject:objID atIndex:0];
                displayedImage = [_thumbnailCache objectForKey:objID];
136 137 138 139 140
                if (!displayedImage) {
                    displayedImage = mediaObject.computedThumbnail;
                    if (displayedImage)
                        [_thumbnailCache setObject:displayedImage forKey:objID];
                }
141 142 143 144 145 146 147 148
            } else {
                if (_thumbnailCacheIndex.count >= MAX_CACHE_SIZE) {
                    [_thumbnailCache removeObjectForKey:[_thumbnailCacheIndex lastObject]];
                    [_thumbnailCacheIndex removeLastObject];
                }
                displayedImage = mediaObject.computedThumbnail;
                if (displayedImage)
                    [_thumbnailCache setObject:displayedImage forKey:objID];
149 150
                if (objID)
                    [_thumbnailCacheIndex insertObject:objID atIndex:0];
151
            }
152
            self.thumbnailView.image = displayedImage;
153
        }
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
        CGFloat position = mediaObject.lastPosition.floatValue;
        self.progressView.progress = position;
        self.progressView.hidden = ((position < .1f) || (position > .95f)) ? YES : NO;
        [self.progressView setNeedsDisplay];
        self.mediaIsUnreadView.hidden = !mediaObject.unread.intValue;
    } else if ([self.mediaObject isKindOfClass:[MLAlbum class]]) {
        MLAlbum *mediaObject = (MLAlbum *)self.mediaObject;
        self.titleLabel.text = mediaObject.name;
        MLAlbumTrack *anyTrack = [mediaObject.tracks anyObject];
        if (anyTrack)
            self.artistNameLabel.text = anyTrack.artist;
        else
            self.artistNameLabel.text = @"";
        self.albumNameLabel.text = mediaObject.releaseYear;
        self.thumbnailView.image = nil;
        NSUInteger count = mediaObject.tracks.count;
170
        self.subtitleLabel.text = [NSString stringWithFormat:(count > 1) ? NSLocalizedString(@"LIBRARY_TRACKS", @"") : NSLocalizedString(@"LIBRARY_SINGLE_TRACK", @""), count];
171 172 173 174 175
        self.mediaIsUnreadView.hidden = YES;
        self.progressView.hidden = YES;
    } else if ([self.mediaObject isKindOfClass:[MLAlbumTrack class]]) {
        MLAlbumTrack *mediaObject = (MLAlbumTrack *)self.mediaObject;
        self.artistNameLabel.text = mediaObject.artist;
176
        self.albumNameLabel.text = [NSString stringWithFormat:NSLocalizedString(@"LIBRARY_SINGLE_TRACK", @""), mediaObject.trackNumber.intValue];
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
        self.titleLabel.text = mediaObject.title;
        self.thumbnailView.image = nil;

        MLFile *anyFileFromTrack = mediaObject.files.anyObject;
        self.subtitleLabel.text = [NSString stringWithFormat:@"%@", [VLCTime timeWithNumber:[anyFileFromTrack duration]]];

        CGFloat position = anyFileFromTrack.lastPosition.floatValue;
        self.progressView.progress = position;
        self.progressView.hidden = ((position < .1f) || (position > .95f)) ? YES : NO;
        [self.progressView setNeedsDisplay];
        self.mediaIsUnreadView.hidden = !anyFileFromTrack.unread.intValue;
    } else if ([self.mediaObject isKindOfClass:[MLShow class]]) {
        MLShow *mediaObject = (MLShow *)self.mediaObject;
        self.titleLabel.text = mediaObject.name;
        self.artistNameLabel.text = @"";
        self.albumNameLabel.text = mediaObject.releaseYear;
        NSUInteger count = mediaObject.episodes.count;
194
        self.subtitleLabel.text = [NSString stringWithFormat:(count > 1) ? NSLocalizedString(@"LIBRARY_EPISODES", @"") : NSLocalizedString(@"LIBRARY_SINGLE_EPISODE", @""), count, mediaObject.unreadEpisodes.count];
195 196
        self.mediaIsUnreadView.hidden = YES;
        self.progressView.hidden = YES;
197 198 199 200 201 202 203 204 205

        MLFile *anyFileFromAnyEpisode = [mediaObject.episodes.anyObject files].anyObject;
        if ([keyPath isEqualToString:@"computedThumbnail"] || !keyPath) {
            NSManagedObjectID *objID = anyFileFromAnyEpisode.objectID;
            UIImage *displayedImage;
            if ([_thumbnailCacheIndex containsObject:objID]) {
                [_thumbnailCacheIndex removeObject:objID];
                [_thumbnailCacheIndex insertObject:objID atIndex:0];
                displayedImage = [_thumbnailCache objectForKey:objID];
206 207 208 209 210
                if (!displayedImage) {
                    displayedImage = anyFileFromAnyEpisode.computedThumbnail;
                    if (displayedImage)
                        [_thumbnailCache setObject:displayedImage forKey:objID];
                }
211 212 213 214 215 216 217 218
            } else {
                if (_thumbnailCacheIndex.count >= MAX_CACHE_SIZE) {
                    [_thumbnailCache removeObjectForKey:[_thumbnailCacheIndex lastObject]];
                    [_thumbnailCacheIndex removeLastObject];
                }
                displayedImage = anyFileFromAnyEpisode.computedThumbnail;
                if (displayedImage)
                    [_thumbnailCache setObject:displayedImage forKey:objID];
219 220
                if (objID)
                    [_thumbnailCacheIndex insertObject:objID atIndex:0];
221 222 223
            }
            self.thumbnailView.image = displayedImage;
        }
224 225 226 227 228 229 230 231 232 233 234 235 236
    } else if ([self.mediaObject isKindOfClass:[MLShowEpisode class]]) {
        MLShowEpisode *mediaObject = (MLShowEpisode *)self.mediaObject;
        self.titleLabel.text = mediaObject.name;

        MLFile *anyFileFromEpisode = mediaObject.files.anyObject;

        if ([keyPath isEqualToString:@"computedThumbnail"] || !keyPath) {
            NSManagedObjectID *objID = anyFileFromEpisode.objectID;
            UIImage *displayedImage;
            if ([_thumbnailCacheIndex containsObject:objID]) {
                [_thumbnailCacheIndex removeObject:objID];
                [_thumbnailCacheIndex insertObject:objID atIndex:0];
                displayedImage = [_thumbnailCache objectForKey:objID];
237 238 239 240 241
                if (!displayedImage) {
                    displayedImage = anyFileFromEpisode.computedThumbnail;
                    if (displayedImage)
                        [_thumbnailCache setObject:displayedImage forKey:objID];
                }
242 243 244 245 246 247 248 249
            } else {
                if (_thumbnailCacheIndex.count >= MAX_CACHE_SIZE) {
                    [_thumbnailCache removeObjectForKey:[_thumbnailCacheIndex lastObject]];
                    [_thumbnailCacheIndex removeLastObject];
                }
                displayedImage = anyFileFromEpisode.computedThumbnail;
                if (displayedImage)
                    [_thumbnailCache setObject:displayedImage forKey:objID];
250 251
                if (objID)
                    [_thumbnailCacheIndex insertObject:objID atIndex:0];
252 253 254
            }
            self.thumbnailView.image = displayedImage;
        }
255 256 257 258 259
        if (self.titleLabel.text.length < 1) {
            self.titleLabel.text = [NSString stringWithFormat:@"S%02dE%02d", mediaObject.episodeNumber.intValue, mediaObject.seasonNumber.intValue];
            self.subtitleLabel.text = [NSString stringWithFormat:@"%@", [VLCTime timeWithNumber:[anyFileFromEpisode duration]]];
        } else
            self.subtitleLabel.text = [NSString stringWithFormat:@"S%02dE%02d — %@", mediaObject.episodeNumber.intValue, mediaObject.seasonNumber.intValue, [VLCTime timeWithNumber:[anyFileFromEpisode duration]]];
260 261 262 263 264 265

        CGFloat position = anyFileFromEpisode.lastPosition.floatValue;
        self.progressView.progress = position;
        self.progressView.hidden = ((position < .1f) || (position > .95f)) ? YES : NO;
        [self.progressView setNeedsDisplay];
        self.mediaIsUnreadView.hidden = !mediaObject.unread.intValue;
266
    }
267

268
    [self setNeedsDisplay];
269 270
}

271
- (IBAction)removeMedia:(id)sender
272
{
273 274 275 276 277 278 279 280 281 282 283
    /* ask user if s/he really wants to delete the media file */
    UIAlertView * alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"DELETE_FILE", @"") message:[NSString stringWithFormat:NSLocalizedString(@"DELETE_FILE_LONG", @""), self.mediaObject.title] delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_CANCEL", @"") otherButtonTitles:NSLocalizedString(@"BUTTON_DELETE", @""), nil];
    [alert show];
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 1) {
        NSUInteger cellIndex = [self.gridView indexForCell:self];
        [self.gridView.delegate gridView:self.gridView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndex:cellIndex];
    }
284 285 286
}

@end