diff --git a/Playgrounds/NumswPlayground.swift b/Playgrounds/NumswPlayground.swift index 44d84f3..c6f0f71 100644 --- a/Playgrounds/NumswPlayground.swift +++ b/Playgrounds/NumswPlayground.swift @@ -13,29 +13,33 @@ import CoreGraphics #endif public class NumswPlayground { + internal init() { #if os(iOS) - viewController = RenderTableViewController() + viewController = RenderTableViewController(state: viewState) #endif } #if os(iOS) public let viewController: RenderTableViewController + internal let viewState = RenderTableViewController.State() #endif - public func append(renderer: ChartRenderer) { - renderers.append(renderer) + public func append(renderer: Renderer) { + #if os(iOS) + viewController.append(renderer: renderer) + #endif } #if os(iOS) public func print(_ matrix: Matrix) { let matrixTextRenderer = MatrixTextRenderer(matrix) - renderers.append(matrixTextRenderer) + append(renderer: matrixTextRenderer) } public func print(_ string: String) { let textRenderer = TextRenderer(string) - renderers.append(textRenderer) + append(renderer: textRenderer) } #endif @@ -85,13 +89,14 @@ public class NumswPlayground { return _shared! } - private var renderers: [Renderer] = [] { + //private var renderers: [Renderer] = [] + /*private var renderers: [ChartRenderer] = [] { didSet { #if os(iOS) - viewController.renderers = renderers.map { $0 as Renderer } + viewController.replace(renderers: renderers.map { $0 as Renderer }) #endif } - } + }*/ private var chartBuilder: ChartBuilder? diff --git a/Playgrounds/PlaygroundKeyValueStore.swift b/Playgrounds/PlaygroundKeyValueStore.swift new file mode 100644 index 0000000..ebc7723 --- /dev/null +++ b/Playgrounds/PlaygroundKeyValueStore.swift @@ -0,0 +1,68 @@ +// +// PlaygroundKeyValueStore.swift +// sandbox +// +// Created by Yusuke Ito on 4/16/17. +// Copyright © 2017 sonson. All rights reserved. +// + + +// PlaygroundKeyValueStore as UserDefautls for sandbox app + +#if os(iOS) +import Foundation + + +#if SANDBOX_APP + // sandbox app + internal enum PlaygroundValue { + case array([PlaygroundValue]) + case boolean(Bool) + case data(Data) + case date(Date) + case dictionary([String: PlaygroundValue]) + case floatingPoint(Double) + case integer(Int) + case string(String) + } + internal class PlaygroundKeyValueStore { + static let current = PlaygroundKeyValueStore() + private init() { + + } + subscript(key: String) -> PlaygroundValue? { + set { + print("KeyValueStore setting \(newValue as Any) for \(key)") + if let value = newValue { + switch value { + case .floatingPoint(let double): + UserDefaults.standard.set(double, forKey: key) + case .integer(let integer): + UserDefaults.standard.set(integer, forKey: key) + default: + fatalError("Not implemented") + } + } else { + UserDefaults.standard.removeObject(forKey: key) + } + } + get { + print("KeyValueStore getting for \(key)") + guard let object = UserDefaults.standard.object(forKey: key) else { + return nil + } + if let integer = object as? Int { + return .integer(integer) + } else if let double = object as? Double { + return .floatingPoint(double) + } else { + fatalError("Not implemented") + } + } + } + } +#else + // playground +#endif + +#endif diff --git a/Playgrounds/RenderTableViewCell.swift b/Playgrounds/RenderTableViewCell.swift index dffec98..43322ed 100644 --- a/Playgrounds/RenderTableViewCell.swift +++ b/Playgrounds/RenderTableViewCell.swift @@ -10,6 +10,8 @@ import UIKit internal class RenderTableViewCell: UITableViewCell { + + private static let renderQueue = DispatchQueue(label: "Renderer-Queue") var renderer: Renderer? { willSet { @@ -22,7 +24,7 @@ internal class RenderTableViewCell: UITableViewCell { override init(style: UITableViewCellStyle, reuseIdentifier: String?) { super.init(style: .default, reuseIdentifier: reuseIdentifier) - print("RenderTableViewCell init") + //print("RenderTableViewCell init") self.separatorInset = .zero self.selectionStyle = .none renderImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] @@ -36,14 +38,18 @@ internal class RenderTableViewCell: UITableViewCell { } deinit { - print("RenderTableViewCell deinit") + //print("RenderTableViewCell deinit") } private var renderedImageSize = CGSize.zero + private var isImageViewDirty: Bool { + return renderedImageSize != self.contentView.bounds.size + } + func updateImageViewIfNeeded() { print("rendering bounds: \(self.contentView.bounds)") - if renderedImageSize == self.contentView.bounds.size && + if isImageViewDirty == false && self.renderImageView.image != nil { // already rendered return @@ -53,9 +59,23 @@ internal class RenderTableViewCell: UITableViewCell { private func updateImageView() { guard let renderer = self.renderer else { return } - let image = renderer.renderToImage(size: self.contentView.bounds.size) - self.renderImageView.image = image + let withFadeAnimation = isImageViewDirty && self.renderImageView.image != nil + renderedImageSize = self.contentView.bounds.size + type(of: self).renderQueue.async { + let image = renderer.renderToImage(size: self.contentView.bounds.size) + DispatchQueue.main.async { + self.renderImageView.image = image + + if withFadeAnimation { + let transition = CATransition() + transition.duration = 0.25 + transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) + transition.type = kCATransitionFade + self.renderImageView.layer.add(transition, forKey: nil) + } + } + } } } #endif diff --git a/Playgrounds/RenderTableViewController.swift b/Playgrounds/RenderTableViewController.swift index f1a00dc..522bd48 100755 --- a/Playgrounds/RenderTableViewController.swift +++ b/Playgrounds/RenderTableViewController.swift @@ -10,10 +10,18 @@ #if os(iOS) import UIKit +import QuartzCore +#if SANDBOX_APP + // sandbox app +#else + // playground + import PlaygroundSupport +#endif + public class RenderTableViewController: UITableViewController, UZTextViewDelegate { - var renderers: [Renderer] = [] { + private var renderers: [Renderer] = [] { didSet { for i in 0.. Int { @@ -98,5 +185,30 @@ public class RenderTableViewController: UITableViewController, UZTextViewDelegat public func selectingStringEnded(_ textView: UZTextView) { self.tableView.isScrollEnabled = true } + + #if SANDBOX_APP + // Tap any table view cell to dismiss + public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + self.navigationController?.popViewController(animated: true) + } + #endif + + public override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + storeTableViewScrollOffset() + } + + public override func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { + storeTableViewScrollOffset() + } + + public override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { + storeTableViewScrollOffset() + } + + private func storeTableViewScrollOffset() { + // store tableview scroll offset + state.tableViewScrollOffset = tableView.contentOffset + state.sync() + } } #endif diff --git a/Playgrounds/sandbox/sandbox.xcodeproj/project.pbxproj b/Playgrounds/sandbox/sandbox.xcodeproj/project.pbxproj index c6dd7eb..a9b0a24 100644 --- a/Playgrounds/sandbox/sandbox.xcodeproj/project.pbxproj +++ b/Playgrounds/sandbox/sandbox.xcodeproj/project.pbxproj @@ -19,6 +19,8 @@ 148967C11E9786D900F19D91 /* TextTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 148967C01E9786D900F19D91 /* TextTableViewCell.swift */; }; 148967C31E9786F400F19D91 /* RenderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 148967C21E9786F400F19D91 /* RenderTableViewCell.swift */; }; 148967C71E97921800F19D91 /* SelectTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 148967C61E97921800F19D91 /* SelectTableViewController.swift */; }; + 52CCAD111EA3913500D6D6EB /* PlaygroundKeyValueStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CCAD101EA3913500D6D6EB /* PlaygroundKeyValueStore.swift */; }; + 52CCAD121EA3913500D6D6EB /* PlaygroundKeyValueStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CCAD101EA3913500D6D6EB /* PlaygroundKeyValueStore.swift */; }; D68EF7091E86C8C600927991 /* AxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A0B5BB1E6FE801004AE3B4 /* AxisRenderer.swift */; }; D68EF70A1E86C8C600927991 /* Chart.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A0B5BC1E6FE801004AE3B4 /* Chart.swift */; }; D68EF70B1E86C8C600927991 /* ChartBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A0B5BD1E6FE801004AE3B4 /* ChartBuilder.swift */; }; @@ -128,6 +130,7 @@ 148967C01E9786D900F19D91 /* TextTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TextTableViewCell.swift; path = ../TextTableViewCell.swift; sourceTree = ""; }; 148967C21E9786F400F19D91 /* RenderTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RenderTableViewCell.swift; path = ../RenderTableViewCell.swift; sourceTree = ""; }; 148967C61E97921800F19D91 /* SelectTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectTableViewController.swift; sourceTree = ""; }; + 52CCAD101EA3913500D6D6EB /* PlaygroundKeyValueStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaygroundKeyValueStore.swift; path = ../PlaygroundKeyValueStore.swift; sourceTree = ""; }; 52E1EE3E1E6A8A2E008D19BB /* sandboxTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = sandboxTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 52E1EE421E6A8A2E008D19BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D68EF6FD1E86C89600927991 /* NumswRenderer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NumswRenderer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -279,6 +282,7 @@ 144A150B1E971A1400B42288 /* MatrixTextRenderer.swift */, D6A0B5C41E6FE801004AE3B4 /* NumswPlayground_Playground.swift */, D6A0B5C51E6FE801004AE3B4 /* NumswPlayground.swift */, + 52CCAD101EA3913500D6D6EB /* PlaygroundKeyValueStore.swift */, D6A0B5C61E6FE801004AE3B4 /* Renderer.swift */, D6A0B5C91E6FE801004AE3B4 /* RendererUtil.swift */, D6A0B5CA1E6FE801004AE3B4 /* RenderScrollViewController.swift */, @@ -606,6 +610,7 @@ 144A150C1E971A1400B42288 /* MatrixTextRenderer.swift in Sources */, D68EF7101E86C8C600927991 /* LineGraph.swift in Sources */, 144A15101E971B9D00B42288 /* UZCursor.swift in Sources */, + 52CCAD111EA3913500D6D6EB /* PlaygroundKeyValueStore.swift in Sources */, D68EF7151E86C8C600927991 /* RendererUtil.swift in Sources */, 144A15131E971C0400B42288 /* UZLoupe.swift in Sources */, 144A15121E971B9D00B42288 /* UZTextView.swift in Sources */, @@ -630,6 +635,7 @@ D68EF77B1E86DA4C00927991 /* ScatterGraphRenderer.swift in Sources */, D68EF77C1E86DA4C00927991 /* ScatterGraph.swift in Sources */, D68EF77D1E86DA4C00927991 /* Renderer.swift in Sources */, + 52CCAD121EA3913500D6D6EB /* PlaygroundKeyValueStore.swift in Sources */, D68EF77E1E86DA4C00927991 /* DummyData.swift in Sources */, D68EF77F1E86DA4C00927991 /* RenderScrollViewController.swift in Sources */, D68EF7801E86DA4C00927991 /* LineGraph.swift in Sources */,