Browse Source

MovieCollectionViewCell: Implement the new design for movie files

- This removes the old playlistTableviewcell and Collectionviewcell
- it puts in place the architecture for further cells by adding a baseCollectionViewCell
Carola Nitz 7 years ago
parent
commit
d5225e9b52

+ 0 - 109
Resources/VLCPlaylistCollectionViewCell.xib

@@ -1,109 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB" version="3.0" toolsVersion="14092" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
-    <device id="ipad9_7" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14081.1"/>
-        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <objects>
-        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
-        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
-        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="VLCPlaylistCollectionViewCell" id="2" customClass="VLCPlaylistCollectionViewCell">
-            <rect key="frame" x="0.0" y="0.0" width="341" height="190"/>
-            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
-            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
-                <rect key="frame" x="0.0" y="0.0" width="341" height="190"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="31">
-                        <rect key="frame" x="0.0" y="0.0" width="341" height="190"/>
-                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                    </imageView>
-                    <imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="top" image="folderIcon.png" translatesAutoresizingMaskIntoConstraints="NO" id="0uT-W6-UMC">
-                        <rect key="frame" x="0.0" y="60" width="341" height="130"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="130" id="Xse-Zt-V2T"/>
-                        </constraints>
-                    </imageView>
-                    <imageView opaque="NO" clearsContextBeforeDrawing="NO" userInteractionEnabled="NO" contentMode="scaleToFill" image="gradient-cell-ios7" translatesAutoresizingMaskIntoConstraints="NO" id="Gzk-gj-0jk">
-                        <rect key="frame" x="0.0" y="0.0" width="341" height="190"/>
-                    </imageView>
-                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="Title" textAlignment="justified" lineBreakMode="tailTruncation" baselineAdjustment="none" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4XD-oC-pqG">
-                        <rect key="frame" x="10" y="141" width="331" height="22"/>
-                        <fontDescription key="fontDescription" type="system" weight="light" pointSize="18"/>
-                        <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <size key="shadowOffset" width="0.0" height="0.0"/>
-                    </label>
-                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="New" textAlignment="justified" lineBreakMode="wordWrap" baselineAdjustment="none" minimumFontSize="9" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ftR-Og-FOs">
-                        <rect key="frame" x="304" y="8" width="29" height="16"/>
-                        <fontDescription key="fontDescription" type="boldSystem" pointSize="13"/>
-                        <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <size key="shadowOffset" width="0.0" height="0.0"/>
-                    </label>
-                    <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="checkboxEmpty.png" translatesAutoresizingMaskIntoConstraints="NO" id="pl6-iw-2ZI">
-                        <rect key="frame" x="6" y="6" width="25" height="25"/>
-                    </imageView>
-                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="Subtitle — Subtitle" textAlignment="natural" lineBreakMode="wordWrap" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="jdp-lJ-hIF">
-                        <rect key="frame" x="10" y="166" width="114" height="16"/>
-                        <fontDescription key="fontDescription" type="boldSystem" pointSize="12"/>
-                        <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <size key="shadowOffset" width="0.0" height="0.0"/>
-                    </label>
-                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Meta Data" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lP6-D2-Oef">
-                        <rect key="frame" x="141.5" y="8" width="58.5" height="14.5"/>
-                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
-                        <color key="textColor" red="1" green="1" blue="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
-                        <nil key="highlightedColor"/>
-                    </label>
-                </subviews>
-            </view>
-            <constraints>
-                <constraint firstAttribute="bottom" secondItem="31" secondAttribute="bottom" id="2Dv-fj-XSY"/>
-                <constraint firstItem="4XD-oC-pqG" firstAttribute="trailing" secondItem="31" secondAttribute="trailing" id="3ru-uR-dxu"/>
-                <constraint firstItem="Gzk-gj-0jk" firstAttribute="leading" secondItem="2" secondAttribute="leading" id="4VB-hN-L6X"/>
-                <constraint firstItem="jdp-lJ-hIF" firstAttribute="leading" secondItem="2" secondAttribute="leadingMargin" constant="2" id="65e-1U-ucq"/>
-                <constraint firstItem="0uT-W6-UMC" firstAttribute="leading" secondItem="2" secondAttribute="leading" id="6Bc-Mo-Zvt"/>
-                <constraint firstAttribute="bottom" secondItem="jdp-lJ-hIF" secondAttribute="bottom" constant="8" id="AVR-YF-5FR"/>
-                <constraint firstItem="ftR-Og-FOs" firstAttribute="top" secondItem="2" secondAttribute="top" constant="8" id="Cf0-yy-7iB"/>
-                <constraint firstAttribute="trailing" secondItem="0uT-W6-UMC" secondAttribute="trailing" id="I1e-9b-1Eu"/>
-                <constraint firstItem="4XD-oC-pqG" firstAttribute="leading" secondItem="2" secondAttribute="leadingMargin" constant="2" id="Myr-sC-Y6O"/>
-                <constraint firstItem="0uT-W6-UMC" firstAttribute="top" secondItem="31" secondAttribute="bottom" constant="-130" id="Owc-pg-OJY"/>
-                <constraint firstItem="pl6-iw-2ZI" firstAttribute="top" secondItem="2" secondAttribute="top" constant="6" id="SKc-13-c0F"/>
-                <constraint firstItem="ftR-Og-FOs" firstAttribute="height" secondItem="jdp-lJ-hIF" secondAttribute="height" id="UwZ-3F-Sbj"/>
-                <constraint firstItem="Gzk-gj-0jk" firstAttribute="top" secondItem="2" secondAttribute="top" id="XMJ-wS-Zg4"/>
-                <constraint firstItem="31" firstAttribute="top" secondItem="2" secondAttribute="top" id="YMD-tj-91G"/>
-                <constraint firstAttribute="trailing" secondItem="ftR-Og-FOs" secondAttribute="trailing" constant="8" id="bcZ-dH-pSC"/>
-                <constraint firstAttribute="bottom" secondItem="Gzk-gj-0jk" secondAttribute="bottom" id="e0A-1e-hof"/>
-                <constraint firstItem="lP6-D2-Oef" firstAttribute="top" secondItem="2" secondAttribute="top" constant="8" id="gcu-no-yiW"/>
-                <constraint firstItem="lP6-D2-Oef" firstAttribute="centerX" secondItem="Gzk-gj-0jk" secondAttribute="centerX" id="hF6-wk-HUE"/>
-                <constraint firstItem="pl6-iw-2ZI" firstAttribute="leading" secondItem="2" secondAttribute="leading" constant="6" id="lWY-9H-Xrv"/>
-                <constraint firstAttribute="trailing" secondItem="31" secondAttribute="trailing" id="mmM-A8-uNu"/>
-                <constraint firstItem="jdp-lJ-hIF" firstAttribute="top" secondItem="4XD-oC-pqG" secondAttribute="bottom" constant="3" id="odO-K3-Eql"/>
-                <constraint firstItem="31" firstAttribute="leading" secondItem="2" secondAttribute="leading" id="tP4-CX-bVc"/>
-                <constraint firstAttribute="trailing" secondItem="Gzk-gj-0jk" secondAttribute="trailing" id="uZk-Aw-Ubw"/>
-            </constraints>
-            <size key="customSize" width="298" height="167"/>
-            <connections>
-                <outlet property="folderIconView" destination="0uT-W6-UMC" id="coZ-4M-nCp"/>
-                <outlet property="isSelectedView" destination="pl6-iw-2ZI" id="1sX-gh-yiU"/>
-                <outlet property="mediaIsUnreadView" destination="ftR-Og-FOs" id="5aH-vE-E37"/>
-                <outlet property="metaDataLabel" destination="lP6-D2-Oef" id="OBz-fP-Wk1"/>
-                <outlet property="subtitleLabel" destination="jdp-lJ-hIF" id="YUa-G7-CMl"/>
-                <outlet property="thumbnailView" destination="31" id="46"/>
-                <outlet property="titleLabel" destination="4XD-oC-pqG" id="Te1-JA-An0"/>
-            </connections>
-        </collectionViewCell>
-    </objects>
-    <resources>
-        <image name="checkboxEmpty.png" width="25" height="25"/>
-        <image name="folderIcon.png" width="221" height="205"/>
-        <image name="gradient-cell-ios7" width="2" height="190"/>
-    </resources>
-</document>

+ 0 - 99
Resources/VLCPlaylistTableViewCell.xib

@@ -1,99 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14092" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
-    <device id="retina4_7" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14081.1"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <objects>
-        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
-        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
-        <tableViewCell contentMode="scaleToFill" selectionStyle="blue" indentationWidth="10" reuseIdentifier="VLCPlaylistTableViewCell" rowHeight="191" id="3" customClass="VLCPlaylistTableViewCell">
-            <rect key="frame" x="0.0" y="0.0" width="320" height="90"/>
-            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
-            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3" id="pEL-yt-P8r">
-                <rect key="frame" x="0.0" y="0.0" width="320" height="89.5"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="4">
-                        <rect key="frame" x="0.0" y="0.0" width="320" height="89"/>
-                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                    </imageView>
-                    <imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="top" image="folderIcon.png" translatesAutoresizingMaskIntoConstraints="NO" id="5iA-hI-rrr">
-                        <rect key="frame" x="0.0" y="35" width="320" height="54"/>
-                    </imageView>
-                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="gradient-cell-ios7" translatesAutoresizingMaskIntoConstraints="NO" id="22">
-                        <rect key="frame" x="0.0" y="0.0" width="320" height="89"/>
-                    </imageView>
-                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="none" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6">
-                        <rect key="frame" x="8" y="40" width="312" height="18"/>
-                        <fontDescription key="fontDescription" type="system" weight="light" pointSize="15"/>
-                        <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <size key="shadowOffset" width="0.0" height="0.0"/>
-                    </label>
-                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="New" textAlignment="right" lineBreakMode="wordWrap" baselineAdjustment="none" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="sYw-l2-Tmv">
-                        <rect key="frame" x="286" y="66" width="26" height="15"/>
-                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
-                        <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <size key="shadowOffset" width="0.0" height="0.0"/>
-                    </label>
-                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Subtitle — Subtitle" lineBreakMode="wordWrap" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="7">
-                        <rect key="frame" x="8" y="66" width="106" height="15"/>
-                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
-                        <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <size key="shadowOffset" width="0.0" height="0.0"/>
-                    </label>
-                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Meta Data" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3xi-uj-aAV">
-                        <rect key="frame" x="131.5" y="8" width="58.5" height="14.5"/>
-                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
-                        <color key="textColor" red="1" green="1" blue="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
-                        <nil key="highlightedColor"/>
-                    </label>
-                </subviews>
-                <constraints>
-                    <constraint firstItem="5iA-hI-rrr" firstAttribute="top" secondItem="pEL-yt-P8r" secondAttribute="top" constant="35" id="0e6-eB-gIO"/>
-                    <constraint firstItem="sYw-l2-Tmv" firstAttribute="height" secondItem="7" secondAttribute="height" id="1N5-73-wMe"/>
-                    <constraint firstAttribute="trailing" secondItem="22" secondAttribute="trailing" id="1Zz-cK-59T"/>
-                    <constraint firstItem="6" firstAttribute="leading" secondItem="pEL-yt-P8r" secondAttribute="leading" constant="8" id="B58-rD-stL"/>
-                    <constraint firstItem="4" firstAttribute="leading" secondItem="pEL-yt-P8r" secondAttribute="leading" id="BWt-6F-Z6H"/>
-                    <constraint firstItem="7" firstAttribute="top" secondItem="6" secondAttribute="bottom" constant="8" id="FDZ-lE-uBQ"/>
-                    <constraint firstItem="3xi-uj-aAV" firstAttribute="top" secondItem="pEL-yt-P8r" secondAttribute="top" constant="8" id="G7M-XR-ut3"/>
-                    <constraint firstItem="6" firstAttribute="trailing" secondItem="4" secondAttribute="trailing" id="GgF-Jk-5oG"/>
-                    <constraint firstAttribute="bottom" secondItem="22" secondAttribute="bottom" id="JC6-Q6-E9V"/>
-                    <constraint firstAttribute="bottom" secondItem="sYw-l2-Tmv" secondAttribute="bottom" constant="8" id="MpI-5C-JLG"/>
-                    <constraint firstAttribute="trailing" secondItem="5iA-hI-rrr" secondAttribute="trailing" id="PfR-Cm-d7h"/>
-                    <constraint firstAttribute="trailing" secondItem="4" secondAttribute="trailing" id="Q12-b6-BKB"/>
-                    <constraint firstAttribute="bottom" secondItem="5iA-hI-rrr" secondAttribute="bottom" id="Thz-vE-rDq"/>
-                    <constraint firstAttribute="bottom" secondItem="7" secondAttribute="bottom" constant="8" id="V2A-54-5Em"/>
-                    <constraint firstItem="22" firstAttribute="top" secondItem="pEL-yt-P8r" secondAttribute="top" id="VLS-dT-bzc"/>
-                    <constraint firstItem="5iA-hI-rrr" firstAttribute="leading" secondItem="pEL-yt-P8r" secondAttribute="leading" id="VNu-Ix-mHw"/>
-                    <constraint firstItem="22" firstAttribute="leading" secondItem="pEL-yt-P8r" secondAttribute="leading" id="XbD-ch-L0p"/>
-                    <constraint firstItem="3xi-uj-aAV" firstAttribute="centerX" secondItem="22" secondAttribute="centerX" id="Y3s-4z-kaM"/>
-                    <constraint firstAttribute="trailing" secondItem="sYw-l2-Tmv" secondAttribute="trailing" constant="8" id="Zcw-z4-u4F"/>
-                    <constraint firstItem="7" firstAttribute="leading" secondItem="pEL-yt-P8r" secondAttribute="leading" constant="8" id="faR-g7-XYt"/>
-                    <constraint firstAttribute="bottom" secondItem="4" secondAttribute="bottom" id="izG-dY-vNl"/>
-                    <constraint firstItem="4" firstAttribute="top" secondItem="pEL-yt-P8r" secondAttribute="top" id="j8t-Ng-xOy"/>
-                </constraints>
-            </tableViewCellContentView>
-            <color key="backgroundColor" red="0.11999999731779099" green="0.11999999731779099" blue="0.11999999731779099" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-            <connections>
-                <outlet property="folderIconView" destination="5iA-hI-rrr" id="K2w-2u-dEl"/>
-                <outlet property="mediaIsUnreadView" destination="sYw-l2-Tmv" id="us6-sJ-NVp"/>
-                <outlet property="metaDataLabel" destination="3xi-uj-aAV" id="BXL-7W-XC9"/>
-                <outlet property="subtitleLabel" destination="7" id="8"/>
-                <outlet property="thumbnailView" destination="4" id="9"/>
-                <outlet property="titleLabel" destination="6" id="10"/>
-            </connections>
-        </tableViewCell>
-    </objects>
-    <resources>
-        <image name="folderIcon.png" width="221" height="205"/>
-        <image name="gradient-cell-ios7" width="2" height="92"/>
-    </resources>
-</document>

