diff options
author | Jon Nermut <jon.nermut@gmail.com> | 2018-01-23 15:18:42 +1100 |
---|---|---|
committer | jan iversen <jani@libreoffice.org> | 2018-01-23 10:56:50 +0100 |
commit | 810dfda5556c5e0f0cc65f01c9634996951fd3e5 (patch) | |
tree | ac9f0833216ddef74977f0fef60090fb1f9a31bd /ios | |
parent | 91b4e4531621b7afb2dbab1a8aa62c92da66951a (diff) |
iOS: implement tabs for spreadsheets
Change-Id: I210d68f013e56efd90da004891b872434ce65f68
Reviewed-on: https://gerrit.libreoffice.org/48368
Reviewed-by: jan iversen <jani@libreoffice.org>
Tested-by: jan iversen <jani@libreoffice.org>
Diffstat (limited to 'ios')
6 files changed, 281 insertions, 5 deletions
diff --git a/ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj b/ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj index 315d4d18151b..4897f40a1641 100644 --- a/ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj +++ b/ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj @@ -35,6 +35,8 @@ 39EF4E2F1FA500C9001914AC /* PropertiesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39EF4E2E1FA500C9001914AC /* PropertiesController.swift */; }; FC31D01E2012F65500E7F402 /* DocumentHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC31D01D2012F65500E7F402 /* DocumentHolder.swift */; }; FC31D0202012F6D300E7F402 /* RenderCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC31D01F2012F6D300E7F402 /* RenderCache.swift */; }; + FC31D02B2013500E00E7F402 /* ButtonScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC31D02A2013500E00E7F402 /* ButtonScrollView.swift */; }; + FC31D02D2015DE1700E7F402 /* UIViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC31D02C2015DE1700E7F402 /* UIViewExtensions.swift */; }; FCAB1CB82009DB6900F1CC34 /* DocumentOverlaysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCAB1CB72009DB6900F1CC34 /* DocumentOverlaysView.swift */; }; FCC2E3FA2004A01500CEB504 /* Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC2E3F62004A01400CEB504 /* Document.swift */; }; FCC2E3FC2004A01500CEB504 /* LibreOfficeKitWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC2E3F82004A01400CEB504 /* LibreOfficeKitWrapper.swift */; }; @@ -87,6 +89,8 @@ FC31D0132012EE4A00E7F402 /* LibreOfficeKitTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LibreOfficeKitTypes.h; sourceTree = "<group>"; }; FC31D01D2012F65500E7F402 /* DocumentHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentHolder.swift; sourceTree = "<group>"; }; FC31D01F2012F6D300E7F402 /* RenderCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenderCache.swift; sourceTree = "<group>"; }; + FC31D02A2013500E00E7F402 /* ButtonScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonScrollView.swift; sourceTree = "<group>"; }; + FC31D02C2015DE1700E7F402 /* UIViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewExtensions.swift; sourceTree = "<group>"; }; FCAB1CB72009DB6900F1CC34 /* DocumentOverlaysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentOverlaysView.swift; sourceTree = "<group>"; }; FCC2E3F62004A01400CEB504 /* Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Document.swift; sourceTree = "<group>"; }; FCC2E3F82004A01400CEB504 /* LibreOfficeKitWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LibreOfficeKitWrapper.swift; sourceTree = "<group>"; }; @@ -172,11 +176,13 @@ 39EE81531FA644E800B73AB8 /* Info.plist */, 39503A6F1F94C4AC00F19C78 /* lokit-Bridging-Header.h */, 397E08FD1E597BD8001374E0 /* AppDelegate.swift */, + FC31D02A2013500E00E7F402 /* ButtonScrollView.swift */, 3992D8591E5B762A00BEA987 /* DocumentController.swift */, FCAB1CB72009DB6900F1CC34 /* DocumentOverlaysView.swift */, FCC2E3FE2004B59B00CEB504 /* DocumentTiledView.swift */, 39284DB21FA5F207006F43E4 /* DocumentActions.swift */, 39EF4E2E1FA500C9001914AC /* PropertiesController.swift */, + FC31D02C2015DE1700E7F402 /* UIViewExtensions.swift */, 392ED9B21E5E4B03005C8435 /* ViewPrintManager.swift */, 399648461E5B87DC00E73E83 /* ViewProperties.swift */, 397E09011E597BD8001374E0 /* Main.storyboard */, @@ -341,8 +347,10 @@ 3992D85A1E5B762A00BEA987 /* DocumentController.swift in Sources */, FCC2E3FD2004A01500CEB504 /* LOKitThread.swift in Sources */, 397E08FE1E597BD8001374E0 /* AppDelegate.swift in Sources */, + FC31D02B2013500E00E7F402 /* ButtonScrollView.swift in Sources */, FCC2E3FA2004A01500CEB504 /* Document.swift in Sources */, FCC2E3FF2004B59B00CEB504 /* DocumentTiledView.swift in Sources */, + FC31D02D2015DE1700E7F402 /* UIViewExtensions.swift in Sources */, FCC2E4052004B74000CEB504 /* AsyncUtil.swift in Sources */, 39EF4E2F1FA500C9001914AC /* PropertiesController.swift in Sources */, ); diff --git a/ios/LibreOfficeLight/LibreOfficeLight/ButtonScrollView.swift b/ios/LibreOfficeLight/LibreOfficeLight/ButtonScrollView.swift new file mode 100644 index 000000000000..279ad22123b6 --- /dev/null +++ b/ios/LibreOfficeLight/LibreOfficeLight/ButtonScrollView.swift @@ -0,0 +1,145 @@ +// +// This file is part of the LibreOffice project. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +import UIKit + +/// Scrollable list of buttons. +/// Kind of like a tab bar, but doesn't maintain or switch between views, just calls back on click +open class ButtonScrollView: UIScrollView +{ + var buttonList: ButtonList? = nil + + var buttonClickedCallback: ( (Int) -> () )? = nil + + var selectedIndex: Int? + { + get { + return buttonList?.selectedIndex + } + set { + buttonList?.selectedIndex = selectedIndex + } + } + + public override init(frame: CGRect) + { + super.init(frame: frame) + } + + public required init?(coder aDecoder: NSCoder) + { + super.init(coder: aDecoder) + } + + public func setButtonLabels(labels: [String]) + { + if let bl = buttonList + { + bl.removeFromSuperview() + } + let bl = ButtonList(frame: CGRect(x:0, y:0, width: self.frame.width, height:44), + labels: labels, + owner: self) + self.addSubview(bl) + self.contentSize = bl.frame.size + self.buttonList = bl + } +} + +/// Horizontally layed out buttons, living within the owned scroll view +open class ButtonList: UIView +{ + let labels: [String] + let gap: CGFloat = 10.0 + let topGap: CGFloat = 8 + weak var owner: ButtonScrollView? = nil + + var buttonBackground = UIColor(white: 0.6, alpha: 1) + var selectedButtonBackground = UIColor.white + + var selectedIndex: Int? = 0 + { + didSet { + runOnMain { + self.highlightSelectedIndex() + } + } + } + + public init(frame: CGRect, labels: [String], owner: ButtonScrollView) + { + self.labels = labels + self.owner = owner + super.init(frame: frame) + self.backgroundColor = UIColor(white: 0.9, alpha: 1) + + var idx = 0 + for label in labels + { + let b = UIButton(type: .custom) + b.setTitle(label, for: .normal) + b.backgroundColor = buttonBackground + b.contentEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4) + b.layer.cornerRadius = 4 + b.tag = idx + b.addTarget(self, action: #selector(buttonTapped), for: UIControlEvents.touchUpInside) + self.addSubview(b) + idx += 1 + } + self.layoutSubviews() + } + + @objc func buttonTapped(sender: UIButton, forEvent event: UIEvent) + { + let idx = sender.tag + owner?.buttonClickedCallback?(idx) + self.selectedIndex = idx + } + + public required init?(coder aDecoder: NSCoder) + { + fatalError("init(coder:) has not been implemented") + } + + public var buttons: [UIButton] + { + return self.subviews.flatMap({ $0 as? UIButton }) + } + + open override func layoutSubviews() + { + + var x: CGFloat = gap + for button in buttons + { + button.sizeToFit() + let s = button.frame.size + button.frame = CGRect(x: x, y: topGap, width: s.width, height: s.height) + x = x + (s.width + gap) + } + highlightSelectedIndex() + self.frame = CGRect(x:0, y: 0, width: x, height: self.frame.height) + } + + open func highlightSelectedIndex() + { + for (index, button) in buttons.enumerated() + { + if (index == selectedIndex) + { + button.backgroundColor = selectedButtonBackground + button.setTitleColor(.black, for: .normal) + } + else + { + button.backgroundColor = buttonBackground + button.setTitleColor(.white, for: .normal) + } + + } + } +} diff --git a/ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift b/ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift index 3decec85410a..88c3ccdcd67e 100755 --- a/ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift +++ b/ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift @@ -26,10 +26,13 @@ class DocumentController: UIViewController, MenuDelegate, UIDocumentBrowserViewC // holds known document types var KnownDocumentTypes : [String] = [] + var zeroInsets: UIEdgeInsets = .zero + @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var mask: UIView! @IBOutlet weak var progressBar: UIProgressView! @IBOutlet weak var searchBar: UISearchBar! + @IBOutlet weak var buttonScrollView: ButtonScrollView! deinit { @@ -61,10 +64,12 @@ class DocumentController: UIViewController, MenuDelegate, UIDocumentBrowserViewC override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - //let res = Bundle.main.url(forResource: "example", withExtension: "odt") - //let res = Bundle.main.url(forResource: "example2", withExtension: "docx") - let res = Bundle.main.url(forResource: "testdata/1", withExtension: "pptx") + // Always load the 'welcome' file, as per the android app + let res = Bundle.main.url(forResource: "example", withExtension: "odt") + + // uncomment for test data in resources until the doc picker works properly + //let res = Bundle.main.url(forResource: "testdata/2", withExtension: "xlsx") if let exampleDoc = res { @@ -416,6 +421,30 @@ class DocumentController: UIViewController, MenuDelegate, UIDocumentBrowserViewC docView.addSubview(overlay) self.documentOverlaysView = overlay + // button view - used for spreadsheet tabs + if doc.isSpeadsheet + { + buttonScrollView.isHidden = false + buttonScrollView.setButtonLabels(labels: doc.partNames) + buttonScrollView.buttonClickedCallback = { + [weak self] index in + self?.document?.async { + $0.setPart(nPart: Int32(index)) + runOnMain { + self?.documentView?.setNeedsDisplay() + } + } + } + // make room for the scroll view + zeroInsets = UIEdgeInsets(top: 0, left: 0, bottom: buttonScrollView.height, right: 0) + } + else + { + zeroInsets = .zero + buttonScrollView.isHidden = true + } + scrollView.contentInset = zeroInsets + // debugging view borders /* self.scrollView.layer.borderColor = UIColor.red.cgColor @@ -563,7 +592,7 @@ extension DocumentController @objc func keyboardWillHide(notification: NSNotification) { print("keyboardWillHide") - scrollView.contentInset = .zero - scrollView.scrollIndicatorInsets = .zero + scrollView.contentInset = zeroInsets + scrollView.scrollIndicatorInsets = zeroInsets } } diff --git a/ios/LibreOfficeLight/LibreOfficeLight/LOKit/DocumentHolder.swift b/ios/LibreOfficeLight/LibreOfficeLight/LOKit/DocumentHolder.swift index a380cc45edd0..c0760b8614a4 100644 --- a/ios/LibreOfficeLight/LibreOfficeLight/LOKit/DocumentHolder.swift +++ b/ios/LibreOfficeLight/LibreOfficeLight/LOKit/DocumentHolder.swift @@ -26,17 +26,31 @@ public class DocumentHolder public let documentSize: CGSize public let views: Int32 public let parts: Int32 + public let partNames: [String] public private(set) var currentPart: Int32 = 0 init(doc: Document) { self.doc = doc + + // we go and get a bunch of document properties and store them in properties + // this allows easy access to these without threading issues + // when we get to editing they will have to be invalidated + self.documentType = doc.getDocumentType() documentSize = doc.getDocumentSizeAsCGSize() views = doc.getViewsCount() parts = doc.getParts() + var partNames = [String]() + for i in 0..<parts + { + let n = doc.getPartName(nPart: i) ?? "" + partNames.append(n) + } + self.partNames = partNames + doc.registerCallback() { [weak self] typ, payload in self?.onDocumentEvent(type: typ, payload: payload) diff --git a/ios/LibreOfficeLight/LibreOfficeLight/UIViewExtensions.swift b/ios/LibreOfficeLight/LibreOfficeLight/UIViewExtensions.swift new file mode 100644 index 000000000000..1c0322331e51 --- /dev/null +++ b/ios/LibreOfficeLight/LibreOfficeLight/UIViewExtensions.swift @@ -0,0 +1,74 @@ +// +// This file is part of the LibreOffice project. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +import UIKit + +public extension UIView +{ + public var height: CGFloat + { + get + { + return frame.size.height + } + set + { + frame.size.height = newValue + } + } + + public var size: CGSize + { + get + { + return frame.size + } + set + { + width = newValue.width + height = newValue.height + } + } + + public var width: CGFloat + { + get + { + return frame.size.width + } + set + { + frame.size.width = newValue + } + } + + public var x: CGFloat + { + get + { + return frame.origin.x + } + set + { + frame.origin.x = newValue + } + } + + + public var y: CGFloat + { + get + { + return frame.origin.y + } + set + { + frame.origin.y = newValue + } + } +} diff --git a/ios/LibreOfficeLight/LibreOfficeLight/en.lproj/Main.storyboard b/ios/LibreOfficeLight/LibreOfficeLight/en.lproj/Main.storyboard index ccc91115c5e0..ffd5059d06a9 100755 --- a/ios/LibreOfficeLight/LibreOfficeLight/en.lproj/Main.storyboard +++ b/ios/LibreOfficeLight/LibreOfficeLight/en.lproj/Main.storyboard @@ -30,6 +30,11 @@ <outlet property="delegate" destination="vXZ-lx-hvc" id="mWv-AB-k2W"/> </connections> </scrollView> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8HF-MM-fd0" userLabel="ButtonBar" customClass="ButtonScrollView" customModule="LibreOfficeLight" customModuleProvider="target"> + <rect key="frame" x="0.0" y="980" width="768" height="44"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </view> <view opaque="NO" userInteractionEnabled="NO" alpha="0.5" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="URZ-zU-xtO" userLabel="Mask"> <rect key="frame" x="0.0" y="64" width="768" height="960"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> @@ -76,6 +81,7 @@ </navigationItem> <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/> <connections> + <outlet property="buttonScrollView" destination="8HF-MM-fd0" id="Mlq-CV-p8N"/> <outlet property="mask" destination="URZ-zU-xtO" id="pkw-v3-0gr"/> <outlet property="progressBar" destination="hRJ-mR-Vnv" id="4lJ-kG-9SW"/> <outlet property="scrollView" destination="cJ7-wO-9D1" id="U50-LO-plb"/> |