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

First implementation of PDF viewer feature #138

Merged
merged 23 commits into from
Nov 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3106879
First implementation of PDF viewer feature
mneuwert Oct 29, 2018
d12243a
Adjusting thumbnail size leads to crashes in certain scenarios
mneuwert Oct 29, 2018
212fc96
- Added license texts
felix-schwarz Oct 30, 2018
70f31d4
Code styling related changes
mneuwert Oct 31, 2018
d5fcd8a
Code review related changes affecting styling / readability
mneuwert Oct 31, 2018
123b19e
Implemented proper theming support in PDF table of contents
mneuwert Oct 31, 2018
ba780a8
Disabled hiding of navigation bar
mneuwert Nov 15, 2018
7afef4b
Showing file name of PDF document only in the navigation bar
mneuwert Nov 15, 2018
f109a16
Tweaked thumbnail size
mneuwert Nov 15, 2018
ddd95de
Fixed an exception related to setting of thumbnail size
mneuwert Nov 15, 2018
7ef9db3
PDF search UI fixes
mneuwert Nov 15, 2018
acd14fa
Fixes in the full screen thumbnails view
mneuwert Nov 15, 2018
1b9dd3e
Merge remote-tracking branch 'origin/master' into feature/pdf_integra…
mneuwert Nov 15, 2018
4c80dc8
Removed not used code
mneuwert Nov 15, 2018
6bd7aa1
Removed unused icons from asset catalog
mneuwert Nov 16, 2018
e9cf02b
Improved PDF search UX (search field is focused immediately)
mneuwert Nov 16, 2018
851808b
Fixed pontential crash in asynchronous thumbnail generation code
mneuwert Nov 16, 2018
9aa68f9
Fixed theming support in PDF outline / thumbnail UI
mneuwert Nov 16, 2018
d0fb58c
Fixed SwiftLint warning (trailing whitespace)
mneuwert Nov 16, 2018
a4856f5
Improved current page number display in PDF viewer
mneuwert Nov 16, 2018
3bcceba
Showing an error if user tries to “go to” invalid / non-existing PDF …
mneuwert Nov 16, 2018
e181904
Changed the way current page nr is displayed
mneuwert Nov 19, 2018
1445b36
Fixed table view separator glitches in PDF search
mneuwert Nov 19, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions ownCloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@
23EC775D2137FB6B0032D4E6 /* WebViewDisplayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23EC775C2137FB6B0032D4E6 /* WebViewDisplayViewController.swift */; };
23F6238120B587EF004FDE8B /* SortMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23F6238020B587EF004FDE8B /* SortMethod.swift */; };
23FA23E620BFD3D8009A6D73 /* SortBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23FA23E520BFD3D8009A6D73 /* SortBar.swift */; };
4C464BEF2187AF1500D30602 /* PDFThumbnailCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C464BE12187AF1400D30602 /* PDFThumbnailCollectionViewCell.swift */; };
4C464BF02187AF1500D30602 /* PDFTocTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C464BE82187AF1400D30602 /* PDFTocTableViewController.swift */; };
4C464BF12187AF1500D30602 /* PDFTocTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C464BE92187AF1400D30602 /* PDFTocTableViewCell.swift */; };
4C464BF22187AF1500D30602 /* PDFSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C464BEA2187AF1400D30602 /* PDFSearchViewController.swift */; };
4C464BF32187AF1500D30602 /* PDFOutlineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C464BEB2187AF1500D30602 /* PDFOutlineViewController.swift */; };
4C464BF42187AF1500D30602 /* PDFSearchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C464BEC2187AF1500D30602 /* PDFSearchTableViewCell.swift */; };
4C464BF52187AF1500D30602 /* PDFThumbnailsCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C464BED2187AF1500D30602 /* PDFThumbnailsCollectionViewController.swift */; };
4C464BF62187AF1500D30602 /* PDFTocItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C464BEE2187AF1500D30602 /* PDFTocItem.swift */; };
5917244E20D3DC2100809B38 /* BiometricalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5917244D20D3DC2100809B38 /* BiometricalTests.swift */; };
593A821120C7D4C5000E2A90 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 593A821320C7D4C5000E2A90 /* Localizable.strings */; };
593BAB46209AE1BC00023634 /* PasscodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 593BAB44209AE1BC00023634 /* PasscodeViewController.swift */; };
Expand Down Expand Up @@ -343,6 +351,14 @@
23EC775C2137FB6B0032D4E6 /* WebViewDisplayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewDisplayViewController.swift; sourceTree = "<group>"; };
23F6238020B587EF004FDE8B /* SortMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SortMethod.swift; sourceTree = "<group>"; };
23FA23E520BFD3D8009A6D73 /* SortBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SortBar.swift; sourceTree = "<group>"; };
4C464BE12187AF1400D30602 /* PDFThumbnailCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFThumbnailCollectionViewCell.swift; sourceTree = "<group>"; };
4C464BE82187AF1400D30602 /* PDFTocTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFTocTableViewController.swift; sourceTree = "<group>"; };
4C464BE92187AF1400D30602 /* PDFTocTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFTocTableViewCell.swift; sourceTree = "<group>"; };
4C464BEA2187AF1400D30602 /* PDFSearchViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFSearchViewController.swift; sourceTree = "<group>"; };
4C464BEB2187AF1500D30602 /* PDFOutlineViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFOutlineViewController.swift; sourceTree = "<group>"; };
4C464BEC2187AF1500D30602 /* PDFSearchTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFSearchTableViewCell.swift; sourceTree = "<group>"; };
4C464BED2187AF1500D30602 /* PDFThumbnailsCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFThumbnailsCollectionViewController.swift; sourceTree = "<group>"; };
4C464BEE2187AF1500D30602 /* PDFTocItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFTocItem.swift; sourceTree = "<group>"; };
5917244D20D3DC2100809B38 /* BiometricalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BiometricalTests.swift; sourceTree = "<group>"; };
593A821220C7D4C5000E2A90 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
593A821820C7D4DC000E2A90 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
Expand Down Expand Up @@ -623,6 +639,14 @@
23D5241421491C670002C566 /* DisplayViewController.swift */,
23EC77562137F3DC0032D4E6 /* DisplayHostViewController.swift */,
23EC77542137F3DC0032D4E6 /* PDFViewerViewController.swift */,
4C464BEB2187AF1500D30602 /* PDFOutlineViewController.swift */,
4C464BEC2187AF1500D30602 /* PDFSearchTableViewCell.swift */,
4C464BEA2187AF1400D30602 /* PDFSearchViewController.swift */,
4C464BE12187AF1400D30602 /* PDFThumbnailCollectionViewCell.swift */,
4C464BED2187AF1500D30602 /* PDFThumbnailsCollectionViewController.swift */,
4C464BEE2187AF1500D30602 /* PDFTocItem.swift */,
4C464BE92187AF1400D30602 /* PDFTocTableViewCell.swift */,
4C464BE82187AF1400D30602 /* PDFTocTableViewController.swift */,
23EC775C2137FB6B0032D4E6 /* WebViewDisplayViewController.swift */,
6E4F1733217749910049A71B /* ImageDisplayViewController.swift */,
);
Expand Down Expand Up @@ -1291,14 +1315,19 @@
23EC775D2137FB6B0032D4E6 /* WebViewDisplayViewController.swift in Sources */,
DC018F8C20A1060A00135198 /* ProgressHUDViewController.swift in Sources */,
DC7DBA29207F71D600E7337D /* VectorImage.swift in Sources */,
4C464BF12187AF1500D30602 /* PDFTocTableViewCell.swift in Sources */,
DC1B270C209CF34B004715E1 /* BookmarkViewController.swift in Sources */,
23EC775A2137F3DD0032D4E6 /* DisplayHostViewController.swift in Sources */,
4C464BF62187AF1500D30602 /* PDFTocItem.swift in Sources */,
DC018F8320A0F56300135198 /* UIView+Animation.swift in Sources */,
DC42244A207CAFAA0006A2A6 /* Theme.swift in Sources */,
4C464BF52187AF1500D30602 /* PDFThumbnailsCollectionViewController.swift in Sources */,
4C464BF02187AF1500D30602 /* PDFTocTableViewController.swift in Sources */,
DC4FEAEA209E48E800D4476B /* DispatchQueueTools.swift in Sources */,
DC1B2708209CF0D3004715E1 /* IssuesPresentationAnimator.swift in Sources */,
DC3BE0DF2077CC14002A0AC0 /* ClientRootViewController.swift in Sources */,
DC854936218331CF00782BA8 /* UserInterfaceSettingsSection.swift in Sources */,
4C464BF42187AF1500D30602 /* PDFSearchTableViewCell.swift in Sources */,
DC1B2709209CF0D3004715E1 /* CertificateViewController.swift in Sources */,
DC248C67213E7DB00067FE94 /* NSLayoutConstraint+Extension.swift in Sources */,
DC136582208223F000FC0F60 /* OCBookmark+Extension.swift in Sources */,
Expand All @@ -1318,10 +1347,13 @@
DCE974B2207E3AF80069FC2B /* ThemeNavigationController.swift in Sources */,
DC89C45D20860B5D0044BCAE /* ProgressSummarizer.swift in Sources */,
232F7CAF2097260400EE22E4 /* SettingsViewController.swift in Sources */,
4C464BF32187AF1500D30602 /* PDFOutlineViewController.swift in Sources */,
DC85572C20513B8C00189B9A /* ServerListTableViewController.swift in Sources */,
233BDEA0204FEFE500C06732 /* AppDelegate.swift in Sources */,
236735A621217C3500E5834A /* MoreViewController.swift in Sources */,
23957A6D209AFFE8003C8537 /* MoreSettingsSection.swift in Sources */,
DCF4F1822051A94200189B9A /* GlobalSettingsViewController.swift in Sources */,
4C464BEF2187AF1500D30602 /* PDFThumbnailCollectionViewCell.swift in Sources */,
232B01F62126B10900366FA0 /* MoreStaticTableViewController.swift in Sources */,
593BAB97209F8A0500023634 /* AppLockManager.swift in Sources */,
DC85493421831B0B00782BA8 /* Tools.swift in Sources */,
Expand All @@ -1346,6 +1378,7 @@
DC0B37972051681600189B9A /* ThemeButton.swift in Sources */,
DCF4F17B20519F9D00189B9A /* StaticTableViewSection.swift in Sources */,
23C56537212167BE00BD4B47 /* CardPresentationController.swift in Sources */,
4C464BF22187AF1500D30602 /* PDFSearchViewController.swift in Sources */,
DC7DBA2B207F71E400E7337D /* VectorImageView.swift in Sources */,
DCE974BC207EACA60069FC2B /* UIImage+Extension.swift in Sources */,
DC1B2707209CF0D3004715E1 /* IssuesDismissalAnimator.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_open_in_new_24px.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_list_24px.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_border_all_24px.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
9 changes: 9 additions & 0 deletions ownCloud/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,12 @@
"There is no network" = "There is no network";
"Error" = "Error";
"Could not get the picture" = "Could not get the picture";

/* PDF Viewer */
"Resume" = "Resume";
"Go to page" = "Go to page";
"Page" = "Page";
"This document has %@ pages" = "This document has %@ pages";
"%@ of %@" = "%@ of %@";
"Invalid Page" = "Invalid Page";
"The entered page number doesn't exist" = "The entered page number doesn't exist";
6 changes: 6 additions & 0 deletions ownCloud/Theming/NSObject+ThemeApplication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ extension NSObject {
tableView.separatorColor = collection.tableSeparatorColor
}

