Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature/sort direction] Allow sorting asc/desc for all sort methods #474

Merged
merged 11 commits into from
Aug 9, 2019
Merged
4 changes: 4 additions & 0 deletions ownCloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
39CC8B01228C8A950020253B /* MediaUploadSettingsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CC8B00228C8A950020253B /* MediaUploadSettingsSection.swift */; };
39CC8B37228D5B890020253B /* ShareClientItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CC8B36228D5B890020253B /* ShareClientItemCell.swift */; };
39D06BEC229BE8D8000D7FC9 /* SettingsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D06BEB229BE8D8000D7FC9 /* SettingsSection.swift */; };
39DE75CD22F960CF0064C1E2 /* SortMethodTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39DE75C722F960CF0064C1E2 /* SortMethodTableViewController.swift */; };
39E2FDED21FDEC7500F0117F /* ServerListTableHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E2FDEC21FDEC7500F0117F /* ServerListTableHeaderView.swift */; };
39E2FE0021FF814A00F0117F /* ThemeRoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E2FDFF21FF814A00F0117F /* ThemeRoundedButton.swift */; };
39E98B3E22797D1B009911F1 /* PublicLinkTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E98B3D22797D1B009911F1 /* PublicLinkTableViewController.swift */; };
Expand Down Expand Up @@ -613,6 +614,7 @@
39CC8B00228C8A950020253B /* MediaUploadSettingsSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaUploadSettingsSection.swift; sourceTree = "<group>"; };
39CC8B36228D5B890020253B /* ShareClientItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareClientItemCell.swift; sourceTree = "<group>"; };
39D06BEB229BE8D8000D7FC9 /* SettingsSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsSection.swift; sourceTree = "<group>"; };
39DE75C722F960CF0064C1E2 /* SortMethodTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortMethodTableViewController.swift; sourceTree = "<group>"; };
39E2FDEC21FDEC7500F0117F /* ServerListTableHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListTableHeaderView.swift; sourceTree = "<group>"; };
39E2FDFF21FF814A00F0117F /* ThemeRoundedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeRoundedButton.swift; sourceTree = "<group>"; };
39E98B3D22797D1B009911F1 /* PublicLinkTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicLinkTableViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1312,6 +1314,7 @@
4C1561E7222321E0009C4EF3 /* PhotoSelectionViewController.swift */,
4C1561EE22232357009C4EF3 /* PhotoSelectionViewCell.swift */,
394804D9225CBDBA00AA8183 /* BreadCrumbTableViewController.swift */,
39DE75C722F960CF0064C1E2 /* SortMethodTableViewController.swift */,
);
path = Client;
sourceTree = "<group>";
Expand Down Expand Up @@ -2443,6 +2446,7 @@
DC29F09522976B9300F77349 /* LibrarySharesTableViewController.swift in Sources */,
392557FE2278703300E83F60 /* UISearchBar+Extension.swift in Sources */,
DC7DBA2B207F71E400E7337D /* VectorImageView.swift in Sources */,
39DE75CD22F960CF0064C1E2 /* SortMethodTableViewController.swift in Sources */,
DCE974BC207EACA60069FC2B /* UIImage+Extension.swift in Sources */,
DC1B2707209CF0D3004715E1 /* IssuesDismissalAnimator.swift in Sources */,
23BEF1182076667F00DD2E6F /* IssuesViewController.swift in Sources */,
Expand Down
4 changes: 4 additions & 0 deletions ownCloud/Client/ClientQueryViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,10 @@ class ClientQueryViewController: QueryFileListTableViewController, UIDropInterac
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}

func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController) {
popoverPresentationController.backgroundColor = Theme.shared.activeCollection.tableBackgroundColor
}
}

// MARK: - Drag & Drop delegates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class LibraryFilesTableViewController: QueryFileListTableViewController {
}

override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
if sortMethod == .alphabeticallyAscendant || sortMethod == .alphabeticallyDescendant {
if sortMethod == .alphabetically {
return Array( Set( self.items.map { String(( $0.name?.first!.uppercased())!) })).sorted()
}

Expand Down
113 changes: 94 additions & 19 deletions ownCloud/Client/SortBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,40 @@

import UIKit

class SegmentedControl: UISegmentedControl {
var oldValue : Int!

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent? ) {
self.oldValue = self.selectedSegmentIndex
super.touchesBegan(touches, with: event)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent? ) {
super.touchesEnded(touches, with: event )

if self.oldValue == self.selectedSegmentIndex {
sendActions(for: UIControl.Event.valueChanged)
}
}
}

protocol SortBarDelegate: class {

var sortDirection: SortDirection { get set }
var sortMethod: SortMethod { get set }

func sortBar(_ sortBar: SortBar, didUpdateSortMethod: SortMethod)

func sortBar(_ sortBar: SortBar, presentViewController: UIViewController, animated: Bool, completionHandler: (() -> Void)?)
}

