Sfoglia il codice sorgente

Sort: Handle ascending and descending sort

(closes #414)
Soomin Lee 6 anni fa
parent
commit
aea6ce4b46

+ 3 - 0
Resources/en.lproj/Localizable.strings

@@ -344,6 +344,9 @@
 "BUTTON_SORT" = "Sort";
 "BUTTON_SORT_HINT" = "Display sort action sheet";
 "HEADER_TITLE_SORT" = "Sort by";
+"DESCENDING_LABEL" = "Descending Order";
+"DESCENDING_SWITCH_LABEL" = "Ascending or descending order";
+"DESCENDING_SWITCH_HINT" = "Sort context in ascending or descending order";
 
 // VLCMediaLibraryKit - Sorting Criteria
 

+ 3 - 2
SharedSources/MediaLibraryModel/AlbumModel.swift

@@ -41,9 +41,10 @@ class AlbumModel: MLBaseModel {
 
 // MARK: - Sort
 extension AlbumModel {
-    func sort(by criteria: VLCMLSortingCriteria) {
-        files = medialibrary.albums(sortingCriteria: criteria)
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool) {
+        files = medialibrary.albums(sortingCriteria: criteria, desc: desc)
         sortModel.currentSort = criteria
+        sortModel.desc = desc
         updateView?()
     }
 }

+ 3 - 2
SharedSources/MediaLibraryModel/ArtistModel.swift

@@ -41,9 +41,10 @@ class ArtistModel: MLBaseModel {
 
 // MARK: - Sort
 extension ArtistModel {
-    func sort(by criteria: VLCMLSortingCriteria) {
-        files = medialibrary.artists(sortingCriteria: criteria)
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool) {
+        files = medialibrary.artists(sortingCriteria: criteria, desc: desc)
         sortModel.currentSort = criteria
+        sortModel.desc = desc
         updateView?()
     }
 }

+ 3 - 2
SharedSources/MediaLibraryModel/GenreModel.swift

@@ -58,9 +58,10 @@ extension GenreModel: MediaLibraryObserver {
 
 // MARK: - Sort
 extension GenreModel {
-    func sort(by criteria: VLCMLSortingCriteria) {
-        files = medialibrary.genres(sortingCriteria: criteria)
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool) {
+        files = medialibrary.genres(sortingCriteria: criteria, desc: desc)
         sortModel.currentSort = criteria
+        sortModel.desc = desc
         updateView?()
     }
 }

+ 3 - 3
SharedSources/MediaLibraryModel/MediaLibraryBaseModel.swift

@@ -24,7 +24,7 @@ protocol MediaLibraryBaseModel {
 
     func append(_ item: VLCMLObject)
     func delete(_ items: [VLCMLObject])
-    func sort(by criteria: VLCMLSortingCriteria)
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool)
 }
 
 protocol MLBaseModel: AnyObject, MediaLibraryBaseModel {
@@ -43,7 +43,7 @@ protocol MLBaseModel: AnyObject, MediaLibraryBaseModel {
     func append(_ item: MLType)
     // FIXME: Ideally items should be MLType but Swift isn't happy so it will always fail
     func delete(_ items: [VLCMLObject])
-    func sort(by criteria: VLCMLSortingCriteria)
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool)
 }
 
 extension MLBaseModel {
@@ -59,7 +59,7 @@ extension MLBaseModel {
         fatalError()
     }
 
-    func sort(by criteria: VLCMLSortingCriteria) {
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool) {
         fatalError()
     }
 }

+ 3 - 2
SharedSources/MediaLibraryModel/PlaylistModel.swift

@@ -60,9 +60,10 @@ class PlaylistModel: MLBaseModel {
 
 // MARK: - Sort
 extension PlaylistModel {
-    func sort(by criteria: VLCMLSortingCriteria) {
-        files = medialibrary.playlists(sortingCriteria: criteria)
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool) {
+        files = medialibrary.playlists(sortingCriteria: criteria, desc: desc)
         sortModel.currentSort = criteria
+        sortModel.desc = desc
         updateView?()
     }
 }

+ 1 - 1
SharedSources/MediaLibraryModel/ShowEpisodeModel.swift

@@ -41,7 +41,7 @@ class ShowEpisodeModel: MediaModel {
 // MARK: - Sort
 
 extension ShowEpisodeModel {
-    func sort(by criteria: VLCMLSortingCriteria) {
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool) {
         // Currently no show specific getter on medialibrary.
     }
 }

+ 5 - 2
SharedSources/MediaLibraryModel/TrackModel.swift

@@ -34,10 +34,13 @@ class TrackModel: MediaModel {
 // MARK: - Sort
 
 extension TrackModel {
-    func sort(by criteria: VLCMLSortingCriteria) {
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool) {
         // FIXME: Currently if sorted by name, the files are sorted by filename but displaying title
-        files = medialibrary.media(ofType: .audio, sortingCriteria: criteria)
+        files = medialibrary.media(ofType: .audio,
+                                   sortingCriteria: criteria,
+                                   desc: desc)
         sortModel.currentSort = criteria
+        sortModel.desc = desc
         updateView?()
     }
 }

+ 5 - 2
SharedSources/MediaLibraryModel/VideoModel.swift

@@ -43,9 +43,12 @@ extension VideoModel: EditableMLModel {
 // MARK: - Sort
 
 extension VideoModel {
-    func sort(by criteria: VLCMLSortingCriteria) {
-        files = medialibrary.media(ofType: .video, sortingCriteria: criteria)
+    func sort(by criteria: VLCMLSortingCriteria, desc: Bool) {
+        files = medialibrary.media(ofType: .video,
+                                   sortingCriteria: criteria,
+                                   desc: desc)
         sortModel.currentSort = criteria
+        sortModel.desc = desc
         updateView?()
     }
 }

+ 14 - 1
Sources/ActionSheet/ActionSheet.swift

@@ -118,6 +118,19 @@ class ActionSheet: UIViewController {
 
     // MARK: UIViewController
 
+    init () {
+        super.init(nibName: nil, bundle: nil)
+    }
+
+    init(header: ActionSheetSectionHeader) {
+        super.init(nibName: nil, bundle: nil)
+        headerView = header
+    }
+
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
     override func viewDidLoad() {
         super.viewDidLoad()
         
@@ -202,7 +215,7 @@ class ActionSheet: UIViewController {
 private extension ActionSheet {
     private func setuplHeaderViewConstraints() {
         NSLayoutConstraint.activate([
-            headerView.heightAnchor.constraint(equalToConstant: cellHeight),
+            headerView.heightAnchor.constraint(equalToConstant: headerView.cellHeight),
             headerView.widthAnchor.constraint(equalTo: view.widthAnchor),
             ])
     }

+ 7 - 4
Sources/ActionSheet/ActionSheetSectionHeader.swift

@@ -13,9 +13,14 @@ class ActionSheetSectionHeader: UIView {
 
     static let identifier = "VLCActionSheetSectionHeader"
 
+    var cellHeight: CGFloat {
+        return 50
+    }
+
     let title: UILabel = {
         let title = UILabel()
-        title.font = UIFont.boldSystemFont(ofSize: 13)
+        title.font = UIFont.boldSystemFont(ofSize: 17)
+        title.textColor = PresentationTheme.current.colors.cellTextColor
         title.translatesAutoresizingMaskIntoConstraints = false
         return title
     }()
@@ -62,9 +67,7 @@ class ActionSheetSectionHeader: UIView {
         addSubview(title)
         NSLayoutConstraint.activate([
             title.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 20),
-            title.centerYAnchor.constraint(equalTo: centerYAnchor),
-            title.centerXAnchor.constraint(equalTo: centerXAnchor),
-            title.topAnchor.constraint(equalTo: topAnchor)
+            title.topAnchor.constraint(equalTo: topAnchor, constant: 20)
         ])
     }
 }

+ 82 - 0
Sources/ActionSheet/ActionSheetSortSectionHeader.swift

@@ -0,0 +1,82 @@
+/*****************************************************************************
+ * ActionSheetSortSectionHeader.swift
+ *
+ * Copyright © 2019 VLC authors and VideoLAN
+ *
+ * Authors: Soomin Lee <bubu@mikan.io>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+protocol ActionSheetSortSectionHeaderDelegate: class {
+    func actionSheetSortSectionHeader(_ header: ActionSheetSortSectionHeader,
+                                      onSwitchIsOnChange: Bool)
+}
+
+class ActionSheetSortSectionHeader: ActionSheetSectionHeader {
+    override var cellHeight: CGFloat {
+        return 100
+    }
+
+    let descendingStackView: UIStackView = {
+        let descendingStackView = UIStackView()
+        descendingStackView.spacing = 0
+        descendingStackView.alignment = .center
+        descendingStackView.translatesAutoresizingMaskIntoConstraints = false
+        return descendingStackView
+    }()
+
+    let descendingLabel: UILabel = {
+        let descendingLabel = UILabel()
+        descendingLabel.textColor = PresentationTheme.current.colors.cellTextColor
+        descendingLabel.text = NSLocalizedString("DESCENDING_LABEL", comment: "")
+        descendingLabel.font = UIFont.systemFont(ofSize: 15, weight: .medium)
+        descendingLabel.translatesAutoresizingMaskIntoConstraints = false
+        return descendingLabel
+    }()
+
+    let actionSwitch: UISwitch = {
+        let actionSwitch = UISwitch()
+        actionSwitch.addTarget(self, action: #selector(handleSwitch(_:)), for: .valueChanged)
+        actionSwitch.accessibilityLabel = NSLocalizedString("DESCENDING_SWITCH_LABEL", comment: "")
+        actionSwitch.accessibilityHint = NSLocalizedString("DESCENDING_SWITCH_HINT", comment: "")
+        actionSwitch.translatesAutoresizingMaskIntoConstraints = false
+        return actionSwitch
+    }()
+
+    weak var delegate: ActionSheetSortSectionHeaderDelegate?
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        translatesAutoresizingMaskIntoConstraints = false
+        setupStackView()
+        updateTheme()
+        NotificationCenter.default.addObserver(self, selector: #selector(updateTheme),
+                                               name: .VLCThemeDidChangeNotification, object: nil)
+    }
+
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    @objc private func updateTheme() {
+        backgroundColor = PresentationTheme.current.colors.background
+        descendingLabel.textColor = PresentationTheme.current.colors.cellTextColor
+    }
+
+    @objc func handleSwitch(_ sender: UISwitch) {
+        delegate?.actionSheetSortSectionHeader(self, onSwitchIsOnChange: sender.isOn)
+    }
+
+    private func setupStackView() {
+        descendingStackView.addArrangedSubview(descendingLabel)
+        descendingStackView.addArrangedSubview(actionSwitch)
+        addSubview(descendingStackView)
+
+        NSLayoutConstraint.activate([
+            descendingStackView.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 20),
+            descendingStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
+            descendingStackView.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 15),
+            ])
+    }
+}

+ 13 - 2
Sources/MediaCategories/MediaCategoryViewController.swift

@@ -46,7 +46,9 @@ class VLCMediaCategoryViewController: UICollectionViewController, UICollectionVi
 //    }()
 
     @objc private lazy var sortActionSheet: ActionSheet = {
-        let actionSheet = ActionSheet()
+        let header = ActionSheetSortSectionHeader()
+        let actionSheet = ActionSheet(header: header)
+        header.delegate = self
         actionSheet.delegate = self
         actionSheet.dataSource = self
         actionSheet.modalPresentationStyle = .custom
@@ -54,7 +56,7 @@ class VLCMediaCategoryViewController: UICollectionViewController, UICollectionVi
             guard let sortingCriteria = item as? VLCMLSortingCriteria else {
                 return
             }
-            self?.model.sort(by: sortingCriteria)
+            self?.model.sort(by: sortingCriteria, desc: header.actionSwitch.isOn)
             self?.sortActionSheet.removeActionSheet()
         }
         return actionSheet
@@ -430,6 +432,15 @@ extension VLCMediaCategoryViewController: ActionSheetDataSource {
     }
 }
 
+// MARK: - ActionSheetSortSectionHeaderDelegate
+
+extension VLCMediaCategoryViewController: ActionSheetSortSectionHeaderDelegate {
+    func actionSheetSortSectionHeader(_ header: ActionSheetSortSectionHeader,
+                                      onSwitchIsOnChange: Bool) {
+        model.sort(by: model.sortModel.currentSort, desc: onSwitchIsOnChange)
+    }
+}
+
 // MARK: - EditControllerDelegate
 
 extension VLCMediaCategoryViewController: EditControllerDelegate {

+ 4 - 0
VLC.xcodeproj/project.pbxproj

@@ -236,6 +236,7 @@
 		7DF9352F1958AB0600E60FD4 /* UIColor+Presets.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF9352E1958AB0600E60FD4 /* UIColor+Presets.m */; };
 		81334053F6D89AB90E14A1C3 /* libPods-VLC-iOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 91CCB170FBC97B6B93B99E0A /* libPods-VLC-iOSTests.a */; };
 		8D144D6322298E8E00984C46 /* AudioMiniPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D144D6222298E8E00984C46 /* AudioMiniPlayer.swift */; };
+		8D15A1ED22A9603300CFA758 /* ActionSheetSortSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D15A1EC22A9603300CFA758 /* ActionSheetSortSectionHeader.swift */; };
 		8D222DC220F779F1009C0D34 /* MediaEditCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D222DC120F779F1009C0D34 /* MediaEditCell.swift */; };
 		8D2AD4D822786F4000393833 /* AddToPlaylistViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D2AD4D722786F4000393833 /* AddToPlaylistViewController.swift */; };
 		8D2AD4DA227AEE8E00393833 /* AddToPlaylistView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8D2AD4D9227AEE8E00393833 /* AddToPlaylistView.xib */; };
@@ -799,6 +800,7 @@
 		7DF9352E1958AB0600E60FD4 /* UIColor+Presets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIColor+Presets.m"; path = "Sources/UIColor+Presets.m"; sourceTree = SOURCE_ROOT; };
 		7FC9CCF39DD8843873A42D34 /* Pods-VLC-iOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VLC-iOSTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-VLC-iOSTests/Pods-VLC-iOSTests.release.xcconfig"; sourceTree = "<group>"; };
 		8D144D6222298E8E00984C46 /* AudioMiniPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioMiniPlayer.swift; sourceTree = "<group>"; };
+		8D15A1EC22A9603300CFA758 /* ActionSheetSortSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSheetSortSectionHeader.swift; sourceTree = "<group>"; };
 		8D222DC120F779F1009C0D34 /* MediaEditCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaEditCell.swift; path = Sources/MediaEditCell.swift; sourceTree = "<group>"; };
 		8D2AD4D722786F4000393833 /* AddToPlaylistViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AddToPlaylistViewController.swift; path = Sources/AddToPlaylistViewController.swift; sourceTree = "<group>"; };
 		8D2AD4D9227AEE8E00393833 /* AddToPlaylistView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AddToPlaylistView.xib; sourceTree = "<group>"; };
@@ -1865,6 +1867,7 @@
 				8D437153205808FF00F36458 /* ActionSheet.swift */,
 				8DD651B9208F6AF00052EE68 /* ActionSheetCell.swift */,
 				8DD651C3208F786F0052EE68 /* ActionSheetSectionHeader.swift */,
+				8D15A1EC22A9603300CFA758 /* ActionSheetSortSectionHeader.swift */,
 			);
 			name = ActionSheet;
 			path = Sources/ActionSheet;
@@ -2944,6 +2947,7 @@
 				7D3784C0183A9938009EE944 /* VLCLinearProgressIndicator.m in Sources */,
 				41CD695D1A29D72600E60BCE /* VLCBoxTableViewController.m in Sources */,
 				DD3EFF4F1BDEBCE500B68579 /* VLCPlexParser.m in Sources */,
+				8D15A1ED22A9603300CFA758 /* ActionSheetSortSectionHeader.swift in Sources */,
 				41CD695C1A29D72600E60BCE /* VLCBoxController.m in Sources */,
 				7D3784C2183A9938009EE944 /* VLCSlider.m in Sources */,
 				7D3784C3183A9938009EE944 /* VLCStatusLabel.m in Sources */,