+ 5 - 0
SharedSources/MediaLibraryModel/MediaLibraryBaseModel.swift

@@ -18,6 +18,7 @@ protocol MediaLibraryBaseModel {
     var updateView: (() -> Void)? { get set }
 
     var indicatorName: String { get }
+    var cellType: BaseCollectionViewCell.Type { get }
 
     func append(_ item: VLCMLObject)
     func delete(_ items: [VLCMLObject])
@@ -44,6 +45,10 @@ protocol MLBaseModel: MediaLibraryBaseModel {
 }
 
 extension MLBaseModel {
+    var cellType: BaseCollectionViewCell.Type {
+        return MovieCollectionViewCell.self
+    }
+
     var anyfiles: [VLCMLObject] {
         return files
     }

+ 14 - 1
SharedSources/MediaLibraryModel/VideoModel.swift

@@ -95,7 +95,7 @@ extension VLCMLMedia {
 }
 
 extension VLCMLMedia {
-    @objc func formatDuration() -> String {
+    @objc func mediaDuration() -> String {
         return String(format: "%@", VLCTime(int: Int32(duration())))
     }
 
@@ -103,4 +103,17 @@ extension VLCMLMedia {
         return ByteCountFormatter.string(fromByteCount: Int64(mainFile().size()),
                                          countStyle: .file)
     }
+
+    func mediaProgress() -> Float {
+        guard let string = metadata(of: .progress).str as NSString? else {
+            return 0.0
+        }
+        return string.floatValue
+    }
+
+    func isNew() -> Bool {
+        let integer = metadata(of: .seen).integer()
+        return integer == 0
+    }
+
 }

+ 66 - 0
SharedSources/MovieCollectionViewCell.swift

@@ -0,0 +1,66 @@
+/*****************************************************************************
+ * MovieCollectionViewCell.swift
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2018 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Carola Nitz <nitz.carola # googlemail.com>
+ *
+ * Refer to the COPYING file of the official project for license.
+*****************************************************************************/
+
+import Foundation
+
+class MovieCollectionViewCell: BaseCollectionViewCell {
+
+    @IBOutlet weak var thumbnailView: UIImageView!
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var newLabel: UILabel!
+    @IBOutlet weak var descriptionLabel: UILabel!
+    @IBOutlet weak var progressView: UIProgressView!
+
+    override var media: VLCMLObject? {
+        didSet {
+            guard let movie = media as? VLCMLMedia else {
+                fatalError("needs to be of Type VLCMLMovie")
+            }
+            update(movie:movie)
+        }
+    }
+
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        newLabel.text = NSLocalizedString("NEW", comment: "")
+        newLabel.textColor = PresentationTheme.current.colors.orangeUI
+        NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .VLCThemeDidChangeNotification, object: nil)
+        themeDidChange()
+    }
+
+    @objc fileprivate func themeDidChange() {
+        backgroundColor = PresentationTheme.current.colors.background
+        titleLabel?.textColor = PresentationTheme.current.colors.cellTextColor
+        descriptionLabel?.textColor = PresentationTheme.current.colors.cellDetailTextColor
+    }
+
+    func update(movie: VLCMLMedia) {
+        titleLabel.text = movie.title
+        descriptionLabel.text = movie.mediaDuration()
+        if movie.isThumbnailGenerated() {
+            thumbnailView.image = UIImage(contentsOfFile: movie.thumbnail.absoluteString)
+        }
+        let progress = movie.mediaProgress()
+        progressView.isHidden = progress == 0
+        progressView.progress = progress
+        newLabel.isHidden = !movie.isNew()
+    }
+
+    override func prepareForReuse() {
+        super.prepareForReuse()
+        titleLabel.text = ""
+        descriptionLabel.text = ""
+        thumbnailView.image = nil
+        progressView.isHidden = true
+        newLabel.isHidden = true
+    }
+}

+ 26 - 0
Sources/BaseCollectionViewCell.swift

@@ -0,0 +1,26 @@
+/*****************************************************************************
+ * BaseCollectionViewCell.Swift
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2018 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Carola Nitz <nitz.carola # googlemail.com>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+import Foundation
+
+class BaseCollectionViewCell: UICollectionViewCell {
+
+    static var defaultReuseIdentifier: String {
+        return NSStringFromClass(self)
+    }
+
+    class var nibName: String {
+        return String(describing:self)
+    }
+
+    var media: VLCMLObject?
+}

+ 16 - 16
Sources/MediaCategories/MediaCategoryViewController.swift

@@ -92,8 +92,8 @@ class VLCMediaCategoryViewController: UICollectionViewController, UICollectionVi
     }
 
     func setupCollectionView() {
-        let playlistnib = UINib(nibName: "VLCPlaylistCollectionViewCell", bundle: nil)
-        collectionView?.register(playlistnib, forCellWithReuseIdentifier: VLCPlaylistCollectionViewCell.cellIdentifier())
+        let cellNib = UINib(nibName: category.cellType.nibName, bundle: nil)
+        collectionView?.register(cellNib, forCellWithReuseIdentifier: category.cellType.defaultReuseIdentifier)
         collectionView?.register(VLCMediaViewEditCell.self, forCellWithReuseIdentifier: VLCMediaViewEditCell.identifier)
         collectionView?.backgroundColor = PresentationTheme.current.colors.background
         collectionView?.alwaysBounceVertical = true
@@ -190,24 +190,23 @@ class VLCMediaCategoryViewController: UICollectionViewController, UICollectionVi
     }
 
     override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-        if let playlistCell = collectionView.dequeueReusableCell(withReuseIdentifier: VLCPlaylistCollectionViewCell.cellIdentifier(), for: indexPath) as? VLCPlaylistCollectionViewCell {
-            if let mediaObject = category.anyfiles[indexPath.row] as? NSManagedObject {
-                playlistCell.mediaObject = mediaObject
-            }
+        guard let mediaCell = collectionView.dequeueReusableCell(withReuseIdentifier:category.cellType.defaultReuseIdentifier, for: indexPath) as? BaseCollectionViewCell else {
+            assertionFailure("you forgot to register the cell or the cell is not a subclass of BaseCollectionViewCell")
+            return UICollectionViewCell()
+        }
 
-            if let media = category.anyfiles[indexPath.row] as? VLCMLMedia {
-                playlistCell.media = (media.mainFile() != nil) ? media : nil
-            }
-            return playlistCell
+        guard let media = category.anyfiles[indexPath.row] as? VLCMLMedia else {
+            assertionFailure("The contained file in the category doesn't conform to VLCMLMedia")
+            return mediaCell
         }
-        return UICollectionViewCell()
+        assert(media.mainFile() != nil, "The mainfile is nil")
+        mediaCell.media = media.mainFile() != nil ? media : nil
+        return mediaCell
     }
 
     // MARK: - UICollectionViewDelegate
     override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
-        if let mediaObject = category.anyfiles[indexPath.row] as? NSManagedObject {
-            play(mediaObject: mediaObject)
-        } else if let media = category.anyfiles[indexPath.row] as? VLCMLMedia {
+        if let media = category.anyfiles[indexPath.row] as? VLCMLMedia {
             play(media: media)
         }
     }
@@ -215,7 +214,7 @@ class VLCMediaCategoryViewController: UICollectionViewController, UICollectionVi
     // MARK: - UICollectionViewDelegateFlowLayout
     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
 
-        let numberOfCells: CGFloat = collectionView.traitCollection.horizontalSizeClass == .regular ? 3.0 : 2.0
+        let numberOfCells: CGFloat = round(collectionView.frame.size.width / 250)
         let aspectRatio: CGFloat = 10.0 / 16.0
 
         // We have the number of cells and we always have numberofCells + 1 padding spaces. -pad-[Cell]-pad-[Cell]-pad-
@@ -224,7 +223,8 @@ class VLCMediaCategoryViewController: UICollectionViewController, UICollectionVi
         var cellWidth = collectionView.bounds.size.width / numberOfCells
         cellWidth = cellWidth - ceil(((numberOfCells + 1) * cellPadding) / numberOfCells)
 
-        return CGSize(width: cellWidth, height: cellWidth * aspectRatio)
+        // 3*20 for the labels + 24 for 3*8 which is the padding
+        return CGSize(width: cellWidth, height: cellWidth * aspectRatio + 3*20+24)
     }
 
     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

+ 94 - 0
Sources/MovieCollectionViewCell.xib

@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+        <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="YyZ-zI-cD7" customClass="MovieCollectionViewCell" customModule="VLC" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="309" height="230"/>
+            <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
+            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
+                <rect key="frame" x="0.0" y="0.0" width="309" height="230"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="iWM-y0-SUe">
+                        <rect key="frame" x="0.0" y="0.0" width="309" height="230"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="jmi-G0-XOo" userLabel="Thumbnail">
+                                <rect key="frame" x="0.0" y="0.0" width="309" height="193"/>
+                                <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" secondItem="jmi-G0-XOo" secondAttribute="height" multiplier="16:10" id="Oml-o7-Dfl"/>
+                                </constraints>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4zQ-Mf-dw7" userLabel="Titlelabel">
+                                <rect key="frame" x="0.0" y="201" width="37.5" height="7.5"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                <nil key="textColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="VeB-L1-KVk">
+                                <rect key="frame" x="0.0" y="216.5" width="63" height="13.5"/>
+                                <subviews>
+                                    <stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="Cgk-mu-ntx">
+                                        <rect key="frame" x="0.0" y="0.0" width="63" height="13.5"/>
+                                        <subviews>
+                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="new" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Aby-eq-q1j" userLabel="NewLabel">
+                                                <rect key="frame" x="0.0" y="0.0" width="23" height="13.5"/>
+                                                <fontDescription key="fontDescription" type="boldSystem" pointSize="11"/>
+                                                <nil key="textColor"/>
+                                                <nil key="highlightedColor"/>
+                                            </label>
+                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oac-dS-Qcd" userLabel="descriptionLabel">
+                                                <rect key="frame" x="31" y="0.0" width="32" height="13.5"/>
+                                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="12"/>
+                                                <nil key="textColor"/>
+                                                <nil key="highlightedColor"/>
+                                            </label>
+                                        </subviews>
+                                    </stackView>
+                                </subviews>
+                            </stackView>
+                        </subviews>
+                    </stackView>
+                    <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="X8l-k0-1oc">
+                        <rect key="frame" x="0.0" y="191" width="309" height="2"/>
+                        <color key="tintColor" red="0.9552378654" green="0.65840983580000001" blue="0.28695866590000002" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
+                    </progressView>
+                </subviews>
+            </view>
+            <constraints>
+                <constraint firstItem="iWM-y0-SUe" firstAttribute="bottom" relation="lessThanOrEqual" secondItem="YyZ-zI-cD7" secondAttribute="bottom" id="3VI-xW-KQ4"/>
+                <constraint firstItem="iWM-y0-SUe" firstAttribute="leading" secondItem="YyZ-zI-cD7" secondAttribute="leading" id="43e-Na-uN0"/>
+                <constraint firstItem="VeB-L1-KVk" firstAttribute="leading" secondItem="BvH-0B-sVS" secondAttribute="leading" id="8tP-cl-aIe"/>
+                <constraint firstItem="4zQ-Mf-dw7" firstAttribute="leading" secondItem="BvH-0B-sVS" secondAttribute="leading" id="Ijd-61-ouV"/>
+                <constraint firstAttribute="trailing" secondItem="iWM-y0-SUe" secondAttribute="trailing" id="PrI-Yq-B9j"/>
+                <constraint firstItem="iWM-y0-SUe" firstAttribute="leading" secondItem="X8l-k0-1oc" secondAttribute="leading" id="Rq2-SS-aA2"/>
+                <constraint firstItem="X8l-k0-1oc" firstAttribute="leading" secondItem="jmi-G0-XOo" secondAttribute="leading" id="WvI-Ra-xlu"/>
+                <constraint firstItem="iWM-y0-SUe" firstAttribute="top" secondItem="YyZ-zI-cD7" secondAttribute="top" id="Y4b-8y-MOG"/>
+                <constraint firstItem="X8l-k0-1oc" firstAttribute="trailing" secondItem="jmi-G0-XOo" secondAttribute="trailing" id="d8L-w5-ba5"/>
+                <constraint firstItem="X8l-k0-1oc" firstAttribute="bottom" secondItem="jmi-G0-XOo" secondAttribute="bottom" id="dWh-bB-nfd"/>
+                <constraint firstItem="jmi-G0-XOo" firstAttribute="width" secondItem="YyZ-zI-cD7" secondAttribute="width" id="t8h-GJ-GvI"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="BvH-0B-sVS"/>
+            <size key="customSize" width="309" height="230"/>
+            <connections>
+                <outlet property="descriptionLabel" destination="oac-dS-Qcd" id="1iJ-b6-gC6"/>
+                <outlet property="newLabel" destination="Aby-eq-q1j" id="4rD-oo-gdq"/>
+                <outlet property="progressView" destination="X8l-k0-1oc" id="mf9-zf-3ya"/>
+                <outlet property="thumbnailView" destination="jmi-G0-XOo" id="gMW-XK-9MV"/>
+                <outlet property="titleLabel" destination="4zQ-Mf-dw7" id="iGP-8x-anz"/>
+            </connections>
+            <point key="canvasLocation" x="-99.5" y="136"/>
+        </collectionViewCell>
+    </objects>
+</document>

+ 1 - 1
Sources/VLCEditController.swift

@@ -196,7 +196,7 @@ extension VLCEditController: UICollectionViewDataSource {
                                                          for: indexPath) as? VLCMediaViewEditCell {
             if let media = category.anyfiles[indexPath.row] as? VLCMLMedia {
                 cell.titleLabel.text = media.title
-                cell.subInfoLabel.text = media.formatDuration()
+                cell.subInfoLabel.text = media.mediaDuration()
                 cell.sizeLabel.text = media.formatSize()
             }
             return cell

+ 4 - 17
Sources/VLCLibrarySearchDisplayDataSource.m

@@ -11,8 +11,6 @@
  *****************************************************************************/
 
 #import "VLCLibrarySearchDisplayDataSource.h"
-#import "VLCPlaylistTableViewCell.h"
-#import "VLCPlaylistCollectionViewCell.h"
 
 @interface VLCLibrarySearchDisplayDataSource() <UITableViewDataSource>
 {
@@ -38,25 +36,14 @@
 
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    VLCPlaylistTableViewCell *cell = (VLCPlaylistTableViewCell *)[tableView dequeueReusableCellWithIdentifier:VLCPlaylistTableViewCell.cellIdentifier forIndexPath:indexPath];
-
-    NSInteger row = indexPath.row;
-
-    if (row < _searchData.count)
-        cell.mediaObject = _searchData[row];
-
-    return cell;
+    //needs to be updated as part of https://code.videolan.org/videolan/vlc-ios/issues/182
+    return [UITableViewCell new];
 }
 
 - (nonnull __kindof UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
-    VLCPlaylistCollectionViewCell *cell = (VLCPlaylistCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:VLCPlaylistCollectionViewCell.cellIdentifier forIndexPath:indexPath];
-
-    NSInteger row = indexPath.row;
-
-    if (row < _searchData.count)
-        cell.mediaObject = _searchData[row];
 
-    return cell;
+    //needs to be updated as part of https://code.videolan.org/videolan/vlc-ios/issues/182
+    return [UICollectionViewCell new];
 }
 
 - (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

+ 0 - 43
Sources/VLCPlaylistCollectionViewCell.h

@@ -1,43 +0,0 @@
-/*****************************************************************************
- * VLCPlaylistCollectionViewCell.h
- * VLC for iOS
- *****************************************************************************
- * Copyright (c) 2013-2018 VideoLAN. All rights reserved.
- * $Id$
- *
- * Authors: Felix Paul Kühne <fkuehne # videolan.org>
- *          Tamas Timar <ttimar.vlc # gmail.com>
- *          Gleb Pinigin <gpinigin # gmail.com>
- *          Carola Nitz <nitz.carola # gmail.com>
- *
- * Refer to the COPYING file of the official project for license.
- *****************************************************************************/
-
-#import <UIKit/UIKit.h>
-#import "VLCLinearProgressIndicator.h"
-
-@class VLCMLMedia;
-
-@interface VLCPlaylistCollectionViewCell : UICollectionViewCell
-
-@property (nonatomic, strong) IBOutlet UILabel *titleLabel;
-@property (nonatomic, strong) IBOutlet UILabel *subtitleLabel;
-@property (nonatomic, strong) IBOutlet UIImageView *thumbnailView;
-@property (nonatomic, strong) IBOutlet VLCLinearProgressIndicator *progressView;
-@property (nonatomic, strong) IBOutlet UIView *mediaIsUnreadView;
-@property (nonatomic, strong) IBOutlet UIImageView *isSelectedView;
-@property (nonatomic, strong) IBOutlet UIImageView *folderIconView;
-@property (nonatomic, strong) IBOutlet UILabel *metaDataLabel;
-
-@property (nonatomic, retain) NSManagedObject *mediaObject;
-@property (nonatomic, retain) VLCMLMedia *media;
-
-@property (nonatomic, weak) UICollectionView *collectionView;
-@property (readonly) BOOL showsMetaData;
-
-- (void)setEditing:(BOOL)editing animated:(BOOL)animated;
-- (void)selectionUpdate;
-- (void)showMetadata:(BOOL)showMeta;
-+ (NSString *)cellIdentifier;
-
-@end

+ 0 - 560
Sources/VLCPlaylistCollectionViewCell.m

@@ -1,560 +0,0 @@
-/*****************************************************************************
- * VLCPlaylistCollectionViewCell.m
- * VLC for iOS
- *****************************************************************************
- * Copyright (c) 2013-2018 VideoLAN. All rights reserved.
- * $Id$
- *
- * Authors: Felix Paul Kühne <fkuehne # videolan.org>
- *          Tamas Timar <ttimar.vlc # gmail.com>
- *          Gleb Pinigin <gpinigin # gmail.com>
- *          Carola Nitz <nitz.carola # googlemail.com>
- *
- * Refer to the COPYING file of the official project for license.
- *****************************************************************************/
-
-#import "VLCPlaylistCollectionViewCell.h"
-#import "VLCThumbnailsCache.h"
-#import "NSString+SupportedMedia.h"
-#import "VLC-Swift.h"
-
-@interface VLCPlaylistCollectionViewCell ()
-{
-    UIImage *_checkboxEmptyImage;
-    UIImage *_checkboxImage;
-    BOOL _editing;
-}
-
-@end
-
-@implementation VLCPlaylistCollectionViewCell
-
-- (void)dealloc
-{
-    [self _removeObserver];
-}
-
-- (void)awakeFromNib
-{
-    _checkboxEmptyImage = [UIImage imageNamed:@"checkboxEmpty"];
-    _checkboxImage = [UIImage imageNamed:@"checkbox"];
-    self.metaDataLabel.hidden = YES;
-    [super awakeFromNib];
-}
-
-+ (NSString *)cellIdentifier
-{
-    return @"VLCPlaylistCollectionViewCell";
-}
-
-- (void)setEditing:(BOOL)editing animated:(BOOL)animated
-{
-    _editing = editing;
-    self.isSelectedView.hidden = !_editing;
-
-    [self shake];
-    [self selectionUpdate];
-    [self _updatedDisplayedInformationForKeyPath:@"editing"];
-}
-
-- (void)selectionUpdate
-{
-    if (self.selected)
-        self.isSelectedView.image = _checkboxImage;
-    else
-        self.isSelectedView.image = _checkboxEmptyImage;
-}
-
-- (void)shake
-{
-    if (_editing) {
-        [UIView animateWithDuration:0.3 animations:^{
-            self.contentView.transform = CGAffineTransformMakeScale(0.9f, 0.9f);
-        }];
-        CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
-        CGFloat shakeAngle = 0.02f;
-        animation.values = @[@(-shakeAngle), @(shakeAngle)];
-        animation.autoreverses = YES;
-        animation.duration = 0.125;
-        animation.repeatCount = HUGE_VALF;
-
-        [[self layer] addAnimation:animation forKey:@"shakeAnimation"];
-        self.contentView.layer.cornerRadius = 10.0;
-        self.contentView.clipsToBounds = YES;
-    } else {
-        [UIView animateWithDuration:0.3 animations:^{
-            self.contentView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
-            self.contentView.layer.cornerRadius = 0.0;
-            self.contentView.clipsToBounds = NO;
-        }];
-        [[self layer] removeAnimationForKey:@"shakeAnimation"];
-    }
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
-{
-    [self _updatedDisplayedInformationForKeyPath:keyPath];
-}
-
-- (void)_removeObserver
-{
-    @try {
-        if ([_mediaObject isKindOfClass:[MLLabel class]]) {
-            [_mediaObject removeObserver:self forKeyPath:@"files"];
-            [_mediaObject removeObserver:self forKeyPath:@"name"];
-        } else if ([_mediaObject isKindOfClass:[MLShow class]])
-            [_mediaObject removeObserver:self forKeyPath:@"episodes"];
-        else if ([_mediaObject isKindOfClass:[MLShowEpisode class]]) {
-            [_mediaObject removeObserver:self forKeyPath:@"name"];
-            [_mediaObject removeObserver:self forKeyPath:@"files"];
-            [_mediaObject removeObserver:self forKeyPath:@"artworkURL"];
-            [_mediaObject removeObserver:self forKeyPath:@"unread"];
-        } else if ([_mediaObject isKindOfClass:[MLAlbum class]]) {
-            [_mediaObject removeObserver:self forKeyPath:@"name"];
-            [_mediaObject removeObserver:self forKeyPath:@"tracks"];
-        } else if ([_mediaObject isKindOfClass:[MLAlbumTrack class]]) {
-            [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
-            [_mediaObject removeObserver:self forKeyPath:@"artist"];
-            [_mediaObject removeObserver:self forKeyPath:@"title"];
-            [_mediaObject removeObserver:self forKeyPath:@"files"];
-            MLFile *anyFileFromTrack = [(MLAlbumTrack *)_mediaObject anyFileFromTrack];
-            if (anyFileFromTrack)
-                [anyFileFromTrack removeObserver:self forKeyPath:@"artworkURL"];
-        } else if ([_mediaObject isKindOfClass:[MLFile class]]) {
-            [_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"];
-            [_mediaObject removeObserver:self forKeyPath:@"unread"];
-            [_mediaObject removeObserver:self forKeyPath:@"albumTrackNumber"];
-            [_mediaObject removeObserver:self forKeyPath:@"album"];
-            [_mediaObject removeObserver:self forKeyPath:@"artist"];
-            [_mediaObject removeObserver:self forKeyPath:@"genre"];
-            [(MLFile*)_mediaObject didHide];
-        }
-    }
-    @catch (NSException *exception) {
-        APLog(@"removing observer failed");
-    }
-}
-
-- (void)_addObserver
-{
-    if ([_mediaObject isKindOfClass:[MLLabel class]]) {
-        [_mediaObject addObserver:self forKeyPath:@"files" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"name" options:0 context:nil];
-    } else if ([_mediaObject isKindOfClass:[MLShow class]])
-        [_mediaObject addObserver:self forKeyPath:@"episodes" options:0 context:nil];
-    else if ([_mediaObject isKindOfClass:[MLShowEpisode class]]) {
-        [_mediaObject addObserver:self forKeyPath:@"name" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"files" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"artworkURL" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
-    } else if ([_mediaObject isKindOfClass:[MLAlbum class]]) {
-        [_mediaObject addObserver:self forKeyPath:@"name" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"tracks" options:0 context:nil];
-    } else if ([_mediaObject isKindOfClass:[MLAlbumTrack class]]) {
-        [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"artist" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"title" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"files" options:0 context:nil];
-        MLFile *anyFileFromTrack = [(MLAlbumTrack *)_mediaObject anyFileFromTrack];
-        if (anyFileFromTrack)
-            [anyFileFromTrack addObserver:self forKeyPath:@"artworkURL" options:0 context:nil];
-    } else if ([_mediaObject isKindOfClass:[MLFile class]]) {
-        [_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];
-        [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
-        [_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];
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(thumbnailWasUpdated:)
-                                                     name:MLFileThumbnailWasUpdated
-                                                   object:nil];
-        [(MLFile*)_mediaObject willDisplay];
-    }
-}
-
-- (void)setMediaObject:(MLFile *)mediaObject
-{
-    if (_mediaObject != mediaObject) {
-
-        [self _removeObserver];
-
-        _mediaObject = mediaObject;
-        // prevent the cell from recycling the current snap for random contents
-        self.thumbnailView.image = nil;
-
-        [self _addObserver];
-    }
-
-    [self _updatedDisplayedInformationForKeyPath:nil];
-}
-
-- (void)setMedia:(VLCMLMedia *)media
-{
-    if (_media != media) {
-        _media = media;
-    }
-    [self _updateDisplayedInformations];
-}
-
-- (void)_updateDisplayedInformations
-{
-    _titleLabel.text = _media.title;
-    _subtitleLabel.text = [NSString stringWithFormat:@"%@ - %@",
-                           [_media formatDuration],
-                           [_media formatSize]];
-    _thumbnailView.image = [UIImage imageWithContentsOfFile:_media.thumbnail.absoluteString];
-}
-
-- (void)_updatedDisplayedInformationForKeyPath:(NSString *)keyPath
-{
-    self.thumbnailView.contentMode = UIViewContentModeScaleAspectFill;
-    if ([self.mediaObject isKindOfClass:[MLFile class]]) {
-        [self _configureForMLFile:(MLFile *)self.mediaObject];
-    } else if ([self.mediaObject isKindOfClass:[MLLabel class]]) {
-        [self _configureForFolder:(MLLabel *)self.mediaObject];
-    } else if ([self.mediaObject isKindOfClass:[MLAlbum class]]) {
-        [self _configureForAlbum:(MLAlbum *)self.mediaObject];
-    } else if ([self.mediaObject isKindOfClass:[MLAlbumTrack class]]) {
-        [self _configureForAlbumTrack:(MLAlbumTrack *)self.mediaObject];
-    } else if ([self.mediaObject isKindOfClass:[MLShow class]]) {
-
-        MLShow *mediaObject = (MLShow *)self.mediaObject;
-        [self _configureForShow:mediaObject];
-
-        if ([keyPath isEqualToString:@"computedThumbnail"] || [keyPath isEqualToString:@"episodes"] || !keyPath || (!self.thumbnailView.image && [keyPath isEqualToString:@"editing"])) {
-            self.thumbnailView.image = [VLCThumbnailsCache thumbnailForManagedObject:mediaObject];
-        }
-    } else if ([self.mediaObject isKindOfClass:[MLShowEpisode class]]) {
-        [self _configureForShowEpisode:(MLShowEpisode *)self.mediaObject];
-    }
-    if (![self.mediaObject isKindOfClass:[MLShow class]] && ([keyPath isEqualToString:@"computedThumbnail"] || !keyPath || (!self.thumbnailView.image && [keyPath isEqualToString:@"editing"]))) {
-        self.thumbnailView.image = [VLCThumbnailsCache thumbnailForManagedObject:self.mediaObject];
-    }
-    [self setNeedsDisplay];
-}
-
-#pragma mark - presentation
-
-- (void)_configureForShow:(MLShow *)show
-{
-    self.titleLabel.text = show.name;
-    NSUInteger count = show.episodes.count;
-    NSString *string = @"";
-    if (show.releaseYear)
-        string = [NSString stringWithFormat:@"%@ — ", show.releaseYear];
-    self.subtitleLabel.text = [string stringByAppendingString:[NSString stringWithFormat:(count > 1) ? NSLocalizedString(@"LIBRARY_EPISODES", nil) : NSLocalizedString(@"LIBRARY_SINGLE_EPISODE", nil), count, show.unreadEpisodes.count]];
-    self.mediaIsUnreadView.hidden = YES;
-    self.progressView.hidden = YES;
-    self.folderIconView.image = [UIImage imageNamed:@"tvShow"];
-    self.folderIconView.hidden = NO;
-}
-
-- (void)_configureForAlbumTrack:(MLAlbumTrack *)albumTrack
-{
-    MLFile *anyFileFromTrack = albumTrack.anyFileFromTrack;
-
-    self.subtitleLabel.text = [NSString stringWithFormat:@"%@ — %@ — %@", albumTrack.artist, [NSString stringWithFormat:NSLocalizedString(@"LIBRARY_TRACK_N", nil), albumTrack.trackNumber.intValue], [VLCTime timeWithNumber:[anyFileFromTrack duration]]];
-    self.titleLabel.text = albumTrack.title;
-
-    [self _showPositionOfItem:anyFileFromTrack];
-    self.folderIconView.hidden = YES;
-}
-
-- (void)_configureForShowEpisode:(MLShowEpisode *)showEpisode
-{
-    self.titleLabel.text = showEpisode.name;
-
-    MLFile *anyFileFromEpisode = showEpisode.files.anyObject;
-    if (self.titleLabel.text.length < 1) {
-        self.titleLabel.text = [NSString stringWithFormat:@"S%02dE%02d", showEpisode.seasonNumber.intValue, showEpisode.episodeNumber.intValue];
-        self.subtitleLabel.text = [NSString stringWithFormat:@"%@", [VLCTime timeWithNumber:[anyFileFromEpisode duration]]];
-    } else
-        self.subtitleLabel.text = [NSString stringWithFormat:@"S%02dE%02d — %@", showEpisode.seasonNumber.intValue, showEpisode.episodeNumber.intValue, [VLCTime timeWithNumber:[anyFileFromEpisode duration]]];
-    [self _showPositionOfItem:anyFileFromEpisode];
-    self.folderIconView.hidden = YES;
-}
-
-- (void)_configureForAlbum:(MLAlbum *)album
-{
-    self.titleLabel.text = album.name;
-    MLAlbumTrack *anyTrack = [album.tracks anyObject];
-    NSUInteger count = album.tracks.count;
-    NSMutableString *string = [[NSMutableString alloc] init];
-    if (anyTrack) {
-        if (anyTrack.artist.length > 0) {
-            [string appendString:anyTrack.artist];
-            [string appendString:@" — "];
-        }
-    }
-    [string appendString:[NSString stringWithFormat:(count > 1) ? NSLocalizedString(@"LIBRARY_TRACKS", nil) : NSLocalizedString(@"LIBRARY_SINGLE_TRACK", nil), count]];
-    if (album.releaseYear.length > 0)
-        [string appendFormat:@" — %@", album.releaseYear];
-    self.subtitleLabel.text = string;
-    self.mediaIsUnreadView.hidden = YES;
-    self.progressView.hidden = YES;
-    self.folderIconView.hidden = YES;
-}
-
-- (void)_configureForFolder:(MLLabel *)label
-{
-    self.titleLabel.text = label.name;
-    NSUInteger count = label.files.count;
-    self.subtitleLabel.text = (count == 1) ? NSLocalizedString(@"ONE_FILE", nil) : [NSString stringWithFormat:NSLocalizedString(@"NUM_OF_FILES", nil), count];
-    self.mediaIsUnreadView.hidden = YES;
-    self.progressView.hidden = YES;
-    self.folderIconView.image = [UIImage imageNamed:@"folderIcon"];
-    self.folderIconView.hidden = NO;
-}
-
-- (void)_configureForMLFile:(MLFile *)mediaFile
-{
-    if (mediaFile.isAlbumTrack) {
-        NSString *string = @"";
-        if (mediaFile.albumTrack.artist)
-            string = [NSString stringWithFormat:@"%@ — ", mediaFile.albumTrack.artist];
-        else if (mediaFile.albumTrack.album.name)
-            string = [NSString stringWithFormat:@"%@ — ", mediaFile.albumTrack.artist];
-        self.titleLabel.text = [string stringByAppendingString:(mediaFile.albumTrack.title.length > 1) ? mediaFile.albumTrack.title : mediaFile.title];
-    } else
-        self.titleLabel.text = mediaFile.title;
-
-    if (_editing)
-        self.subtitleLabel.text = [NSString stringWithFormat:@"%@ — %@", [VLCTime timeWithNumber:[mediaFile duration]], [NSByteCountFormatter stringFromByteCount:[mediaFile fileSizeInBytes] countStyle:NSByteCountFormatterCountStyleFile]];
-    else {
-        self.subtitleLabel.text = [NSString stringWithFormat:@"%@", [VLCTime timeWithNumber:[mediaFile duration]]];
-        if (mediaFile.videoTrack) {
-            NSString *width = [[mediaFile videoTrack] valueForKey:@"width"];
-            NSString *height = [[mediaFile videoTrack] valueForKey:@"height"];
-            if (width.intValue > 0 && height.intValue > 0)
-                self.subtitleLabel.text = [self.subtitleLabel.text stringByAppendingFormat:@" — %@x%@", width, height];
-        }
-    }
-    [self _showPositionOfItem:mediaFile];
-    self.folderIconView.hidden = YES;
-}
-
-- (void)_showPositionOfItem:(MLFile *)mediaLibraryFile
-{
-    if (!mediaLibraryFile)
-        return;
-    CGFloat position = mediaLibraryFile.lastPosition.floatValue;
-    CGFloat duration = mediaLibraryFile.duration.floatValue;
-
-    if (position > .05f && position < .95f && (duration * position - duration) < -60000) {
-        [(UITextView*)self.mediaIsUnreadView setText:[NSString stringWithFormat:NSLocalizedString(@"LIBRARY_MINUTES_LEFT", nil), [[VLCTime timeWithInt:(duration * position - duration)] minuteStringValue]]];
-        self.mediaIsUnreadView.hidden = NO;
-    } else if (position != 0.) {
-        self.mediaIsUnreadView.hidden = YES;
-    } else {
-        [(UILabel *)self.mediaIsUnreadView setText:[NSLocalizedString(@"NEW", nil) capitalizedStringWithLocale:[NSLocale currentLocale]]];
-        self.mediaIsUnreadView.hidden = NO;
-    }
-}
-
-- (void)showMetadata:(BOOL)showMeta
-{
-    if (showMeta) {
-        NSMutableString *mediaInfo = [[NSMutableString alloc] init];
-
-        MLFile *theFile;
-        if ([self.mediaObject isKindOfClass:[MLFile class]])
-            theFile = (MLFile *)self.mediaObject;
-        else if ([self.mediaObject isKindOfClass:[MLShowEpisode class]])
-            theFile = [[(MLShowEpisode *)self.mediaObject files]anyObject];
-        else if ([self.mediaObject isKindOfClass:[MLAlbumTrack class]])
-            theFile = [(MLAlbumTrack *)self.mediaObject anyFileFromTrack];
-
-        if (!theFile) {
-            self.metaDataLabel.hidden = YES;
-            return;
-        }
-
-        NSMutableArray *videoTracks = [[NSMutableArray alloc] init];
-        NSMutableArray *audioTracks = [[NSMutableArray alloc] init];
-        NSMutableArray *spuTracks = [[NSMutableArray alloc] init];
-        NSArray *tracks = [[theFile tracks] allObjects];
-        NSUInteger trackCount = tracks.count;
-
-        for (NSUInteger x = 0; x < trackCount; x++) {
-            NSManagedObject *track = tracks[x];
-            NSString *trackEntityName = [[track entity] name];
-            if ([trackEntityName isEqualToString:@"VideoTrackInformation"])
-                [videoTracks addObject:track];
-            else if ([trackEntityName isEqualToString:@"AudioTrackInformation"])
-                [audioTracks addObject:track];
-            else if ([trackEntityName isEqualToString:@"SubtitlesTrackInformation"])
-                [spuTracks addObject:track];
-        }
-
-        /* print video info */
-        trackCount = videoTracks.count;
-
-        if (trackCount > 0) {
-            if (trackCount != 1)
-                [mediaInfo appendFormat:@"%lu video tracks", (unsigned long)trackCount];
-            else
-                [mediaInfo appendString:@"1 video track"];
-
-            [mediaInfo appendString:@" ("];
-            for (NSUInteger x = 0; x < trackCount; x++) {
-                int fourcc = [[videoTracks[x] valueForKey:@"codec"] intValue];
-                if (x != 0)
-                    [mediaInfo appendFormat:@", %4.4s", (char *)&fourcc];
-                else
-                    [mediaInfo appendFormat:@"%4.4s", (char *)&fourcc];
-            }
-            [mediaInfo appendString:@")"];
-        }
-
-        /* print audio info */
-        trackCount = audioTracks.count;
-
-        if (trackCount > 0) {
-            if (mediaInfo.length > 0)
-                [mediaInfo appendString:@"\n\n"];
-
-            if (trackCount != 1)
-                [mediaInfo appendFormat:@"%lu audio tracks", (unsigned long)trackCount];
-            else
-                [mediaInfo appendString:@"1 audio track"];
-
-            [mediaInfo appendString:@":\n"];
-            for (NSUInteger x = 0; x < trackCount; x++) {
-                NSManagedObject *track = audioTracks[x];
-                int fourcc = [[track valueForKey:@"codec"] intValue];
-                if (x != 0)
-                    [mediaInfo appendFormat:@", %4.4s", (char *)&fourcc];
-                else
-                    [mediaInfo appendFormat:@"%4.4s", (char *)&fourcc];
-
-                int channelNumber = [[track valueForKey:@"channelsNumber"] intValue];
-                NSString *language = [track valueForKey:@"language"];
-                int bitrate = [[track valueForKey:@"bitrate"] intValue];
-                if (channelNumber != 0 || language != nil || bitrate > 0) {
-                    [mediaInfo appendString:@" ["];
-
-                    if (bitrate > 0)
-                        [mediaInfo appendFormat:@"%i kbit/s", bitrate / 1024];
-
-                    if (channelNumber > 0) {
-                        if (bitrate > 0)
-                            [mediaInfo appendString:@", "];
-
-                        if (channelNumber == 1)
-                            [mediaInfo appendString:@"MONO"];
-                        else if (channelNumber == 2)
-                            [mediaInfo appendString:@"STEREO"];
-                        else
-                            [mediaInfo appendString:@"MULTI-CHANNEL"];
-                    }
-
-                    if (language != nil) {
-                        if (channelNumber > 0 || bitrate > 0)
-                            [mediaInfo appendString:@", "];
-
-                        [mediaInfo appendString:[language uppercaseString]];
-                    }
-
-                    [mediaInfo appendString:@"]"];
-                }
-            }
-        }
-        [mediaInfo appendString:@"\n\n"];
-
-        /* SPU */
-        trackCount = spuTracks.count;
-        if (trackCount == 0) {
-            NSFileManager *fileManager = [NSFileManager defaultManager];
-            NSString *folderLocation = [theFile.url.path stringByDeletingLastPathComponent];
-            NSArray *allfiles = [fileManager contentsOfDirectoryAtPath:folderLocation error:nil];
-            NSString *fileName = [theFile.path.lastPathComponent stringByDeletingPathExtension];
-            NSUInteger count = allfiles.count;
-            NSString *additionalFilePath;
-            for (unsigned int x = 0; x < count; x++) {
-                additionalFilePath = [NSString stringWithFormat:@"%@", allfiles[x]];
-                if ([additionalFilePath isSupportedSubtitleFormat])
-                    if ([additionalFilePath rangeOfString:fileName].location != NSNotFound)
-                        trackCount ++;
-            }
-        }
-
-        if ((trackCount > 0) || (spuTracks.count > 0)) {
-            if (mediaInfo.length > 0)
-                [mediaInfo appendString:@"\n\n"];
-
-            if (trackCount != 1)
-                [mediaInfo appendFormat:@"%lu subtitles tracks", (unsigned long)trackCount];
-            else
-                [mediaInfo appendString:@"1 subtitles track"];
-
-            if (spuTracks.count > 0) {
-                [mediaInfo appendString:@" ("];
-                for (NSUInteger x = 0; x < trackCount; x++) {
-                    NSString *language = [spuTracks[x] valueForKey:@"language"];
-
-                    if (language) {
-                        if (x != 0)
-                            [mediaInfo appendFormat:@", %@", [language uppercaseString]];
-                        else
-                            [mediaInfo appendString:[language uppercaseString]];
-                    }
-                }
-                [mediaInfo appendString:@")"];
-            }
-        }
-
-        self.metaDataLabel.text = mediaInfo;
-        videoTracks = audioTracks = spuTracks = nil;
-    }
-
-    void (^animationBlock)(void) = ^() {
-        self.metaDataLabel.hidden = !showMeta;
-    };
-
-    void (^completionBlock)(BOOL finished) = ^(BOOL finished) {
-        self.metaDataLabel.hidden = !showMeta;
-    };
-
-    NSTimeInterval animationDuration = .2;
-    [UIView animateWithDuration:animationDuration animations:animationBlock completion:completionBlock];
-}
-
-- (BOOL)showsMetaData
-{
-    return !self.metaDataLabel.hidden;
-}
-
-- (void)thumbnailWasUpdated:(NSNotification *)aNotification
-{
-    self.thumbnailView.contentMode = UIViewContentModeScaleAspectFill;
-    self.thumbnailView.image = [VLCThumbnailsCache thumbnailForManagedObject:self.mediaObject refreshCache:YES];
-}
-
-- (void)prepareForReuse
-{
-    [super prepareForReuse];
-    self.media = nil;
-    self.mediaObject = nil;
-    self.thumbnailView.image = nil;
-    self.titleLabel.text = @"";
-    self.subtitleLabel.text = @"";
-    self.mediaIsUnreadView.hidden = YES;
-    self.progressView.hidden = YES;
-    self.metaDataLabel.hidden = YES;
-    self.folderIconView.hidden = YES;
-    self.isSelectedView.hidden = YES;
-    self.metaDataLabel.hidden = YES;
-    self.mediaIsUnreadView.hidden = YES;
-}
-@end

+ 0 - 35
Sources/VLCPlaylistTableViewCell.h

@@ -1,35 +0,0 @@
-/*****************************************************************************
- * VLCPlaylistTableViewCell.h
- * VLC for iOS
- *****************************************************************************
- * Copyright (c) 2013-2015 VideoLAN. All rights reserved.
- * $Id$
- *
- * Authors: Felix Paul Kühne <fkuehne # videolan.org>
- *          Gleb Pinigin <gpinigin # gmail.com>
- *
- * Refer to the COPYING file of the official project for license.
- *****************************************************************************/
-#import <UIKit/UIKit.h>
-
-@class VLCLinearProgressIndicator;
-@interface VLCPlaylistTableViewCell : UITableViewCell
-
-@property (nonatomic, strong) IBOutlet UILabel *titleLabel;
-@property (nonatomic, strong) IBOutlet UILabel *subtitleLabel;
-@property (nonatomic, strong) IBOutlet UILabel *metaDataLabel;
-@property (nonatomic, strong) IBOutlet UIImageView *thumbnailView;
-@property (nonatomic, strong) IBOutlet VLCLinearProgressIndicator *progressIndicator;
-@property (nonatomic, strong) IBOutlet UIView *mediaIsUnreadView;
-@property (nonatomic, strong) IBOutlet UIImageView *folderIconView;
-
-@property (readonly) BOOL isExpanded;
-
-@property (nonatomic, strong) NSManagedObject *mediaObject;
-
-+ (CGFloat)heightOfCell;
-+ (NSString *)cellIdentifier;
-
-- (void)collapsWithAnimation:(BOOL)animate;
-
-@end

+ 0 - 542
Sources/VLCPlaylistTableViewCell.m

@@ -1,542 +0,0 @@
-/*****************************************************************************
- * VLCPlaylistTableViewCell.m
- * VLC for iOS
- *****************************************************************************
- * Copyright (c) 2013-2015 VideoLAN. All rights reserved.
- * $Id$
- *
- * Authors: Felix Paul Kühne <fkuehne # videolan.org>
- *          Gleb Pinigin <gpinigin # gmail.com>
- *          Carola Nitz <nitz.carola #googlemail.com>
- *
- * Refer to the COPYING file of the official project for license.
- *****************************************************************************/
-
-#import "VLCPlaylistTableViewCell.h"
-#import "VLCLinearProgressIndicator.h"
-#import "VLCThumbnailsCache.h"
-#import "NSString+SupportedMedia.h"
-
-@interface VLCPlaylistTableViewCell ()
-{
-    UILongPressGestureRecognizer *_longPress;
-}
-
-@end
-
-@implementation VLCPlaylistTableViewCell
-
-- (void)awakeFromNib
-{
-    [super awakeFromNib];
-    UIView *bgColorView = [[UIView alloc] init];
-    bgColorView.backgroundColor = [UIColor clearColor];
-    [self setSelectedBackgroundView:bgColorView];
-}
-
-+ (NSString *)cellIdentifier
-{
-    return @"VLCPlaylistTableViewCell";
-}
-
-- (void)dealloc
-{
-    [self _removeObserver];
-}
-
-- (void)prepareForReuse
-{
-    [super prepareForReuse];
-    [self collapsWithAnimation:NO];
-}
-
-- (void)setNeedsDisplay
-{
-    [self collapsWithAnimation:NO];
-    [super setNeedsDisplay];
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
-{
-    [self _updatedDisplayedInformationForKeyPath:keyPath];
-}
-
-- (void)_removeObserver
-{
-    @try {
-        if ([_mediaObject isKindOfClass:[MLLabel class]]) {
-            [_mediaObject removeObserver:self forKeyPath:@"files"];
-            [_mediaObject removeObserver:self forKeyPath:@"name"];
-        } else if ([_mediaObject isKindOfClass:[MLShow class]])
-            [_mediaObject removeObserver:self forKeyPath:@"episodes"];
-        else if ([_mediaObject isKindOfClass:[MLShowEpisode class]]) {
-            [_mediaObject removeObserver:self forKeyPath:@"name"];
-            [_mediaObject removeObserver:self forKeyPath:@"files"];
-            [_mediaObject removeObserver:self forKeyPath:@"artworkURL"];
-            [_mediaObject removeObserver:self forKeyPath:@"unread"];
-        } else if ([_mediaObject isKindOfClass:[MLAlbum class]]) {
-            [_mediaObject removeObserver:self forKeyPath:@"name"];
-            [_mediaObject removeObserver:self forKeyPath:@"tracks"];
-        } else if ([_mediaObject isKindOfClass:[MLAlbumTrack class]]) {
-            [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
-            [_mediaObject removeObserver:self forKeyPath:@"artist"];
-            [_mediaObject removeObserver:self forKeyPath:@"title"];
-            [_mediaObject removeObserver:self forKeyPath:@"files"];
-            MLFile *anyFileFromTrack = [(MLAlbumTrack *)_mediaObject anyFileFromTrack];
-            if (anyFileFromTrack)
-                [anyFileFromTrack removeObserver:self forKeyPath:@"artworkURL"];
-        } else if ([_mediaObject isKindOfClass:[MLFile class]]) {
-            [_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"];
-            [_mediaObject removeObserver:self forKeyPath:@"unread"];
-            [_mediaObject removeObserver:self forKeyPath:@"albumTrackNumber"];
-            [_mediaObject removeObserver:self forKeyPath:@"album"];
-            [_mediaObject removeObserver:self forKeyPath:@"artist"];
-            [_mediaObject removeObserver:self forKeyPath:@"genre"];
-            [(MLFile*)_mediaObject didHide];
-        }
-    }
-    @catch (NSException *exception) {
-        APLog(@"removing observer failed");
-    }
-}
-
-- (void)_addObserver
-{
-    if ([_mediaObject isKindOfClass:[MLLabel class]]) {
-        [_mediaObject addObserver:self forKeyPath:@"files" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"name" options:0 context:nil];
-    } else if ([_mediaObject isKindOfClass:[MLShow class]])
-        [_mediaObject addObserver:self forKeyPath:@"episodes" options:0 context:nil];
-    else if ([_mediaObject isKindOfClass:[MLShowEpisode class]]) {
-        [_mediaObject addObserver:self forKeyPath:@"name" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"files" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"artworkURL" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
-    } else if ([_mediaObject isKindOfClass:[MLAlbum class]]) {
-        [_mediaObject addObserver:self forKeyPath:@"name" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"tracks" options:0 context:nil];
-    } else if ([_mediaObject isKindOfClass:[MLAlbumTrack class]]) {
-        [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"artist" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"title" options:0 context:nil];
-        [_mediaObject addObserver:self forKeyPath:@"files" options:0 context:nil];
-        MLFile *anyFileFromTrack = [(MLAlbumTrack *)_mediaObject anyFileFromTrack];
-        if (anyFileFromTrack)
-            [anyFileFromTrack addObserver:self forKeyPath:@"artworkURL" options:0 context:nil];
-    } else if ([_mediaObject isKindOfClass:[MLFile class]]) {
-        [_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];
-        [_mediaObject addObserver:self forKeyPath:@"unread" options:0 context:nil];
-        [_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];
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(thumbnailWasUpdated:)
-                                                     name:MLFileThumbnailWasUpdated
-                                                   object:nil];
-        [(MLFile*)_mediaObject willDisplay];
-    }
-}
-
-- (void)setMediaObject:(MLFile *)mediaObject
-{
-    if (_mediaObject != mediaObject) {
-        [self _removeObserver];
-
-        _mediaObject = mediaObject;
-        // prevent the cell from recycling the current snap for random contents
-        self.thumbnailView.image = nil;
-
-        [self _addObserver];
-    }
-
-    [self collapsWithAnimation:NO];
-    [self _updatedDisplayedInformationForKeyPath:nil];
-}
-
-- (void)setEditing:(BOOL)editing animated:(BOOL)animated
-{
-    [super setEditing:editing animated:animated];
-    [self _updatedDisplayedInformationForKeyPath:@"editing"];
-
-    if (editing) {
-        if (_longPress)
-            [self removeGestureRecognizer:_longPress];
-    } else {
-        if (!_longPress)
-            _longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longTouchGestureAction:)];
-        [self addGestureRecognizer:_longPress];
-    }
-}
-
-- (void)_updatedDisplayedInformationForKeyPath:(NSString *)keyPath
-{
-    self.thumbnailView.contentMode = UIViewContentModeScaleAspectFill;
-    if ([self.mediaObject isKindOfClass:[MLFile class]]) {
-        [self _configureForMLFile:(MLFile *)self.mediaObject];
-    } else if ([self.mediaObject isKindOfClass:[MLLabel class]]) {
-        [self _configureForFolder:(MLLabel *)self.mediaObject];
-    } else if ([self.mediaObject isKindOfClass:[MLAlbum class]]) {
-        [self _configureForAlbum:(MLAlbum *)self.mediaObject];
-    } else if ([self.mediaObject isKindOfClass:[MLAlbumTrack class]]) {
-        [self _configureForAlbumTrack:(MLAlbumTrack *)self.mediaObject];
-        if ([keyPath isEqualToString:@"computedThumbnail"] || !keyPath || (!self.thumbnailView.image && [keyPath isEqualToString:@"editing"])) {
-            self.thumbnailView.image = [VLCThumbnailsCache thumbnailForManagedObject:self.mediaObject];
-        }
-    } else if ([self.mediaObject isKindOfClass:[MLShow class]]) {
-
-        MLShow *mediaObject = (MLShow *)self.mediaObject;
-        [self _configureForShow:mediaObject];
-
-        if ([keyPath isEqualToString:@"computedThumbnail"] || [keyPath isEqualToString:@"episodes"] || !keyPath || (!self.thumbnailView.image && [keyPath isEqualToString:@"editing"])) {
-            self.thumbnailView.image = [VLCThumbnailsCache thumbnailForManagedObject:mediaObject];
-        }
-    } else if ([self.mediaObject isKindOfClass:[MLShowEpisode class]]) {
-        [self _configureForShowEpisode:(MLShowEpisode *)self.mediaObject];
-    }
-    if (![self.mediaObject isKindOfClass:[MLShow class]] && ([keyPath isEqualToString:@"computedThumbnail"] || !keyPath || (!self.thumbnailView.image && [keyPath isEqualToString:@"editing"]))) {
-        self.thumbnailView.image = [VLCThumbnailsCache thumbnailForManagedObject:self.mediaObject];
-    }
-    [self setNeedsDisplay];
-}
-
-+ (CGFloat)heightOfCell
-{
-    return 90.;
-}
-
-#pragma mark - presentation
-
-- (void)_configureForShow:(MLShow *)show
-{
-    self.titleLabel.text = show.name;
-    NSUInteger count = show.episodes.count;
-    NSString *string = @"";
-    if (show.releaseYear)
-        string = [NSString stringWithFormat:@"%@ — ", show.releaseYear];
-    self.subtitleLabel.text = [string stringByAppendingString:[NSString stringWithFormat:(count > 1) ? NSLocalizedString(@"LIBRARY_EPISODES", nil) : NSLocalizedString(@"LIBRARY_SINGLE_EPISODE", nil), count, show.unreadEpisodes.count]];
-    self.mediaIsUnreadView.hidden = YES;
-    self.progressIndicator.hidden = YES;
-    self.folderIconView.image = [UIImage imageNamed:@"tvShow"];
-    self.folderIconView.hidden = NO;
-}
-
-- (void)_configureForAlbumTrack:(MLAlbumTrack *)albumTrack
-{
-    MLFile *anyFileFromTrack = albumTrack.anyFileFromTrack;
-    self.subtitleLabel.text = [NSString stringWithFormat:@"%@ — %@ — %@", albumTrack.artist, [NSString stringWithFormat:NSLocalizedString(@"LIBRARY_TRACK_N", nil), albumTrack.trackNumber.intValue], [VLCTime timeWithNumber:[anyFileFromTrack duration]]];
-    self.titleLabel.text = albumTrack.title;
-    [self _showPositionOfItem:anyFileFromTrack];
-    self.folderIconView.hidden = YES;
-}
-
-- (void)_configureForShowEpisode:(MLShowEpisode *)showEpisode
-{
-    self.titleLabel.text = showEpisode.name;
-
-    MLFile *anyFileFromEpisode = showEpisode.files.anyObject;
-    if (self.titleLabel.text.length < 1) {
-        self.titleLabel.text = [NSString stringWithFormat:@"S%02dE%02d", showEpisode.seasonNumber.intValue, showEpisode.episodeNumber.intValue];
-        self.subtitleLabel.text = [NSString stringWithFormat:@"%@", [VLCTime timeWithNumber:[anyFileFromEpisode duration]]];
-    } else
-        self.subtitleLabel.text = [NSString stringWithFormat:@"S%02dE%02d — %@", showEpisode.seasonNumber.intValue, showEpisode.episodeNumber.intValue, [VLCTime timeWithNumber:[anyFileFromEpisode duration]]];
-
-    [self _showPositionOfItem:anyFileFromEpisode];
-    self.folderIconView.hidden = YES;
-}
-
-- (void)_configureForAlbum:(MLAlbum *)album
-{
-    self.titleLabel.text = album.name;
-    MLAlbumTrack *anyTrack = [album.tracks anyObject];
-    NSUInteger count = album.tracks.count;
-    NSMutableString *string = [[NSMutableString alloc] init];
-    if (anyTrack) {
-        if (anyTrack.artist.length > 0) {
-            [string appendString:anyTrack.artist];
-            [string appendString:@" — "];
-        }
-    }
-    [string appendString:[NSString stringWithFormat:(count > 1) ? NSLocalizedString(@"LIBRARY_TRACKS", nil) : NSLocalizedString(@"LIBRARY_SINGLE_TRACK", nil), count]];
-    if (album.releaseYear.length > 0)
-        [string appendFormat:@" — %@", album.releaseYear];
-    self.subtitleLabel.text = string;
-    self.mediaIsUnreadView.hidden = YES;
-    self.progressIndicator.hidden = YES;
-    self.folderIconView.hidden = YES;
-}
-
-- (void)_configureForFolder:(MLLabel *)label
-{
-    self.titleLabel.text = label.name;
-    NSUInteger count = label.files.count;
-    self.subtitleLabel.text = (count == 1) ? NSLocalizedString(@"ONE_FILE", nil) : [NSString stringWithFormat:NSLocalizedString(@"NUM_OF_FILES", nil), count];
-    self.mediaIsUnreadView.hidden = YES;
-    self.progressIndicator.hidden = YES;
-    self.folderIconView.image = [UIImage imageNamed:@"folderIcon"];
-    self.folderIconView.hidden = NO;
-}
-
-- (void)_configureForMLFile:(MLFile *)mediaFile
-{
-    if (mediaFile.isAlbumTrack) {
-        NSString *string = @"";
-        if (mediaFile.albumTrack.artist)
-            string = [NSString stringWithFormat:@"%@ — ", mediaFile.albumTrack.artist];
-        else if (mediaFile.albumTrack.album.name)
-            string = [NSString stringWithFormat:@"%@ — ", mediaFile.albumTrack.artist];
-        self.titleLabel.text = [string stringByAppendingString:(mediaFile.albumTrack.title.length > 1) ? mediaFile.albumTrack.title : mediaFile.title];
-    } else
-        self.titleLabel.text = mediaFile.title;
-
-    if (self.isEditing)
-        self.subtitleLabel.text = [NSString stringWithFormat:@"%@ — %@", [VLCTime timeWithNumber:[mediaFile duration]], [NSByteCountFormatter stringFromByteCount:[mediaFile fileSizeInBytes] countStyle:NSByteCountFormatterCountStyleFile]];
-    else {
-        self.subtitleLabel.text = [NSString stringWithFormat:@"%@", [VLCTime timeWithNumber:[mediaFile duration]]];
-        if (mediaFile.videoTrack) {
-            NSString *width = [[mediaFile videoTrack] valueForKey:@"width"];
-            NSString *height = [[mediaFile videoTrack] valueForKey:@"height"];
-            if (width.intValue > 0 && height.intValue > 0)
-                self.subtitleLabel.text = [self.subtitleLabel.text stringByAppendingFormat:@" — %@x%@", width, height];
-        }
-    }
-    [self _showPositionOfItem:mediaFile];
-    self.folderIconView.hidden = YES;
-}
-
-- (void)_showPositionOfItem:(MLFile *)mediaLibraryFile
-{
-    if (!mediaLibraryFile)
-        return;
-    CGFloat position = mediaLibraryFile.lastPosition.floatValue;
-    CGFloat duration = mediaLibraryFile.duration.floatValue;
-
-    if (position > .05f && position < .95f && (duration * position - duration) < -60000) {
-        [(UITextView*)self.mediaIsUnreadView setText:[NSString stringWithFormat:NSLocalizedString(@"LIBRARY_MINUTES_LEFT", nil), [[VLCTime timeWithInt:(duration * position - duration)] minuteStringValue]]];
-        self.mediaIsUnreadView.hidden = NO;
-    } else if (position != 0.) {
-        self.mediaIsUnreadView.hidden = YES;
-    } else {
-        [(UILabel *)self.mediaIsUnreadView setText:[NSLocalizedString(@"NEW", nil) capitalizedStringWithLocale:[NSLocale currentLocale]]];
-        self.mediaIsUnreadView.hidden = NO;
-    }
-}
-
-- (void)longTouchGestureAction:(UIGestureRecognizer *)recognizer
-{
-    _isExpanded = YES;
-    CGRect frame = self.frame;
-    frame.size.height = 180.;
-    BOOL metaHidden = NO;
-
-    MLFile *theFile;
-    if ([self.mediaObject isKindOfClass:[MLFile class]])
-        theFile = (MLFile *)self.mediaObject;
-    else if ([self.mediaObject isKindOfClass:[MLShowEpisode class]])
-        theFile = [(MLShowEpisode *)self.mediaObject anyFileFromEpisode];
-    else if ([self.mediaObject isKindOfClass:[MLAlbumTrack class]])
-        theFile = [(MLAlbumTrack *)self.mediaObject anyFileFromTrack];
-
-    NSMutableString *mediaInfo = [[NSMutableString alloc] init];
-
-    if (theFile) {
-        NSMutableArray *videoTracks = [[NSMutableArray alloc] init];
-        NSMutableArray *audioTracks = [[NSMutableArray alloc] init];
-        NSMutableArray *spuTracks = [[NSMutableArray alloc] init];
-        NSArray *tracks = [[theFile tracks] allObjects];
-        NSUInteger trackCount = tracks.count;
-
-        for (NSUInteger x = 0; x < trackCount; x++) {
-            NSManagedObject *track = tracks[x];
-            NSString *trackEntityName = [[track entity] name];
-            if ([trackEntityName isEqualToString:@"VideoTrackInformation"])
-                [videoTracks addObject:track];
-            else if ([trackEntityName isEqualToString:@"AudioTrackInformation"])
-                [audioTracks addObject:track];
-            else if ([trackEntityName isEqualToString:@"SubtitlesTrackInformation"])
-                [spuTracks addObject:track];
-        }
-
-        /* print video info */
-        trackCount = videoTracks.count;
-
-        if (trackCount > 0) {
-            if (trackCount != 1)
-                [mediaInfo appendFormat:@"%lu video tracks", (unsigned long)trackCount];
-            else
-                [mediaInfo appendString:@"1 video track"];
-
-            [mediaInfo appendString:@" ("];
-            for (NSUInteger x = 0; x < trackCount; x++) {
-                int fourcc = [[videoTracks[x] valueForKey:@"codec"] intValue];
-                if (x != 0)
-                    [mediaInfo appendFormat:@", %4.4s", (char *)&fourcc];
-                else
-                    [mediaInfo appendFormat:@"%4.4s", (char *)&fourcc];
-            }
-            [mediaInfo appendString:@")"];
-        }
-
-        /* print audio info */
-        trackCount = audioTracks.count;
-
-        if (trackCount > 0) {
-            if (mediaInfo.length > 0)
-                [mediaInfo appendString:@"\n\n"];
-
-            if (trackCount != 1)
-                [mediaInfo appendFormat:@"%lu audio tracks", (unsigned long)trackCount];
-            else
-                [mediaInfo appendString:@"1 audio track"];
-
-            [mediaInfo appendString:@":\n"];
-            for (NSUInteger x = 0; x < trackCount; x++) {
-                NSManagedObject *track = audioTracks[x];
-                int fourcc = [[track valueForKey:@"codec"] intValue];
-                if (x != 0)
-                    [mediaInfo appendFormat:@", %4.4s", (char *)&fourcc];
-                else
-                    [mediaInfo appendFormat:@"%4.4s", (char *)&fourcc];
-
-                int channelNumber = [[track valueForKey:@"channelsNumber"] intValue];
-                NSString *language = [track valueForKey:@"language"];
-                int bitrate = [[track valueForKey:@"bitrate"] intValue];
-                if (channelNumber != 0 || language != nil || bitrate > 0) {
-                    [mediaInfo appendString:@" ["];
-
-                    if (bitrate > 0)
-                        [mediaInfo appendFormat:@"%i kbit/s", bitrate / 1024];
-
-                    if (channelNumber > 0) {
-                        if (bitrate > 0)
-                            [mediaInfo appendString:@", "];
-
-                        if (channelNumber == 1)
-                            [mediaInfo appendString:@"MONO"];
-                        else if (channelNumber == 2)
-                            [mediaInfo appendString:@"STEREO"];
-                        else
-                            [mediaInfo appendString:@"MULTI-CHANNEL"];
-                    }
-
-                    if (language != nil) {
-                        if (channelNumber > 0 || bitrate > 0)
-                            [mediaInfo appendString:@", "];
-
-                        [mediaInfo appendString:[language uppercaseString]];
-                    }
-
-                    [mediaInfo appendString:@"]"];
-                }
-            }
-        }
-
-        /* SPU */
-        trackCount = spuTracks.count;
-        if (trackCount == 0) {
-            NSFileManager *fileManager = [NSFileManager defaultManager];
-            NSString *folderLocation = [theFile.url.path stringByDeletingLastPathComponent];
-            NSArray *allfiles = [fileManager contentsOfDirectoryAtPath:folderLocation error:nil];
-            NSString *fileName = [theFile.path.lastPathComponent stringByDeletingPathExtension];
-            NSUInteger count = allfiles.count;
-            NSString *additionalFilePath;
-            for (unsigned int x = 0; x < count; x++) {
-                additionalFilePath = [NSString stringWithFormat:@"%@", allfiles[x]];
-                if ([additionalFilePath isSupportedSubtitleFormat])
-                    if ([additionalFilePath rangeOfString:fileName].location != NSNotFound)
-                        trackCount ++;
-            }
-        }
-
-        if ((trackCount > 0) || (spuTracks.count > 0)) {
-            if (mediaInfo.length > 0)
-                [mediaInfo appendString:@"\n\n"];
-
-            if (trackCount != 1)
-                [mediaInfo appendFormat:@"%lu subtitles tracks", (unsigned long)trackCount];
-            else
-                [mediaInfo appendString:@"1 subtitles track"];
-            
-            if (spuTracks.count > 0) {
-                [mediaInfo appendString:@" ("];
-                for (NSUInteger x = 0; x < trackCount; x++) {
-                    NSString *language = [spuTracks[x] valueForKey:@"language"];
-
-                    if (language) {
-                        if (x != 0)
-                            [mediaInfo appendFormat:@", %@", [language uppercaseString]];
-                        else
-                            [mediaInfo appendString:[language uppercaseString]];
-                    }
-                }
-                [mediaInfo appendString:@")"];
-            }
-        }
-
-        self.metaDataLabel.text = mediaInfo;
-        [self.metaDataLabel sizeToFit];
-        [self.metaDataLabel setFrame:CGRectMake((self.frame.size.width - self.metaDataLabel.frame.size.width)/2, self.metaDataLabel.frame.origin.y, self.metaDataLabel.frame.size.width, self.metaDataLabel.frame.size.height)];
-        videoTracks = audioTracks = spuTracks = nil;
-    } else
-        self.metaDataLabel.text = @"";
-
-    void (^animationBlock)(void) = ^() {
-        self.frame = frame;
-        self.metaDataLabel.hidden = metaHidden;
-    };
-
-    void (^completionBlock)(BOOL finished) = ^(BOOL finished) {
-        self.frame = frame;
-        self.metaDataLabel.hidden = metaHidden;
-    };
-
-    NSTimeInterval animationDuration = .2;
-    [UIView animateWithDuration:animationDuration animations:animationBlock completion:completionBlock];
-}
-
-- (void)collapsWithAnimation:(BOOL)animate
-{
-    _isExpanded = NO;
-    if (!animate) {
-        self.metaDataLabel.hidden = YES;
-        CGRect frame = self.frame;
-        frame.size.height = 90.;
-        self.frame = frame;
-        return;
-    }
-
-    CGRect frame = self.frame;
-    frame.size.height = 90.;
-    BOOL metaHidden = YES;
-
-    void (^animationBlock)(void) = ^() {
-        self.frame = frame;
-        self.metaDataLabel.hidden = metaHidden;
-    };
-
-    void (^completionBlock)(BOOL finished) = ^(BOOL finished) {
-        self.frame = frame;
-        self.metaDataLabel.hidden = metaHidden;
-    };
-
-    NSTimeInterval animationDuration = .2;
-    [UIView animateWithDuration:animationDuration animations:animationBlock completion:completionBlock];
-}
-
-- (void)thumbnailWasUpdated:(NSNotification *)aNotification
-{
-    self.thumbnailView.contentMode = UIViewContentModeScaleAspectFill;
-    self.thumbnailView.image = [VLCThumbnailsCache thumbnailForManagedObject:self.mediaObject refreshCache:YES];
-}
-
-@end

+ 0 - 2
VLC-iOS-Bridging-Header.h

@@ -17,8 +17,6 @@
 #import "VLCPlaybackController+MediaLibrary.h"
 #import "VLCPlaybackNavigationController.h"
 #import "VLCPlayerDisplayController.h"
-#import "VLCPlaylistTableViewCell.h"
-#import "VLCPlaylistCollectionViewCell.h"
 #import "VLCServerListViewController.h"
 #import "VLCSettingsController.h"
 #import "VLCWiFiUploadTableViewCell.h"

+ 12 - 20
VLC.xcodeproj/project.pbxproj

@@ -59,6 +59,9 @@
 		41EB91D71F7BE6F500821AA5 /* VLCRemoteControlService.m in Sources */ = {isa = PBXBuildFile; fileRef = 417D7F5F1F7BA26200DDF36A /* VLCRemoteControlService.m */; };
 		41EB91DD1F7BFF8500821AA5 /* VLCMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 41EB91DC1F7BFF8400821AA5 /* VLCMetadata.m */; };
 		41EB91DE1F7BFF8500821AA5 /* VLCMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 41EB91DC1F7BFF8400821AA5 /* VLCMetadata.m */; };
+		41EC28E32136D905004BCF0F /* BaseCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41EC28E22136D905004BCF0F /* BaseCollectionViewCell.swift */; };
+		41EC28E52136DD41004BCF0F /* MovieCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41EC28E42136DD41004BCF0F /* MovieCollectionViewCell.swift */; };
+		41EC28E92136DE46004BCF0F /* MovieCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 41EC28E82136DE46004BCF0F /* MovieCollectionViewCell.xib */; };
 		41F5C0781F41ED55005EB9CB /* VLCLibrarySearchDisplayDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 41F5C0771F41ED55005EB9CB /* VLCLibrarySearchDisplayDataSource.m */; };
 		41F9BC7C1F4F20E400268461 /* VLCTrackSelectorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 41F9BC7B1F4F20E400268461 /* VLCTrackSelectorView.m */; };
 		41FCD2F820B565B600660AAB /* VLCAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41FCD2F720B565B500660AAB /* VLCAlertViewController.swift */; };