class SortBar: UIView, Themeable {
class SortBar: UIView, Themeable, UIPopoverPresentationControllerDelegate {

weak var delegate: SortBarDelegate?
weak var delegate: SortBarDelegate? {
didSet {
updateSortButtonTitle()
}
}

// MARK: - Constants
let sideButtonsSize: CGSize = CGSize(width: 30.0, height: 30.0)
Expand All @@ -37,19 +62,33 @@ class SortBar: UIView, Themeable {

// MARK: - Instance variables.

var sortSegmentedControl: UISegmentedControl?
var sortSegmentedControl: SegmentedControl?
var sortButton: UIButton?

var sortMethod: SortMethod {
didSet {
if self.superview != nil { // Only toggle direction if the view is already in the view hierarchy (i.e. not during initial setup)
if oldValue == sortMethod {
if delegate?.sortDirection == .ascendant {
delegate?.sortDirection = .descendant
} else {
delegate?.sortDirection = .ascendant
}
} else {
delegate?.sortDirection = .ascendant // Reset sort direction when switching sort methods
}
}
updateSortButtonTitle()

let title = NSString(format: "Sort by %@".localized as NSString, sortMethod.localizedName()) as String
sortButton?.setTitle(title, for: .normal)
sortButton?.accessibilityLabel = NSString(format: "Sort by %@".localized as NSString, sortMethod.localizedName()) as String
sortButton?.sizeToFit()

if let oldSementIndex = SortMethod.all.index(of: oldValue) {
sortSegmentedControl?.setTitle(oldValue.localizedName(), forSegmentAt: oldSementIndex)
}
if let segmentIndex = SortMethod.all.index(of: sortMethod) {
sortSegmentedControl?.selectedSegmentIndex = segmentIndex
sortSegmentedControl?.setTitle(sortDirectionTitle(sortMethod.localizedName()), forSegmentAt: segmentIndex)
}

delegate?.sortBar(self, didUpdateSortMethod: sortMethod)
Expand All @@ -59,7 +98,7 @@ class SortBar: UIView, Themeable {
// MARK: - Init & Deinit

init(frame: CGRect, sortMethod: SortMethod) {
sortSegmentedControl = UISegmentedControl()
sortSegmentedControl = SegmentedControl()

sortButton = UIButton(type: .system)

Expand All @@ -86,8 +125,19 @@ class SortBar: UIView, Themeable {
sortSegmentedControl.rightAnchor.constraint(lessThanOrEqualTo: self.rightAnchor, constant: -rightPadding)
])

var longestTitleWidth : CGFloat = 0.0
for method in SortMethod.all {
sortSegmentedControl.insertSegment(withTitle: method.localizedName(), at: SortMethod.all.index(of: method)!, animated: false)
let titleWidth = method.localizedName().appending(" ↓").width(withConstrainedHeight: sortSegmentedControl.frame.size.height, font: UIFont.systemFont(ofSize: 16.0))
if titleWidth > longestTitleWidth {
longestTitleWidth = titleWidth
}
}

var currentIndex = 0
for _ in SortMethod.all {
sortSegmentedControl.setWidth(longestTitleWidth, forSegmentAt: currentIndex)
currentIndex += 1
}

sortSegmentedControl.selectedSegmentIndex = SortMethod.all.index(of: sortMethod)!
Expand All @@ -98,6 +148,7 @@ class SortBar: UIView, Themeable {
sortButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .subheadline)
sortButton.titleLabel?.adjustsFontForContentSizeCategory = true
sortButton.semanticContentAttribute = (sortButton.effectiveUserInterfaceLayoutDirection == .leftToRight) ? .forceRightToLeft : .forceLeftToRight

sortButton.setImage(UIImage(named: "chevron-small-light"), for: .normal)

sortButton.setContentHuggingPriority(.required, for: .horizontal)
Expand All @@ -110,7 +161,7 @@ class SortBar: UIView, Themeable {
])

sortButton.isHidden = true
sortButton.addTarget(self, action: #selector(presentSortButtonOptions), for: .touchUpInside)
sortButton.addTarget(self, action: #selector(presentSortButtonOptions(_:)), for: .touchUpInside)
}

// Finalize view setup
Expand Down Expand Up @@ -147,20 +198,35 @@ class SortBar: UIView, Themeable {
}
}

// MARK: - Actions
@objc private func presentSortButtonOptions() {
let controller = UIAlertController(title: "Sort by".localized, message: nil, preferredStyle: .actionSheet)

for method in SortMethod.all {
let action = UIAlertAction(title: method.localizedName(), style: .default, handler: {(_) in
self.sortMethod = method
})
controller.addAction(action)
// MARK: - Sort Direction Title

func updateSortButtonTitle() {
let title = NSString(format: "Sort by %@".localized as NSString, sortMethod.localizedName()) as String
sortButton?.setTitle(sortDirectionTitle(title), for: .normal)
}

func sortDirectionTitle(_ title: String) -> String {
if delegate?.sortDirection == .descendant {
return String(format: "%@ ↓", title)
} else {
return String(format: "%@ ↑", title)
}
}

let cancel = UIAlertAction(title: "Cancel".localized, style: .cancel)
controller.addAction(cancel)
delegate?.sortBar(self, presentViewController: controller, animated: true, completionHandler: nil)
// MARK: - Actions
@objc private func presentSortButtonOptions(_ sender : UIButton) {
let tableViewController = SortMethodTableViewController()
tableViewController.modalPresentationStyle = UIModalPresentationStyle.popover
tableViewController.sortBarDelegate = self.delegate
tableViewController.sortBar = self

let popoverPresentationController = tableViewController.popoverPresentationController
popoverPresentationController?.sourceView = sender
popoverPresentationController?.delegate = self
popoverPresentationController?.sourceRect = CGRect(x: 0, y: 0, width: sender.frame.size.width, height: sender.frame.size.height)
popoverPresentationController?.permittedArrowDirections = .up

delegate?.sortBar(self, presentViewController: tableViewController, animated: true, completionHandler: nil)
}

@objc private func sortSegmentedControllerValueChanged() {
Expand All @@ -169,4 +235,13 @@ class SortBar: UIView, Themeable {
delegate?.sortBar(self, didUpdateSortMethod: self.sortMethod)
}
}

// MARK: - UIPopoverPresentationControllerDelegate
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}

func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController) {
popoverPresentationController.backgroundColor = Theme.shared.activeCollection.tableBackgroundColor
}
}
68 changes: 41 additions & 27 deletions ownCloud/Client/SortMethod.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,27 @@ import ownCloudSDK

typealias OCSort = Comparator

public enum SortDirection: Int {
case ascendant = 0
case descendant = 1
}

public enum SortMethod: Int {

case alphabeticallyAscendant = 0
case alphabeticallyDescendant = 1
case type = 2
case size = 3
case date = 4
case shared = 5
case alphabetically = 0
case type = 1
case size = 2
case date = 3
case shared = 4

static var all: [SortMethod] = [alphabeticallyAscendant, alphabeticallyDescendant, type, size, date, shared]
static var all: [SortMethod] = [alphabetically, type, size, date, shared]

func localizedName() -> String {
var name = ""

switch self {
case .alphabeticallyAscendant:
name = "name (A-Z)".localized
case .alphabeticallyDescendant:
name = "name (Z-A)".localized
case .alphabetically:
name = "name".localized
case .type:
name = "type".localized
case .size:
Expand All @@ -53,7 +55,7 @@ public enum SortMethod: Int {
return name
}

func comparator() -> OCSort {
func comparator(direction: SortDirection) -> OCSort {
var comparator: OCSort

switch self {
Expand All @@ -64,28 +66,23 @@ public enum SortMethod: Int {

let leftSize = leftItem!.size as NSNumber
let rightSize = rightItem!.size as NSNumber
if direction == .descendant {
return (leftSize.compare(rightSize))
}

return (rightSize.compare(leftSize))
}

case .alphabeticallyAscendant:
case .alphabetically:
comparator = { (left, right) in
guard let leftName = (left as? OCItem)?.name, let rightName = (right as? OCItem)?.name else {
return .orderedSame
}

return (leftName.caseInsensitiveCompare(rightName))
}

case .alphabeticallyDescendant:
comparator = { (left, right) in
guard let leftName = (left as? OCItem)?.name, let rightName = (right as? OCItem)?.name else {
return .orderedSame
if direction == .descendant {
return (rightName.caseInsensitiveCompare(leftName))
}

return (rightName.caseInsensitiveCompare(leftName))
return (leftName.caseInsensitiveCompare(rightName))
}

case .type:
comparator = { (left, right) in
let leftItem = left as? OCItem
Expand All @@ -109,6 +106,9 @@ public enum SortMethod: Int {
if rightMimeType == nil {
rightMimeType = "various"
}
if direction == .descendant {
return rightMimeType!.compare(leftMimeType!)
}

return leftMimeType!.compare(rightMimeType!)
}
Expand All @@ -122,17 +122,31 @@ public enum SortMethod: Int {

if leftShared == rightShared {
return .orderedSame
} else if leftShared {
return .orderedAscending
}
return .orderedDescending

if direction == .descendant {
if rightShared {
return .orderedAscending
}

return .orderedDescending
} else {
if leftShared {
return .orderedAscending
}

return .orderedDescending
}
}
case .date:
comparator = { (left, right) in

guard let leftLastModified = (left as? OCItem)?.lastModified, let rightLastModified = (right as? OCItem)?.lastModified else {
return .orderedSame
}
if direction == .descendant {
return (leftLastModified.compare(rightLastModified))
}

return (rightLastModified.compare(leftLastModified))
}
Expand Down
Loading