Latest 0.6.9
Homepage https://github.com/feilfeilundfeil/Cyanic
License MIT
Platforms ios 10.0, requires ARC
Dependencies LayoutKit, RxDataSources, RxSwift, Sourcery
Authors , ,

Cyanic is an iOS framework created at Feil, Feil, & Feil GmbH in response to a need for state-driven UI. It borrows heavily
from the concepts of Airbnb’s MvRx framework (which our Android developers use) to create a very similar
code base with Android thereby unifying the business logic in both platforms. We use this framework to create complex, performant, and reactive
screens in our projects.

Cyanic is a Swift only framework. There are no plans to make it compatible with Objective-C.

Installation

CocoaPods

Requirements:

  • Swift 5.0+
  • iOS 10.0+
  1. Add the following to your Podfile:

    pod 'Cyanic'
    pod 'LayoutKit', :git => 'https://github.com/hooliooo/LayoutKit.git' // Use this fork until LayoutKit is updated
  2. Integrate your dependencies using frameworks: add use_frameworks! to your Podfile.
  3. Run pod install.

Why we use a forked version of LayoutKit

LayoutKit is the library that is responsible for most of the UI logic in Cyanic. However, as of April 17, 2019, there are some limitations to the current LayoutKit version in Cocoapods:

  1. It is not updated to use Swift 5
  2. Cyanic needs access to an internal initializer of the Layouts that allows you to declare the UIView subclass type as an argument.

Without these changes, Cyanic will continue to use the forked version.

Documentation

Check out our wiki for full documentation.

A Simple Example

A very simple example with expandable functionality:

struct YourState: ExpandableState {

    enum Section: String, CaseIterable {
        case first
        case second
    }

    static var `default`: YourState { 
        return YourState(
            text: "Hello, World!",
            expandableDict: YourState.Section.allCases.map { $0.rawValue }
                .reduce(into: [String: Bool](), { (current: inout [String: Bool], id: String) -> Void in
                    current[id] = false
                }
        ) 
    } 

    var text: String
    var expandableDict: [String: Bool]
}

class YourViewModel: ViewModel<YourState> {
    func showCyanic() {
        self.setState { $0.text = "Hello, Cyanic!" }
    }
}

class YourComponentViewController: SingleSectionCollectionComponentViewController {

    private let viewModel: YourViewModel = YourViewModel(initialState: YourState.default)

    override var viewModels: [AnyViewModel] {
        return [self.viewModel.asAnyViewModel]
    }

    override func buildComponents(_ componentsController: inout ComponentsController) {
        withState(self.viewModel) { (state: YourState) -> Void in
            componentsController.staticTextComponent {
                $0.id = "title"
                $0.text = state.text
            }

            componentsController.buttonComponent {
                $0.id = "button"
                $0.onTap = { [weak self]
                    self?.viewModel.showCyanic()
                }
            }

            let firstExpandableID: String = YourState.Section.first.rawValue

            let yourExpandable = components.expandableComponent { [weak self] in
                guard let s = self else { return }
                $0.id = firstExpandableID
                $0.contentLayout = LabelContentLayout(text: Text.unattributed("Hello, World!"))
                $0.isExpanded = state.expandableDict[firstExpandableID] ?? false
                $0.setExpandableState = self.viewModel.setExpandableState
                $0.backgroundColor = UIColor.lightGray
                $0.height = 55.0
            }

            // These ButtonComponents will only show up when yourExpandable is expanded.
            if yourExpandable.isExpanded {
                for number in 1...5 {
                    componentsController.buttonComponent {
                        $0.id = "button(number)"
                        $0.title = "(number)"
                        $0.onTap = { [weak self]
                            print("Hello, World from Button (number)")
                        }
                    }
                }
            }
        }
    }
}

Contributors

Latest podspec

{
    "name": "Cyanic",
    "version": "0.6.9",
    "summary": "Cyanic is a MvRx and Epoxy inspired framework that aims to build a reactive UI in a UICollectionView/UITableView.",
    "description": "Cyanic is a MvRx and Epoxy inspired framework that aims to build reactive UI in a UICollectionView/UITableView.nIt borrows heavily from MvRx in terms of API and structure while falling within the constraints ofnSwift and iOS development. It leverages RxSwift to have reactive functionality, LayoutKit to havenperformance close to manual layout when sizing and arranging subviews, and Sourcery for fast creation ofncustom components. It uses an Model-View-ViewModel (MVVM) style of architecture.",
    "homepage": "https://github.com/feilfeilundfeil/Cyanic",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    },
    "authors": [
        "Feil, Feil, & Feil GmbH",
        "Julio Alorro",
        "Jonas Bark"
    ],
    "platforms": {
        "ios": "10.0"
    },
    "source": {
        "git": "https://github.com/feilfeilundfeil/Cyanic.git",
        "tag": "0.6.9"
    },
    "source_files": [
        "Sources/**/*.swift",
        "Sources/Components/**/*.swift"
    ],
    "resources": [
        "Templates/*"
    ],
    "requires_arc": true,
    "swift_version": "5.0",
    "dependencies": {
        "LayoutKit": [],
        "RxDataSources": [],
        "RxSwift": [],
        "Sourcery": []
    },
    "testspecs": [
        {
            "name": "Tests",
            "test_type": "unit",
            "source_files": "Tests/*.swift",
            "dependencies": {
                "Quick": [],
                "Nimble": []
            }
        }
    ]
}

Pin It on Pinterest

Share This