@@ -109,8 +112,6 @@
 		7D32B384185E293D006CA474 /* Raleway.woff in Resources */ = {isa = PBXBuildFile; fileRef = 7D32B383185E293D006CA474 /* Raleway.woff */; };
 		7D37848F183A98B6009EE944 /* VLCMovieViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D37848E183A98B6009EE944 /* VLCMovieViewController.m */; };
 		7D378492183A98BF009EE944 /* VLCExternalDisplayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D378491183A98BF009EE944 /* VLCExternalDisplayController.m */; };
-		7D378499183A98D1009EE944 /* VLCPlaylistCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D378494183A98D1009EE944 /* VLCPlaylistCollectionViewCell.m */; };
-		7D37849A183A98D1009EE944 /* VLCPlaylistTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D378496183A98D1009EE944 /* VLCPlaylistTableViewCell.m */; };
 		7D37849E183A98DD009EE944 /* VLCThumbnailsCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D37849D183A98DD009EE944 /* VLCThumbnailsCache.m */; };
 		7D3784A1183A98EB009EE944 /* VLCBugreporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D3784A0183A98EB009EE944 /* VLCBugreporter.m */; };
 		7D3784A6183A98F5009EE944 /* VLCAboutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D3784A3183A98F5009EE944 /* VLCAboutViewController.m */; };
