Swiftpack.co - Holistic-Apps-LTDA/DeclarativeUI as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by Holistic-Apps-LTDA.
Holistic-Apps-LTDA/DeclarativeUI 0.0.8
A library to develop UI declaratively in Swift.
⭐️ 2
🕓 2 weeks ago
iOS
.package(url: "https://github.com/Holistic-Apps-LTDA/DeclarativeUI.git", from: "0.0.8")

DeclarativeUI

A library to develop UI declaratively in Swift.

Requirements

Platform Minimum Swift Version Installation Status
iOS 11.0+ 5.0 CocoaPods, Carthage, Swift Package Manager Partially Tested

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate DeclarativeUI into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'DeclarativeUUI', '~> 0.0.8'

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate DeclarativeUI into your Xcode project using Carthage, specify it in your Cartfile:

github "Holistic-Apps-LTDA/DeclarativeUI" ~> 0.0.8

In terminal run:

carthage update --use-xcframeworks

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.

Once you have your Swift package set up, adding DeclarativeUI as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/Holistic-Apps-LTDA/DeclarativeUI.git", .upToNextMajor(from: "0.0.8"))
]

Usage

A demo app is available in the DemoApp folder for querying the usage of library components.

ViewModel

enum DemoInteractionEvents {
    case rowSelect(DataObject)
    case iconTap
}

import DeclarativeUI

final class DemoViewModel: DeclarativeViewModel<Void, Error> {

    // MARK: Attributes

    let interactionEvents = Publisher<DemoInteractionEvents>()
    let data: DataObject
    
    // MARK: Life Cycle

    init(data: DataObject) {
        self.data = data
        super.init()
    }
}

ViewController

import DeclarativeUI

final class DemoViewController: DeclarativeViewController {

    // MARK: Attributes

    public lazy var viewController = ViewController(view: view)
    private let viewModel: DemoViewModel
    
    private lazy var titlelLabel = Label(
        text: viewModel.data.title,
        style: .systemFont()
    )
    
    private lazy var detailLabel = Label(
        text: viewModel.data.detail
        style: .boldSystemFont()
    )

    private lazy var valueLabel = Label(
        text: viewModel.data.value
        style: .boldSystemFont()
    )

    private let icon = Image()
        .size(width: .medium, height: .medium)
        .image(viewModel.data.icon)
        
    private lazy var view = StackView(.vertical) {
        Spacer(.small)
        titlelLabel
        Spacer(.small)
        StackView(.horizontal) {
            icon
            detailLabel
        }.spacing(.extraSmall)
        .alignment(.leading)
        Spacer(.medium)
        valueLabel       
        Spacer(.flexible)
    }.padding(.uniform(.small))
    
    // MARK: Life Cycle

    public init(viewModel: DemoViewModel) {
        self.viewModel = viewModel
    }
}

Component

import DeclarativeUI

public class Pager: DeclarativeComponent {
    public lazy var view = stackView
    
    private lazy var stackView = StackView(.horizontal)
        .distribution(.fillEqually)
        .alignment(.center)
        .spacing(.zero)
        
    private var buttons = [Page](https://raw.github.com/Holistic-Apps-LTDA/DeclarativeUI/main/)
    private var selectedIndex = Publisher<Int>()
    private let initialIndexSelected: Int
    
    public init(_ options: [String],
                indexSelected: Int = 0) {
        initialIndexSelected = indexSelected
        options.enumerated().forEach { index, value in
            let button = Page(value)
                .onTap { [weak self] in
                    self?.selectedIndex.publish(index)
                }
            if index == initialIndexSelected {
                button.selectLayout()
            } else {
                button.normalLayout()
            }
            buttons.append(button)
        }
        stackView.update {
            buttons as [UIViewConvertible]
        }
        
        bindSelectedIndex()
    }
    
    private func bindSelectedIndex() {
        observe(selectedIndex) { [stackView, buttons] vc, indexSelected in
            vc.buttons.enumerated().forEach { index, button in
                if index == indexSelected {
                    button.selectLayout()
                } else {
                    button.normalLayout()
                }
            }
            stackView.update {
                buttons as [UIViewConvertible]
            }
        }
    }
    
    @discardableResult
    public func didChangeValue(_ action: @escaping (Int?) -> Void) -> Self {
        selectedIndex.subscribe().onNext { _, value in
            action(value)
        }.disposedBy(self)
        return self
    }
}

private class Page: DeclarativeComponent {
    public lazy var view = ContainerView { stackView }
    private let title = Label(style: .systemFont())
    private let line = EmptyView()
        .backgroundColor(.white)
        .height(.extraSmall2)
        .cornerRadius(.extraSmall3)
    
    private lazy var stackView = StackView(.vertical) {
        title
            .alignment(.center)
        Spacer(.extraSmall)
        line
    }.distribution(.fill)

    public init(_ title: String) {
        self.title.text(title)
    }
    
    public func selectLayout() {
        title.style(.boldSystemFont())
        line.backgroundColor(.black)
    }
    
    public func normalLayout() {
        title.style(.systemFont())
        line.backgroundColor(.white)
    }
}

Preview

import SwiftUI
@available(iOS 13.0.0, *)
struct Pager_Previews: PreviewProvider {
    static var previews: some View {
        ViewContainer(view: pager)
            .previewDevice("iPhone 12")
    }

    static var pager = StackView(.vertical) {
        Spacer(.large)
        Pager(["Option 1", "Option 2", "Option 3"])
    }.padding(.horizontal(.medium))
}

Coordinator

import DeclarativeUI

public final class DemoCoordinator: DeclarativeCoordinator {
        
    // MARK: Life Cycle
    
    public init() {
        super.init()
        start()
    }
    
    public func start() {
        navigateToDemo()
    }
    
    private func navigateToDemo() {
        let viewModel = DemoViewModel(data: DataObject())
        
        let viewController = DemoViewController(viewModel: viewModel)
            .navigationBarOptions([.back, .close])
            .navigationTitle("Title Navigation Bar")

        viewModel.interactionEvents.subscribe().onNext { event in
            switch event {
            case .rowSelect(let data):
                self.navigateToDemoDetail(data: data)
            case .iconOnTap:
                self.navigateToIconTap()
            }
        }.disposedBy(self)

        navigator.push(viewController)
    }
}

GitHub

link
Stars: 2
Last commit: 2 weeks ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Related Packages

Release Notes

2 weeks ago

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics