Resolve #17 ObservableList

This commit is contained in:
Igor Zapletnev
2016-05-16 18:37:14 +02:00
parent c1702b6b54
commit 1111ecf2ae
4 changed files with 229 additions and 9 deletions
+12
View File
@@ -26,6 +26,7 @@
66AE19D21CC8C6B300B78B5E /* SVGParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66AE19D11CC8C6B300B78B5E /* SVGParser.swift */; };
AD9EDEE3709C1668BED1B1BF /* Pods_Macaw.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA114AD1025D7DA0B0DC35A8 /* Pods_Macaw.framework */; };
B0086C561C789758008A4F69 /* GroupRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0086C551C789758008A4F69 /* GroupRenderer.swift */; };
B0090DBF1CEA1EDD0018D77C /* ObservableList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0090DBE1CEA1EDD0018D77C /* ObservableList.swift */; };
B03275E51C78772F000BDD33 /* Align.swift in Sources */ = {isa = PBXBuildFile; fileRef = B03275B21C78772F000BDD33 /* Align.swift */; };
B03275E61C78772F000BDD33 /* AspectRatio.swift in Sources */ = {isa = PBXBuildFile; fileRef = B03275B31C78772F000BDD33 /* AspectRatio.swift */; };
B03275E71C78772F000BDD33 /* Baseline.swift in Sources */ = {isa = PBXBuildFile; fileRef = B03275B41C78772F000BDD33 /* Baseline.swift */; };
@@ -103,6 +104,7 @@
66AE19D11CC8C6B300B78B5E /* SVGParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SVGParser.swift; path = svg/SVGParser.swift; sourceTree = "<group>"; };
8A680FA7BCDE96402C10D8D2 /* Pods-Macaw.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Macaw.release.xcconfig"; path = "Pods/Target Support Files/Pods-Macaw/Pods-Macaw.release.xcconfig"; sourceTree = "<group>"; };
B0086C551C789758008A4F69 /* GroupRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupRenderer.swift; sourceTree = "<group>"; };
B0090DBE1CEA1EDD0018D77C /* ObservableList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObservableList.swift; sourceTree = "<group>"; };
B02E75D61C160F8D00D1971D /* Macaw.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Macaw.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B02E76131C1612A900D1971D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B03275B21C78772F000BDD33 /* Align.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Align.swift; sourceTree = "<group>"; };
@@ -237,6 +239,14 @@
name = svg;
sourceTree = "<group>";
};
B0090DBD1CEA1ECE0018D77C /* bindings */ = {
isa = PBXGroup;
children = (
B0090DBE1CEA1EDD0018D77C /* ObservableList.swift */,
);
path = bindings;
sourceTree = "<group>";
};
B02E75CC1C160F8D00D1971D = {
isa = PBXGroup;
children = (
@@ -259,6 +269,7 @@
isa = PBXGroup;
children = (
66AE19D01CC8C66E00B78B5E /* svg */,
B0090DBD1CEA1ECE0018D77C /* bindings */,
5742238C1CA540F8001EE463 /* animation */,
B03275B01C78772F000BDD33 /* model */,
585C04461C27CFB100335FF2 /* views */,
@@ -567,6 +578,7 @@
B03275ED1C78772F000BDD33 /* FontWeight.swift in Sources */,
B03275F61C78772F000BDD33 /* Cubic.swift in Sources */,
66AE19D21CC8C6B300B78B5E /* SVGParser.swift in Sources */,
B0090DBF1CEA1EDD0018D77C /* ObservableList.swift in Sources */,
574223901CA5448C001EE463 /* Animation.swift in Sources */,
585C04481C27CFB100335FF2 /* MacawView.swift in Sources */,
);
+212
View File
@@ -0,0 +1,212 @@
//
// https://github.com/safx/ObservableArray-RxSwift
// ObservableArray.swift
// ObservableArray
//
// Created by Safx Developer on 2015/02/19.
// Copyright (c) 2016 Safx Developers. All rights reserved.
//
import Foundation
import RxSwift
public struct ArrayChangeEvent {
public let insertedIndices: [Int]
public let deletedIndices: [Int]
public let updatedIndices: [Int]
private init(inserted: [Int] = [], deleted: [Int] = [], updated: [Int] = []) {
assert(inserted.count + deleted.count + updated.count > 0)
self.insertedIndices = inserted
self.deletedIndices = deleted
self.updatedIndices = updated
}
}
public struct ObservableArray<Element>: ArrayLiteralConvertible {
public typealias EventType = ArrayChangeEvent
internal var eventSubject: PublishSubject<EventType>!
internal var elementsSubject: PublishSubject<[Element]>!
internal var elements: [Element]
public init() {
self.elements = []
}
public init(count:Int, repeatedValue: Element) {
self.elements = Array(count: count, repeatedValue: repeatedValue)
}
public init<S : SequenceType where S.Generator.Element == Element>(_ s: S) {
self.elements = Array(s)
}
public init(arrayLiteral elements: Element...) {
self.elements = elements
}
public init(array elements: [Element]) {
self.elements = elements
}
}
extension ObservableArray {
public mutating func rx_elements() -> Observable<[Element]> {
if elementsSubject == nil {
self.elementsSubject = PublishSubject<[Element]>()
}
return elementsSubject
}
public mutating func rx_events() -> Observable<EventType> {
if eventSubject == nil {
self.eventSubject = PublishSubject<EventType>()
}
return eventSubject
}
private func arrayDidChange(event: EventType) {
elementsSubject?.onNext(elements)
eventSubject?.onNext(event)
}
}
extension ObservableArray: Indexable {
public var startIndex: Int {
return elements.startIndex
}
public var endIndex: Int {
return elements.endIndex
}
}
extension ObservableArray: RangeReplaceableCollectionType {
public var capacity: Int {
return elements.capacity
}
public mutating func reserveCapacity(minimumCapacity: Int) {
elements.reserveCapacity(minimumCapacity)
}
public mutating func append(newElement: Element) {
elements.append(newElement)
arrayDidChange(ArrayChangeEvent(inserted: [elements.count - 1]))
}
public mutating func appendContentsOf<S : SequenceType where S.Generator.Element == Element>(newElements: S) {
let end = elements.count
elements.appendContentsOf(newElements)
guard end != elements.count else {
return
}
arrayDidChange(ArrayChangeEvent(inserted: Array(end..<elements.count)))
}
public mutating func appendContentsOf<C : CollectionType where C.Generator.Element == Element>(newElements: C) {
guard !newElements.isEmpty else {
return
}
let end = elements.count
elements.appendContentsOf(newElements)
arrayDidChange(ArrayChangeEvent(inserted: Array(end..<elements.count)))
}
public mutating func removeLast() -> Element {
let e = elements.removeLast()
arrayDidChange(ArrayChangeEvent(deleted: [elements.count]))
return e
}
public mutating func insert(newElement: Element, atIndex i: Int) {
elements.insert(newElement, atIndex: i)
arrayDidChange(ArrayChangeEvent(inserted: [i]))
}
public mutating func removeAtIndex(index: Int) -> Element {
let e = elements.removeAtIndex(index)
arrayDidChange(ArrayChangeEvent(deleted: [index]))
return e
}
public mutating func removeAll(keepCapacity: Bool = false) {
guard !elements.isEmpty else {
return
}
let es = elements
elements.removeAll(keepCapacity: keepCapacity)
arrayDidChange(ArrayChangeEvent(deleted: Array(0..<es.count)))
}
public mutating func insertContentsOf(newElements: [Element], atIndex i: Int) {
guard !newElements.isEmpty else {
return
}
elements.insertContentsOf(newElements, at: i)
arrayDidChange(ArrayChangeEvent(inserted: Array(i..<i + newElements.count)))
}
public mutating func replaceRange<C : CollectionType where C.Generator.Element == Element>(subRange: Range<Int>, with newCollection: C) {
let oldCount = elements.count
elements.replaceRange(subRange, with: newCollection)
guard let first = subRange.first else {
return
}
let newCount = elements.count
let end = first + (newCount - oldCount) + subRange.count
arrayDidChange(ArrayChangeEvent(inserted: Array(first..<end),
deleted: Array(subRange)))
}
public mutating func popLast() -> Element? {
let e = elements.popLast()
if e != nil {
arrayDidChange(ArrayChangeEvent(deleted: [elements.count]))
}
return e
}
}
extension ObservableArray: CustomDebugStringConvertible {
public var description: String {
return elements.description
}
}
extension ObservableArray: CustomStringConvertible {
public var debugDescription: String {
return elements.debugDescription
}
}
extension ObservableArray: CollectionType {
public subscript(index: Int) -> Element {
get {
return elements[index]
}
set {
elements[index] = newValue
if index == elements.count {
arrayDidChange(ArrayChangeEvent(inserted: [index]))
} else {
arrayDidChange(ArrayChangeEvent(updated: [index]))
}
}
}
public subscript(bounds: Range<Int>) -> ArraySlice<Element> {
get {
return elements[bounds]
}
set {
elements[bounds] = newValue
guard let first = bounds.first else {
return
}
arrayDidChange(ArrayChangeEvent(inserted: Array(first..<first + newValue.count),
deleted: Array(bounds)))
}
}
}
+2 -6
View File
@@ -3,14 +3,10 @@ import RxSwift
public class Group: Node {
public let contentsVar: Variable<[Node]>
public var contents: [Node] {
get { return contentsVar.value }
set(val) { contentsVar.value = val }
}
public var contents: ObservableArray<Node>
public init(contents: [Node] = [], pos: Transform = Transform(), opaque: NSObject = true, visible: NSObject = true, clip: Locus? = nil, tag: [String] = []) {
self.contentsVar = Variable<[Node]>(contents)
self.contents = ObservableArray<Node>(array: contents)
super.init(
pos: pos,
opaque: opaque,
+3 -3
View File
@@ -20,13 +20,13 @@ class GroupRenderer: NodeRenderer {
func onGroupChange(new: [Node]) {
ctx.view.setNeedsDisplay()
}
group.contentsVar.asObservable().subscribeNext { new in
onGroupChange(new)
group.contents.rx_events().subscribeNext { new in
onGroupChange(self.group.contents.elements)
}.addDisposableTo(disposeBag)
}
func render() {
let contentRenderers = group.contents.map { RenderUtils.createNodeRenderer($0, context: ctx) }
let contentRenderers = self.group.contents.map { RenderUtils.createNodeRenderer($0, context: ctx) }
contentRenderers.forEach { renderer in
if let rendererVal = renderer {
CGContextSaveGState(ctx.cgContext)