@@ -193,8 +194,6 @@
 		7DBBF19B183AB4300009A339 /* VLCCloudStorageTableViewCell~iphone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DBBF186183AB4300009A339 /* VLCCloudStorageTableViewCell~iphone.xib */; };
 		7DBBF19D183AB4300009A339 /* VLCCloudStorageTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DBBF188183AB4300009A339 /* VLCCloudStorageTableViewController.xib */; };
 		7DBBF19E183AB4300009A339 /* VLCEmptyLibraryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DBBF189183AB4300009A339 /* VLCEmptyLibraryView.xib */; };
-		7DBBF1A0183AB4300009A339 /* VLCPlaylistCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DBBF18B183AB4300009A339 /* VLCPlaylistCollectionViewCell.xib */; };
-		7DBBF1A1183AB4300009A339 /* VLCPlaylistTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DBBF18C183AB4300009A339 /* VLCPlaylistTableViewCell.xib */; };
 		7DBBF1A4183AB4300009A339 /* VLCNetworkListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DBBF18F183AB4300009A339 /* VLCNetworkListCell.xib */; };
 		7DBBF1A5183AB4300009A339 /* VLCMovieViewController~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DBBF190183AB4300009A339 /* VLCMovieViewController~ipad.xib */; };
 		7DBBF1A6183AB4300009A339 /* VLCMovieViewController~iphone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DBBF191183AB4300009A339 /* VLCMovieViewController~iphone.xib */; };