if self.isKind(of: UICollectionView.self) {
let collectionView : UICollectionView = (self as? UICollectionView)!

collectionView.backgroundColor = collection.tableBackgroundColor
}

if self.isKind(of: UISearchBar.self) {
let searchBar : UISearchBar = (self as? UISearchBar)!

Expand Down
5 changes: 5 additions & 0 deletions ownCloud/UIKit Extensions/String+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,9 @@ extension String {
var localized: String {
return NSLocalizedString(self, comment: "")
}

var isNumeric: Bool {
let nonDigitsCharacterSet = CharacterSet.decimalDigits.inverted
return !self.isEmpty && rangeOfCharacter(from: nonDigitsCharacterSet) == nil
}
}
121 changes: 121 additions & 0 deletions ownCloud/Viewer/PDFOutlineViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//
// PDFOutlineViewController.swift
// ownCloud
//
// Created by Michael Neuwert on 04.10.2018.
// Copyright © 2018 ownCloud GmbH. All rights reserved.
//

/*
* Copyright (C) 2018, ownCloud GmbH.
*
* This code is covered by the GNU Public License Version 3.
*
* For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/
* You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>.
*
*/

import UIKit
import PDFKit

class PDFOutlineViewController: UIViewController {

enum Mode : Int {
case ToC, Thumbnails
}

var pdfDocument: PDFDocument?
var themeCollection: ThemeCollection?

var mode: Mode = .ToC {
didSet {
if let control = modeSegmentedControl {
control.selectedSegmentIndex = mode.rawValue
}
setupChildController(forMode: mode)
}
}

var modeSegmentedControl: UISegmentedControl?

override func viewDidLoad() {
super.viewDidLoad()
var iconArray: [UIImage] = [UIImage]()
if self.pdfDocument?.outlineRoot != nil {
iconArray.append( UIImage(named: "ic_pdf_outline")!)
}
iconArray.append(UIImage(named: "ic_pdf_view_multipage")!)

modeSegmentedControl = UISegmentedControl(items: iconArray)
if self.pdfDocument?.outlineRoot != nil {
modeSegmentedControl?.addTarget(self, action: #selector(modeChanged), for: .valueChanged)
self.mode = .ToC
} else {
self.mode = .Thumbnails
}
self.navigationItem.titleView = modeSegmentedControl

if UIDevice.current.userInterfaceIdiom != .pad {
let resumeItem = UIBarButtonItem(title: "Resume".localized, style: .plain, target: self, action: #selector(resume))
self.navigationItem.rightBarButtonItem = resumeItem
}
}

// MARK: - User actions

@objc func resume() {
self.dismiss(animated: true, completion: nil)
}

@objc func modeChanged() {
if let newMode = Mode(rawValue: modeSegmentedControl!.selectedSegmentIndex) {
self.mode = newMode
}
}

// MARK: - Private helper methods

fileprivate func setupChildController(forMode mode:Mode) {

var fromViewController: UIViewController?
var toViewController: UIViewController?

if self.childViewControllers.count > 0 {
fromViewController = self.childViewControllers.first
}
if mode == .ToC {
let tocViewController = PDFTocTableViewController()
tocViewController.outlineRoot = self.pdfDocument?.outlineRoot
toViewController = tocViewController
} else {
let thumbnaisViewController = PDFThumbnailsCollectionViewController()
thumbnaisViewController.pdfDocument = self.pdfDocument
toViewController = thumbnaisViewController
}

change(fromViewController: fromViewController, toViewController: toViewController!)
}

fileprivate func change(fromViewController:UIViewController?, toViewController:UIViewController) {
fromViewController?.willMove(toParentViewController: nil)
self.addChildViewController(toViewController)
toViewController.view.frame = self.view.frame
self.view.addSubview(toViewController.view)

if fromViewController != nil {
toViewController.view.alpha = 0.0

UIView.animate(withDuration: 0.25, animations: {
fromViewController!.view.alpha = 0.0
toViewController.view.alpha = 1.0
}, completion: { (_) in
fromViewController?.view.removeFromSuperview()
fromViewController?.removeFromParentViewController()
toViewController.didMove(toParentViewController: self)
})
} else {
toViewController.didMove(toParentViewController: self)
}
}
}
96 changes: 96 additions & 0 deletions ownCloud/Viewer/PDFSearchTableViewCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//
// PDFSearchTableViewCell.swift
// ownCloud
//
// Created by Michael Neuwert on 18.09.2018.
// Copyright © 2018 ownCloud GmbH. All rights reserved.
//

/*
* Copyright (C) 2018, ownCloud GmbH.
*
* This code is covered by the GNU Public License Version 3.
*
* For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/
* You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>.
*
*/

import UIKit
import PDFKit

class PDFSearchTableViewCell: ThemeTableViewCell {

var titleLabel = UILabel()
var pageLabel = UILabel()

static let identifier = "PDFSearchTableViewCell"

fileprivate let layoutMargin: CGFloat = 20.0
fileprivate let titleFontSize: CGFloat = 16
fileprivate let pageFontSize: CGFloat = 15

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupSubviewsAndConstraints()
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSubviewsAndConstraints()
}

fileprivate func setupSubviewsAndConstraints() {

self.contentView.addSubview(titleLabel)
self.contentView.addSubview(pageLabel)

titleLabel.font = UIFont.systemFont(ofSize: titleFontSize, weight: UIFont.Weight.regular)
titleLabel.lineBreakMode = .byTruncatingTail
titleLabel.translatesAutoresizingMaskIntoConstraints = false

pageLabel.font = UIFont.systemFont(ofSize: pageFontSize, weight: UIFont.Weight.light)
pageLabel.textAlignment = .right
pageLabel.translatesAutoresizingMaskIntoConstraints = false

titleLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor).isActive = true
titleLabel.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor).isActive = true
titleLabel.leftAnchor.constraint(equalTo: self.contentView.leftAnchor, constant: layoutMargin).isActive = true

pageLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor).isActive = true
pageLabel.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor).isActive = true
pageLabel.rightAnchor.constraint(equalTo: self.contentView.rightAnchor, constant: -layoutMargin).isActive = true