@@ -559,6 +558,9 @@
 		41E6BECC207E64E900E158BA /* RemoteNetworkCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteNetworkCell.swift; sourceTree = "<group>"; };
 		41EB91DB1F7BFF8400821AA5 /* VLCMetadata.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCMetadata.h; sourceTree = "<group>"; };
 		41EB91DC1F7BFF8400821AA5 /* VLCMetadata.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCMetadata.m; sourceTree = "<group>"; };
+		41EC28E22136D905004BCF0F /* BaseCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BaseCollectionViewCell.swift; path = Sources/BaseCollectionViewCell.swift; sourceTree = "<group>"; };
+		41EC28E42136DD41004BCF0F /* MovieCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MovieCollectionViewCell.swift; path = SharedSources/MovieCollectionViewCell.swift; sourceTree = "<group>"; };
+		41EC28E82136DE46004BCF0F /* MovieCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MovieCollectionViewCell.xib; path = Sources/MovieCollectionViewCell.xib; sourceTree = "<group>"; };
 		41F5C0761F41ED55005EB9CB /* VLCLibrarySearchDisplayDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = VLCLibrarySearchDisplayDataSource.h; path = Sources/VLCLibrarySearchDisplayDataSource.h; sourceTree = SOURCE_ROOT; };
 		41F5C0771F41ED55005EB9CB /* VLCLibrarySearchDisplayDataSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = VLCLibrarySearchDisplayDataSource.m; path = Sources/VLCLibrarySearchDisplayDataSource.m; sourceTree = SOURCE_ROOT; };
 		41F9BC7A1F4F20E400268461 /* VLCTrackSelectorView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = VLCTrackSelectorView.h; path = Sources/VLCTrackSelectorView.h; sourceTree = SOURCE_ROOT; };
@@ -694,10 +696,6 @@
 		7D37848E183A98B6009EE944 /* VLCMovieViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCMovieViewController.m; path = Sources/VLCMovieViewController.m; sourceTree = SOURCE_ROOT; };
 		7D378490183A98BF009EE944 /* VLCExternalDisplayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCExternalDisplayController.h; path = Sources/VLCExternalDisplayController.h; sourceTree = SOURCE_ROOT; };
 		7D378491183A98BF009EE944 /* VLCExternalDisplayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCExternalDisplayController.m; path = Sources/VLCExternalDisplayController.m; sourceTree = SOURCE_ROOT; };
-		7D378493183A98D1009EE944 /* VLCPlaylistCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCPlaylistCollectionViewCell.h; path = Sources/VLCPlaylistCollectionViewCell.h; sourceTree = SOURCE_ROOT; };
-		7D378494183A98D1009EE944 /* VLCPlaylistCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCPlaylistCollectionViewCell.m; path = Sources/VLCPlaylistCollectionViewCell.m; sourceTree = SOURCE_ROOT; };
-		7D378495183A98D1009EE944 /* VLCPlaylistTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCPlaylistTableViewCell.h; path = Sources/VLCPlaylistTableViewCell.h; sourceTree = SOURCE_ROOT; };
-		7D378496183A98D1009EE944 /* VLCPlaylistTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCPlaylistTableViewCell.m; path = Sources/VLCPlaylistTableViewCell.m; sourceTree = SOURCE_ROOT; };
 		7D37849C183A98DD009EE944 /* VLCThumbnailsCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCThumbnailsCache.h; path = Sources/VLCThumbnailsCache.h; sourceTree = SOURCE_ROOT; };
 		7D37849D183A98DD009EE944 /* VLCThumbnailsCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCThumbnailsCache.m; path = Sources/VLCThumbnailsCache.m; sourceTree = SOURCE_ROOT; };
 		7D37849F183A98EB009EE944 /* VLCBugreporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCBugreporter.h; path = Sources/VLCBugreporter.h; sourceTree = SOURCE_ROOT; };
@@ -832,8 +830,6 @@
 		7DBBF186183AB4300009A339 /* VLCCloudStorageTableViewCell~iphone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "VLCCloudStorageTableViewCell~iphone.xib"; path = "Resources/VLCCloudStorageTableViewCell~iphone.xib"; sourceTree = SOURCE_ROOT; };
 		7DBBF188183AB4300009A339 /* VLCCloudStorageTableViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCCloudStorageTableViewController.xib; path = Resources/VLCCloudStorageTableViewController.xib; sourceTree = SOURCE_ROOT; };
 		7DBBF189183AB4300009A339 /* VLCEmptyLibraryView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCEmptyLibraryView.xib; path = Resources/VLCEmptyLibraryView.xib; sourceTree = SOURCE_ROOT; };
-		7DBBF18B183AB4300009A339 /* VLCPlaylistCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCPlaylistCollectionViewCell.xib; path = Resources/VLCPlaylistCollectionViewCell.xib; sourceTree = SOURCE_ROOT; };
-		7DBBF18C183AB4300009A339 /* VLCPlaylistTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCPlaylistTableViewCell.xib; path = Resources/VLCPlaylistTableViewCell.xib; sourceTree = SOURCE_ROOT; };
 		7DBBF18F183AB4300009A339 /* VLCNetworkListCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCNetworkListCell.xib; path = Resources/VLCNetworkListCell.xib; sourceTree = SOURCE_ROOT; };
 		7DBBF190183AB4300009A339 /* VLCMovieViewController~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "VLCMovieViewController~ipad.xib"; path = "Resources/VLCMovieViewController~ipad.xib"; sourceTree = SOURCE_ROOT; };
 		7DBBF191183AB4300009A339 /* VLCMovieViewController~iphone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "VLCMovieViewController~iphone.xib"; path = "Resources/VLCMovieViewController~iphone.xib"; sourceTree = SOURCE_ROOT; };
@@ -1525,10 +1521,6 @@
 				8DE1877F2105DA2B00A091D2 /* MediaViewControllers */,
 				418B145820179E50000447AA /* VLCDragAndDropManager.swift */,
 				41251ECB1FD0C5C100099110 /* VLC-iOS-Bridging-Header.h */,
-				7D378493183A98D1009EE944 /* VLCPlaylistCollectionViewCell.h */,
-				7D378494183A98D1009EE944 /* VLCPlaylistCollectionViewCell.m */,
-				7D378495183A98D1009EE944 /* VLCPlaylistTableViewCell.h */,
-				7D378496183A98D1009EE944 /* VLCPlaylistTableViewCell.m */,
 				CADFAD06207D128200103F33 /* VLCEmptyLibraryView.h */,
 				CADFAD07207D128200103F33 /* VLCEmptyLibraryView.m */,
 				8F91EC77195CEC7900F5BCBA /* VLCOpenInActivity.h */,
@@ -1538,6 +1530,9 @@
 				41701545209B36E800802E44 /* VLCPagingViewController.swift */,
 				41D7DD0420C1853E00AD94F6 /* ButtonBarView.swift */,
 				41D7DD2620C3060300AD94F6 /* PagerStripViewController.swift */,
+				41EC28E22136D905004BCF0F /* BaseCollectionViewCell.swift */,
+				41EC28E42136DD41004BCF0F /* MovieCollectionViewCell.swift */,
+				41EC28E82136DE46004BCF0F /* MovieCollectionViewCell.xib */,
 			);
 			name = "Everything Playlist";
 			sourceTree = "<group>";