pageLabel.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor).isActive = true

titleLabel.setContentCompressionResistancePriority(UILayoutPriority.defaultLow, for: UILayoutConstraintAxis.horizontal)
pageLabel.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: UILayoutConstraintAxis.horizontal)
}

// MARK: - Theme support
override func applyThemeCollectionToCellContents(theme: Theme, collection: ThemeCollection) {
let itemState = ThemeItemState(selected: self.isSelected)

self.titleLabel.applyThemeCollection(collection, itemStyle: .title, itemState: itemState)
self.pageLabel.applyThemeCollection(collection, itemStyle: .message, itemState: itemState)
}

func setup(with selection:PDFSelection) {
// Create a copy to not modify original instance through extend() calls
if let pdfSelection = selection.copy() as? PDFSelection {
let matchStr = selection.string

// Extend the selection around search match
pdfSelection.extendForLineBoundaries()

// Create attributed string where match substring is highlighted with bold font
let range = (pdfSelection.string! as NSString).range(of: matchStr!, options: .caseInsensitive)
let attrStr = NSMutableAttributedString(string: pdfSelection.string!)
let boldFont = UIFont.systemFont(ofSize: titleFontSize, weight: UIFont.Weight.bold)
attrStr.addAttribute(.font, value: boldFont, range: range)

self.titleLabel.attributedText = attrStr
self.pageLabel.text = "\(selection.pages.first?.label ?? "")"
}
}
}
Loading