@@ -1603,8 +1598,6 @@
 			isa = PBXGroup;
 			children = (
 				7DBBF189183AB4300009A339 /* VLCEmptyLibraryView.xib */,
-				7DBBF18B183AB4300009A339 /* VLCPlaylistCollectionViewCell.xib */,
-				7DBBF18C183AB4300009A339 /* VLCPlaylistTableViewCell.xib */,
 				419D7F041F54176900AF69A2 /* VLCTimeNavigationTitleView.xib */,
 			);
 			name = Library;
@@ -2786,6 +2779,7 @@
 				7D1516461868D7E0004B18F3 /* VLCFirstStepsSixthPageViewController~iphone.xib in Resources */,
 				41273A3D1A955C4100A2EF77 /* VLCMigrationViewController.xib in Resources */,
 				41D7DD2120C1FC2D00AD94F6 /* VLCLabelCell.xib in Resources */,
+				41EC28E92136DE46004BCF0F /* MovieCollectionViewCell.xib in Resources */,
 				7DBBF19D183AB4300009A339 /* VLCCloudStorageTableViewController.xib in Resources */,
 				7D9289761877459B009108FD /* VLCFirstStepsThirdPageViewController~iphone.xib in Resources */,
 				7DBBF19E183AB4300009A339 /* VLCEmptyLibraryView.xib in Resources */,
@@ -2793,7 +2787,6 @@
 				7D63C19518774E0100BD5256 /* VLCFirstStepsThirdPageViewController~ipad.xib in Resources */,
 				7D9870651A3E03D5009CF27D /* papasscode_background@2x.png in Resources */,
 				7D5B26641D6350BF00FE7B4D /* gradient-cell.png in Resources */,
-				7DBBF1A1183AB4300009A339 /* VLCPlaylistTableViewCell.xib in Resources */,
 				7D63C19718774F1000BD5256 /* VLCFirstStepsFourthPageViewController~ipad.xib in Resources */,
 				7DBBF1A5183AB4300009A339 /* VLCMovieViewController~ipad.xib in Resources */,
 				26F1BFD01A770408001DF30C /* libMediaVLC.xml in Resources */,
@@ -2802,7 +2795,6 @@
 				7D27EC2C19DF310300EF0370 /* VLCFirstStepsSecondPageViewController~iphone.xib in Resources */,
 				7AC8629D1765DC560011611A /* style.css in Resources */,
 				7D27EC2B19DF310300EF0370 /* VLCFirstStepsSecondPageViewController~ipad.xib in Resources */,
-				7DBBF1A0183AB4300009A339 /* VLCPlaylistCollectionViewCell.xib in Resources */,
 				417CDA241A48D1F300D9ACE7 /* VLCCloudServicesTableViewController.xib in Resources */,
 				7D9870671A3E03D5009CF27D /* papasscode_failed_bg@2x.png in Resources */,
 				7DDFF4251BDFD23300913BD1 /* VLCCone512x512.png in Resources */,
@@ -3160,6 +3152,7 @@
 				DD3EFF311BDEBCE500B68579 /* VLCNetworkServerBrowserFTP.m in Sources */,
 				8DF966EF211C643D00D0FCD6 /* PlaylistModel.swift in Sources */,
 				9BADAF45185FBD9D00108BD8 /* VLCFrostedGlasView.m in Sources */,
+				41EC28E32136D905004BCF0F /* BaseCollectionViewCell.swift in Sources */,
 				DDC10BE41AEE8EA700890DC3 /* VLCTimeNavigationTitleView.m in Sources */,
 				DD870E9A1CEF929A00BBD4FE /* VLCNetworkLoginViewFieldCell.m in Sources */,
 				4195747D206A92ED00393A42 /* RemoteNetworkDataSource.swift in Sources */,
@@ -3192,13 +3185,11 @@
 				8DE1888C210B459000A091D2 /* ShowEpisodeModel.swift in Sources */,
 				4170152C209A1D3600802E44 /* MediaViewController.swift in Sources */,
 				41F9BC7C1F4F20E400268461 /* VLCTrackSelectorView.m in Sources */,
-				7D378499183A98D1009EE944 /* VLCPlaylistCollectionViewCell.m in Sources */,
 				DD8F84311B00EB3B0009138A /* VLCPlaybackController+MediaLibrary.m in Sources */,
 				418B144720179C00000447AA /* MediaCategoryViewController.swift in Sources */,
 				41EB91DD1F7BFF8500821AA5 /* VLCMetadata.m in Sources */,
 				41DFC6C62100BAAF00EEC9E3 /* VLCDocumentClass.swift in Sources */,
 				DD3EFF551BDEBCE500B68579 /* VLCLocalNetworkServiceBrowserDSM.m in Sources */,
-				7D37849A183A98D1009EE944 /* VLCPlaylistTableViewCell.m in Sources */,
 				8DD651C4208F786F0052EE68 /* VLCActionSheetSectionHeader.swift in Sources */,
 				7D37849E183A98DD009EE944 /* VLCThumbnailsCache.m in Sources */,
 				DD3EFF411BDEBCE500B68579 /* VLCNetworkServerBrowserSharedLibrary.m in Sources */,
@@ -3231,6 +3222,7 @@
 				4144156C20ECE6330078EC37 /* VLCFileServerSectionTableHeaderView.swift in Sources */,
 				7D1276621AADA0E600F0260C /* VLCMultiSelectionMenuView.m in Sources */,
 				416DACB720B6DB9A001BC75D /* VLCPlayingExternallyView.swift in Sources */,
+				41EC28E52136DD41004BCF0F /* MovieCollectionViewCell.swift in Sources */,
 				7D3784C8183A9972009EE944 /* NSString+SupportedMedia.m in Sources */,
 				417E68B91F321EFF00DB9BB2 /* VLCActivityViewControllerVendor.m in Sources */,
 				DD3EFF5B1BDEBCE500B68579 /* VLCNetworkServerBrowserUPnP.m in Sources */,