profile
viewpoint

badoo/Chatto 4304

A lightweight framework to build chat applications, made in Swift

badoo/android-weak-handler 1520

Memory safer implementation of android.os.Handler

badoo/Decompose 796

Kotlin Multiplatform lifecycle-aware business logic components (aka BLoCs) with routing functionality and pluggable UI (Jetpack Compose, SwiftUI, JS React, etc.), inspired by Badoos RIBs fork of the Uber RIBs framework

badoo/Chateau 680

Chateau is a framework for adding (or improving) chat functionality in any Android app

badoo/BMASpinningLabel 153

BMASpinningLabel is an UI component which provides easy way for displaying and animating text inside it

badoo/BMASliders 92

Configurable simple and range sliders

badoo/codeisok 87

Git code browsing and code review tool

badoo/balancer 42

Load balancer that was presented at HighLoad++ 2015 Conference in Moscow

badoo/BMACollectionViewLayouts 20

A set of UICollectionView layouts

issue openedbadoo/MVIKotlin

Mvi

created time in 2 hours

startedbadoo/Decompose

started time in 10 hours

fork makosblade/Reaktive

Kotlin multi-platform implementation of Reactive Extensions

fork in 15 hours

startedbadoo/Chatto

started time in a day

startedbadoo/MVIKotlin

started time in a day

push eventbadoo/marathon

Sergey Chelombitko

commit sha b4f60ea4ccbca65955918df40b65eacc99472469

Fix pulling large number of screenshots

view details

push time in 2 days

PullRequestReviewEvent

push eventbadoo/Chatto

Victor Shamanov

commit sha 230847a2283ed698111e894f029d7b21fee7e1dc

Add missing UIKit imports

view details

Victor Shamanov

commit sha 6d8607943fac21c0b934ea4e16092dbb3b7b6dd2

Fix method names in ContainerViewProtocols

view details

Victor Shamanov

commit sha 4c326e1d3fc9d5e6c3d469408b2231ff01ac7aff

Fix typo in CachingLayoutProvider name

view details

Victor Shamanov

commit sha a1c6b49f6d6e033cedd137cae2294d41abff0980

Group if statemets

view details

push time in 2 days

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++import Chatto+import ChattoAdditions++public final class ChatItemPresenter<ChatItem>: ChatItemPresenterProtocol {++    private typealias Key = AnyBindingKey+    private typealias ViewModels = [Key: Any]+    private typealias LayoutProviders = [Key: Any]+    private typealias Cell = ChatItemCell++    private let chatItem: ChatItem+    private let binder: Binder+    private let assembler: ViewAssembler+    private let layoutAssembler: LayoutAssembler+    private let factory: FactoryAggregate<ChatItem>+    private let reuseIdentifier: String++    private var viewModels: ViewModels?+    private var rootViewSizeProvider: AnySizeProvider?+    private var layoutProviders: LayoutProviders?+    private var lifecycleObservers: [ChatItemLifecycleViewModel] = []++    public init(chatItem: ChatItem,+                binder: Binder,+                assembler: ViewAssembler,+                layoutAssembler: LayoutAssembler,+                factory: FactoryAggregate<ChatItem>,+                reuseIdentifier: String) {+        self.chatItem = chatItem+        self.binder = binder+        self.assembler = assembler+        self.layoutAssembler = layoutAssembler+        self.factory = factory+        self.reuseIdentifier = reuseIdentifier+    }++    public static func registerCells(_ collectionView: UICollectionView) {+        fatalError("This method should not be called")+    }++    public static func registerCells(for collectionView: UICollectionView, with reuseID: String) {+        collectionView.register(Cell.self, forCellWithReuseIdentifier: reuseID)+    }++    public let isItemUpdateSupported: Bool = true++    // TODO: Implement support for updating #742+    public func update(with chatItem: ChatItemProtocol) {}++    public func heightForCell(maximumWidth width: CGFloat, decorationAttributes: ChatItemDecorationAttributesProtocol?) -> CGFloat {+        let context = LayoutContext(maxWidth: width)+        let provider = self.makeRootViewSizeProvider()+        do {+            return try provider.height(for: context)+        } catch {+            fatalError(error.localizedDescription)+        }+    }++    public func dequeueCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell {+        collectionView.dequeueReusableCell(withReuseIdentifier: self.reuseIdentifier, for: indexPath)+    }++    public func configureCell(_ cell: UICollectionViewCell, decorationAttributes: ChatItemDecorationAttributesProtocol?) {+        guard let cell = cell as? Cell else { fatalError() }+        do {+            let subviews = self.setupSubviews(of: cell)+            let viewModels = self.makeViewModels()+            self.lifecycleObservers = viewModels.values.compactMap { $0 as? ChatItemLifecycleViewModel }+            try self.binder.bind(subviews: subviews, viewModels: viewModels)+            let layoutProviders = self.makeLayoutProviders()+            let rootContext = LayoutContext(maxWidth: cell.bounds.width)+            try self.layoutAssembler.applyLayout(with: rootContext, views: subviews.subviews, layoutProviders: layoutProviders)+        } catch {+            fatalError(error.localizedDescription)+        }+    }++    public func cellWillBeShown(_ cell: UICollectionViewCell) {+        for observer in self.lifecycleObservers {+            observer.willShow()+        }+    }++    // TODO: Unify viewModels instantiation. We need to create everything at once #743+    private func makeViewModels() -> [Key: Any] {

Sounds great ;)

wiruzx

comment created time in 2 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++import Chatto+import ChattoAdditions++public final class ChatItemPresenterBuilder<ChatItem>: ChatItemPresenterBuilderProtocol, ChatItemPresenterBuilderCollectionViewConfigurable {++    private let binder: Binder+    private let assembler: ViewAssembler+    private let layoutAssembler: LayoutAssembler+    private let factory: FactoryAggregate<ChatItem>+    private let reuseIdentifier: String++    public init(binder: Binder,+                assembler: ViewAssembler,+                layoutAssembler: LayoutAssembler,+                factory: FactoryAggregate<ChatItem>) {+        self.binder = binder+        self.assembler = assembler+        self.factory = factory+        self.layoutAssembler = layoutAssembler+        self.reuseIdentifier = assembler.reuseIdentifier+    }++    // TODO: Implement me #744+    public func canHandleChatItem(_ chatItem: ChatItemProtocol) -> Bool {+        guard let item = chatItem as? ChatItem else { return false }+        //return self.binder.canHandle(item: item)+        return true+    }++    public func createPresenterWithChatItem(_ chatItem: ChatItemProtocol) -> ChatItemPresenterProtocol {

Also the part of the public protocol. I could create a separate issue to make the naming nicer, what do you think?

wiruzx

comment created time in 2 days

Pull request review commentbadoo/Chatto

Composable messages

 public final class ChatItemPresenterFactory: ChatItemPresenterFactoryProtocol {                 return builder.createPresenterWithChatItem(chatItem)             }         }-        return DummyChatItemPresenter()+        return self.fallbackItemPresenterFactory.createChatItemPresenter(chatItem)     }      public func configure(withCollectionView collectionView: UICollectionView) {         for presenterBuilder in self.presenterBuildersByType.flatMap({ $0.1 }) {-            presenterBuilder.presenterType.registerCells(collectionView)+            if let configurablePresenterBuilder = presenterBuilder as? ChatItemPresenterBuilderCollectionViewConfigurable {+                configurablePresenterBuilder.configure(with: collectionView)+            } else {+                presenterBuilder.presenterType.registerCells(collectionView)+            }         }+        self.fallbackItemPresenterFactory.configure(withCollectionView: collectionView)+    }+}++public final class DummyItemPresenterFactory: ChatItemPresenterFactoryProtocol {++    public init() {}++    public func createChatItemPresenter(_ chatItem: ChatItemProtocol) -> ChatItemPresenterProtocol {+        DummyChatItemPresenter()+    }++    public func configure(withCollectionView collectionView: UICollectionView) {

This one is part of public protocol, so not sure if it's a great idea to do renaming here.

I could rename the other one(configure(with collectionView: UICollectionView)), to match this function (configure(withCollectionView collectionView: UICollectionView)), but I'm going to remove the protocol completely: #761

wiruzx

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentbadoo/Chatto

Composable messages

 class DemoChatViewController: UIViewController {         ]     } -    class func createTextMessageViewModelBuilder() -> DemoTextMessageViewModelBuilder {-        return DemoTextMessageViewModelBuilder()+    private static func makeNewFallbackItemPresenterFactory() -> ChatItemPresenterFactoryProtocol {++        struct DummyItemPresenterFactory: ChatItemPresenterFactoryProtocol {++            typealias PresenterBuilder = ChatItemPresenterBuilderProtocol & ChatItemPresenterBuilderCollectionViewConfigurable++            let presenterBuilder: PresenterBuilder++            func createChatItemPresenter(_ chatItem: ChatItemProtocol) -> ChatItemPresenterProtocol {+                guard self.presenterBuilder.canHandleChatItem(chatItem) else { fatalError() }+                return self.presenterBuilder.createPresenterWithChatItem(chatItem)+            }++            func configure(withCollectionView collectionView: UICollectionView) {+                self.presenterBuilder.configure(with: collectionView)+            }+        }++        var factory = FactoryAggregate<ChatItemProtocol>()++        let dummy = factory.register(+            viewFactory: DummyContentViewFactory(),+            viewModelFactory: DummyViewModelFactory(),+            layoutProviderFactory: DummyLayoutProviderFactory()+        )++        var binder = Binder()+        binder.registerBinding(for: dummy)++        let assembler = ViewAssembler(root: dummy)+        var layoutAssembler = LayoutAssembler(rootKey: dummy)++        // TODO: Remove #746+        layoutAssembler.populateSizeProviders(for: dummy)++        let presenterBuilder = ChatItemPresenterBuilder(+            binder: binder,+            assembler: assembler,+            layoutAssembler: layoutAssembler,+            factory: factory+        )+        return DummyItemPresenterFactory(presenterBuilder: presenterBuilder)+    }++    private static func makeNewPresenterBuilders() -> [ChatItemType: [ChatItemPresenterBuilderProtocol]] {+        return [+            DemoTextMessageModel.chatItemType: [self.makeNewTextMessagePresenterBuilder()],+            ChatItemType.compoundItemType: [self.makeNewCompoundExamplePresenterBuilder()],+            DemoPhotoMessageModel.chatItemType: [self.makeNewImagePresenterBuilder()]+        ]+    }++    private static func makeNewImagePresenterBuilder() -> ChatItemPresenterBuilderProtocol {++        var factory = FactoryAggregate<DemoPhotoMessageModel>()++        let image = factory.register(+            viewFactory: AsyncImageViewFactory(),+            viewModelFactory: AsyncImageViewModelFactory(),+            layoutProviderFactory: AsyncImageLayoutProviderFactory()+        )++        let bubble = factory.register(+            viewFactory: MessageBubbleViewFactory(),+            viewModelFactory: MessageBubbleViewModelFactory(),+            layoutProviderFactory: MessageBubbleLayoutProviderFactory(configuration: .init(percentageToOccupy: 0.4))+        )++        var binder = Binder()++        binder.registerBinding(for: bubble)++        binder.registerBlockBinding(for: image) { view, viewModel in+            view.viewModel = viewModel+        }++        var assembler = ViewAssembler(root: bubble)+        assembler.register(child: image, parent: bubble)++        var layoutAssembler = LayoutAssembler(rootKey: bubble)+        layoutAssembler.register(child: image, for: bubble)++        // TODO: Remove #746+        layoutAssembler.populateSizeProviders(for: bubble)+        layoutAssembler.populateSizeProviders(for: image)++        return ChatItemPresenterBuilder(+            binder: binder,+            assembler: assembler,+            layoutAssembler: layoutAssembler,+            factory: factory+        )+    }++    private static func makeNewCompoundExamplePresenterBuilder() -> ChatItemPresenterBuilderProtocol {+        var factory = FactoryAggregate<DemoCompoundMessageModel>()++        let bubble = factory.register(+            viewFactory: MessageBubbleViewFactory(),+            viewModelFactory: MessageBubbleViewModelFactory(),+            layoutProviderFactory: MessageBubbleLayoutProviderFactory(configuration: .init(percentageToOccupy: 0.8))+        )++        let compound = factory.register(+            viewFactory: CompoundViewFactory(),+            viewModelFactory: CompoundViewModelFactory(),+            layoutProviderFactory: CompoundLayoutProviderFactory()+        )++        let first = factory.register(+            viewFactory: DummyContentViewFactory(),+            viewModelFactory: StaticDummyViewModelFactory(text: "first"),+            layoutProviderFactory: DummyLayoutProviderFactory()+        )++        let second = factory.register(+            viewFactory: DummyContentViewFactory(),+            viewModelFactory: StaticDummyViewModelFactory(text: "second"),+            layoutProviderFactory: DummyLayoutProviderFactory()+        )++        var binder = Binder()++        binder.registerBinding(for: bubble)+        binder.registerNoopBinding(for: compound)+        binder.registerBinding(for: first)+        binder.registerBinding(for: second)++        var assembler = ViewAssembler(root: bubble)

Going to tackle that one in #749

wiruzx

comment created time in 2 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++public struct LayoutAssembler {++    // MARK: - Type declarations++    public typealias Key = AnyBindingKey+    private typealias LayoutCache = [AnyBindingKey: AnyCachedLayoutProvider]++    public enum Error: Swift.Error {+        case notFound(Key)+        case internalInconsistency+        case layoutWasNotCalculated(Key)+    }++    private enum Composition {+        case single(AnyBindingKey)+        case multiple([AnyBindingKey])+    }++    // MARK: - Private properties++    private let rootKey: AnyBindingKey+    private var compositions: [AnyBindingKey: Composition] = [:]+    private var makeSizeProviders: [AnyBindingKey: (Any) throws -> AnySizeProvider] = [:]+    private var makeCachingProviders: [AnyBindingKey: (Any) throws -> AnyCachedLayoutProvider] = [:]+    private var layoutApplicators: [AnyBindingKey: (Any, Any) throws -> Void] = [:]++    // MARK: - Instantiation++    public init(rootKey: AnyBindingKey) {+        self.rootKey = rootKey+    }++    public init<Root: BindingKeyProtocol>(rootKey: Root) {+        self.init(rootKey: .init(rootKey))+    }++    // MARK: - Public API++    public mutating func register<Parent: BindingKeyProtocol>(child: AnyBindingKey, for parent: Parent) {+        self.compositions[.init(parent)] = .single(child)+    }++    public mutating func register<Parent: BindingKeyProtocol>(children: [AnyBindingKey], for parent: Parent) {+        self.compositions[.init(parent)] = .multiple(children)+    }++    // TODO: Remove #746+    public mutating func populateSizeProviders<Key: BindingKeyProtocol>(for key: Key)+        where Key.LayoutProvider.Layout: SizeContainer, Key.View: ManualLayoutViewProtocol, Key.View.Layout == Key.LayoutProvider.Layout {+        let erasedKey = AnyBindingKey(key)+        self.makeSizeProviders[erasedKey] = { anyLayoutProvider in+            guard let layoutProvider = anyLayoutProvider as? CachingLayoutProvder<Key.LayoutProvider.Layout> else {+                throw Error.internalInconsistency+            }+            return AnySizeProvider(layoutProvider)+        }+        self.makeCachingProviders[erasedKey] = { anyLayoutProvider in+            guard let layoutProvider = anyLayoutProvider as? Key.LayoutProvider else {+                throw Error.internalInconsistency+            }+            return CachingLayoutProvder(layoutProvider)+        }+        self.layoutApplicators[erasedKey] = { anyView, anyLayout in+            guard let view = anyView as? Key.View, let layout = anyLayout as? Key.LayoutProvider.Layout else {+                throw Error.internalInconsistency+            }+            view.apply(layout: layout)+        }+    }++    public func assembleRootSizeProvider(layoutProviders: [Key: Any]) throws -> AnySizeProvider {+        let key = self.rootKey+        var layoutCache: LayoutCache = [:]+        return try self.assemble(for: key, with: layoutProviders, layoutCache: &layoutCache)+    }++    // TODO: #747+    public func applyLayout(with context: LayoutContext, views: [Key: Any], layoutProviders: [Key: Any]) throws {+        var layoutCache: LayoutCache = [:]+        // TODO: Check keys+        let rootLayoutProvider = try self.assemble(for: self.rootKey, with: layoutProviders, layoutCache: &layoutCache)++        // perform layout to cache results+        _ = try rootLayoutProvider.layout(for: context)++        for (key, view) in views {+            guard let applicator = self.layoutApplicators[key] else {+                throw Error.notFound(key)+            }++            guard let cachedLayout = layoutCache[key]?.lastPerformedLayoutResult else {+                throw Error.layoutWasNotCalculated(key)+            }++            try applicator(view, cachedLayout)+        }+    }++    // MARK: - Private++    private func assemble(for key: Key, with providers: [Key: Any], layoutCache: inout LayoutCache) throws -> AnySizeProvider {+        guard let layoutProvider = providers[key] else {+            throw Error.notFound(key)+        }++        guard let makeSizeProvider = makeSizeProviders[key] else {+            throw Error.notFound(key)+        }++        guard let makeCachingProvider = makeCachingProviders[key] else {+            throw Error.notFound(key)+        }++        let resultLayoutProvider: Any+        switch self.compositions[key] {++        case .single(let childKey)?:+            let child = try self.assemble(for: childKey, with: providers, layoutCache: &layoutCache)+            guard var container = layoutProvider as? SingleContainerLayoutProviderProtocol else {+                throw Error.internalInconsistency+            }+            container.childLayoutProvider = child+            resultLayoutProvider = container++        case .multiple(let childrenKeys)?:+            let children: [AnySizeProvider] = try childrenKeys+                .map { try self.assemble(for: $0, with: providers, layoutCache: &layoutCache) }+            guard var container = layoutProvider as? MultipleContainerLayoutProviderProtocol else {+                throw Error.internalInconsistency+            }+            container.childrenLayoutProviders = children+            resultLayoutProvider = container++        case nil:+            resultLayoutProvider = layoutProvider++        }++        let cachingContainer = try makeCachingProvider(resultLayoutProvider)+        layoutCache[key] = cachingContainer+        let sizeProvider = try makeSizeProvider(cachingContainer)+        return sizeProvider+    }+}++public protocol AnyCachedLayoutProvider {+    var lastPerformedLayoutResult: Any? { get }+}++private final class CachingLayoutProvder<Layout: LayoutModel>: LayoutProviderProtocol {++    private let _layout: (LayoutContext) throws -> Layout++    private(set) var lastLayout: Layout?++    init<Base: LayoutProviderProtocol>(_ base: Base) where Base.Layout == Layout {+        self._layout = { try base.layout(for: $0) }+    }++    func layout(for context: LayoutContext) throws -> Layout {+        let layout = try self._layout(context)+        self.lastLayout = layout+        return layout+    }+}++extension CachingLayoutProvder: AnyCachedLayoutProvider {

Thanks!

wiruzx

comment created time in 2 days

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++import Chatto+import ChattoAdditions++public final class ChatItemPresenter<ChatItem>: ChatItemPresenterProtocol {++    private typealias Key = AnyBindingKey+    private typealias ViewModels = [Key: Any]+    private typealias LayoutProviders = [Key: Any]+    private typealias Cell = ChatItemCell++    private let chatItem: ChatItem+    private let binder: Binder+    private let assembler: ViewAssembler+    private let layoutAssembler: LayoutAssembler+    private let factory: FactoryAggregate<ChatItem>+    private let reuseIdentifier: String++    private var viewModels: ViewModels?+    private var rootViewSizeProvider: AnySizeProvider?+    private var layoutProviders: LayoutProviders?+    private var lifecycleObservers: [ChatItemLifecycleViewModel] = []++    public init(chatItem: ChatItem,+                binder: Binder,+                assembler: ViewAssembler,+                layoutAssembler: LayoutAssembler,+                factory: FactoryAggregate<ChatItem>,+                reuseIdentifier: String) {+        self.chatItem = chatItem+        self.binder = binder+        self.assembler = assembler+        self.layoutAssembler = layoutAssembler+        self.factory = factory+        self.reuseIdentifier = reuseIdentifier+    }++    public static func registerCells(_ collectionView: UICollectionView) {+        fatalError("This method should not be called")+    }++    public static func registerCells(for collectionView: UICollectionView, with reuseID: String) {+        collectionView.register(Cell.self, forCellWithReuseIdentifier: reuseID)+    }++    public let isItemUpdateSupported: Bool = true++    // TODO: Implement support for updating #742+    public func update(with chatItem: ChatItemProtocol) {}++    public func heightForCell(maximumWidth width: CGFloat, decorationAttributes: ChatItemDecorationAttributesProtocol?) -> CGFloat {+        let context = LayoutContext(maxWidth: width)+        let provider = self.makeRootViewSizeProvider()+        do {+            return try provider.height(for: context)+        } catch {+            fatalError(error.localizedDescription)+        }+    }++    public func dequeueCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell {+        collectionView.dequeueReusableCell(withReuseIdentifier: self.reuseIdentifier, for: indexPath)+    }++    public func configureCell(_ cell: UICollectionViewCell, decorationAttributes: ChatItemDecorationAttributesProtocol?) {+        guard let cell = cell as? Cell else { fatalError() }+        do {+            let subviews = self.setupSubviews(of: cell)+            let viewModels = self.makeViewModels()+            self.lifecycleObservers = viewModels.values.compactMap { $0 as? ChatItemLifecycleViewModel }+            try self.binder.bind(subviews: subviews, viewModels: viewModels)+            let layoutProviders = self.makeLayoutProviders()+            let rootContext = LayoutContext(maxWidth: cell.bounds.width)+            try self.layoutAssembler.applyLayout(with: rootContext, views: subviews.subviews, layoutProviders: layoutProviders)+        } catch {+            fatalError(error.localizedDescription)+        }+    }++    public func cellWillBeShown(_ cell: UICollectionViewCell) {+        for observer in self.lifecycleObservers {+            observer.willShow()+        }+    }++    // TODO: Unify viewModels instantiation. We need to create everything at once #743+    private func makeViewModels() -> [Key: Any] {

I've already created an issue almost exactly for that: #743 What do you think if I fix it there?

wiruzx

comment created time in 2 days

PullRequestReviewEvent

push eventbadoo/marathon

Sergey Chelombitko

commit sha 512020d9284f7fad32855ddff570d4980f3f96c6

Fix pulling large number of screenshots

view details

push time in 2 days

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++import Chatto+import ChattoAdditions++public final class ChatItemPresenter<ChatItem>: ChatItemPresenterProtocol {++    private typealias Key = AnyBindingKey+    private typealias ViewModels = [Key: Any]+    private typealias LayoutProviders = [Key: Any]+    private typealias Cell = ChatItemCell++    private let chatItem: ChatItem+    private let binder: Binder+    private let assembler: ViewAssembler+    private let layoutAssembler: LayoutAssembler+    private let factory: FactoryAggregate<ChatItem>+    private let reuseIdentifier: String++    private var viewModels: ViewModels?+    private var rootViewSizeProvider: AnySizeProvider?+    private var layoutProviders: LayoutProviders?+    private var lifecycleObservers: [ChatItemLifecycleViewModel] = []++    public init(chatItem: ChatItem,+                binder: Binder,+                assembler: ViewAssembler,+                layoutAssembler: LayoutAssembler,+                factory: FactoryAggregate<ChatItem>,+                reuseIdentifier: String) {+        self.chatItem = chatItem+        self.binder = binder+        self.assembler = assembler+        self.layoutAssembler = layoutAssembler+        self.factory = factory+        self.reuseIdentifier = reuseIdentifier+    }++    public static func registerCells(_ collectionView: UICollectionView) {+        fatalError("This method should not be called")+    }++    public static func registerCells(for collectionView: UICollectionView, with reuseID: String) {+        collectionView.register(Cell.self, forCellWithReuseIdentifier: reuseID)

This function has to be a static function, that's why we're passing reuseID from the outside. I'm going to fix this in #761

wiruzx

comment created time in 2 days

PullRequestReviewEvent

fork amixuse/MVIKotlin

Extendable MVI framework for Kotlin Multiplatform with powerful debugging tools (logging and time travel), inspired by Badoo MVICore library

https://arkivanov.github.io/MVIKotlin

fork in 2 days

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++public struct LayoutAssembler {++    // MARK: - Type declarations++    public typealias Key = AnyBindingKey+    private typealias LayoutCache = [AnyBindingKey: AnyCachedLayoutProvider]++    public enum Error: Swift.Error {+        case notFound(Key)+        case internalInconsistency+        case layoutWasNotCalculated(Key)+    }++    private enum Composition {+        case single(AnyBindingKey)+        case multiple([AnyBindingKey])+    }++    // MARK: - Private properties++    private let rootKey: AnyBindingKey+    private var compositions: [AnyBindingKey: Composition] = [:]+    private var makeSizeProviders: [AnyBindingKey: (Any) throws -> AnySizeProvider] = [:]+    private var makeCachingProviders: [AnyBindingKey: (Any) throws -> AnyCachedLayoutProvider] = [:]+    private var layoutApplicators: [AnyBindingKey: (Any, Any) throws -> Void] = [:]++    // MARK: - Instantiation++    public init(rootKey: AnyBindingKey) {+        self.rootKey = rootKey+    }++    public init<Root: BindingKeyProtocol>(rootKey: Root) {+        self.init(rootKey: .init(rootKey))+    }++    // MARK: - Public API++    public mutating func register<Parent: BindingKeyProtocol>(child: AnyBindingKey, for parent: Parent) {+        self.compositions[.init(parent)] = .single(child)+    }++    public mutating func register<Parent: BindingKeyProtocol>(children: [AnyBindingKey], for parent: Parent) {+        self.compositions[.init(parent)] = .multiple(children)+    }++    // TODO: Remove #746+    public mutating func populateSizeProviders<Key: BindingKeyProtocol>(for key: Key)+        where Key.LayoutProvider.Layout: SizeContainer, Key.View: ManualLayoutViewProtocol, Key.View.Layout == Key.LayoutProvider.Layout {+        let erasedKey = AnyBindingKey(key)+        self.makeSizeProviders[erasedKey] = { anyLayoutProvider in+            guard let layoutProvider = anyLayoutProvider as? CachingLayoutProvder<Key.LayoutProvider.Layout> else {+                throw Error.internalInconsistency+            }+            return AnySizeProvider(layoutProvider)+        }+        self.makeCachingProviders[erasedKey] = { anyLayoutProvider in+            guard let layoutProvider = anyLayoutProvider as? Key.LayoutProvider else {+                throw Error.internalInconsistency+            }+            return CachingLayoutProvder(layoutProvider)+        }+        self.layoutApplicators[erasedKey] = { anyView, anyLayout in+            guard let view = anyView as? Key.View, let layout = anyLayout as? Key.LayoutProvider.Layout else {+                throw Error.internalInconsistency+            }+            view.apply(layout: layout)+        }+    }++    public func assembleRootSizeProvider(layoutProviders: [Key: Any]) throws -> AnySizeProvider {+        let key = self.rootKey+        var layoutCache: LayoutCache = [:]+        return try self.assemble(for: key, with: layoutProviders, layoutCache: &layoutCache)+    }++    // TODO: #747+    public func applyLayout(with context: LayoutContext, views: [Key: Any], layoutProviders: [Key: Any]) throws {+        var layoutCache: LayoutCache = [:]+        // TODO: Check keys+        let rootLayoutProvider = try self.assemble(for: self.rootKey, with: layoutProviders, layoutCache: &layoutCache)++        // perform layout to cache results+        _ = try rootLayoutProvider.layout(for: context)++        for (key, view) in views {+            guard let applicator = self.layoutApplicators[key] else {+                throw Error.notFound(key)+            }++            guard let cachedLayout = layoutCache[key]?.lastPerformedLayoutResult else {+                throw Error.layoutWasNotCalculated(key)+            }++            try applicator(view, cachedLayout)+        }+    }++    // MARK: - Private++    private func assemble(for key: Key, with providers: [Key: Any], layoutCache: inout LayoutCache) throws -> AnySizeProvider {+        guard let layoutProvider = providers[key] else {+            throw Error.notFound(key)+        }++        guard let makeSizeProvider = makeSizeProviders[key] else {+            throw Error.notFound(key)+        }++        guard let makeCachingProvider = makeCachingProviders[key] else {+            throw Error.notFound(key)+        }++        let resultLayoutProvider: Any+        switch self.compositions[key] {++        case .single(let childKey)?:+            let child = try self.assemble(for: childKey, with: providers, layoutCache: &layoutCache)+            guard var container = layoutProvider as? SingleContainerLayoutProviderProtocol else {+                throw Error.internalInconsistency+            }+            container.childLayoutProvider = child+            resultLayoutProvider = container++        case .multiple(let childrenKeys)?:+            let children: [AnySizeProvider] = try childrenKeys+                .map { try self.assemble(for: $0, with: providers, layoutCache: &layoutCache) }+            guard var container = layoutProvider as? MultipleContainerLayoutProviderProtocol else {+                throw Error.internalInconsistency+            }+            container.childrenLayoutProviders = children+            resultLayoutProvider = container++        case nil:+            resultLayoutProvider = layoutProvider++        }++        let cachingContainer = try makeCachingProvider(resultLayoutProvider)+        layoutCache[key] = cachingContainer+        let sizeProvider = try makeSizeProvider(cachingContainer)+        return sizeProvider+    }+}++public protocol AnyCachedLayoutProvider {+    var lastPerformedLayoutResult: Any? { get }+}++private final class CachingLayoutProvder<Layout: LayoutModel>: LayoutProviderProtocol {++    private let _layout: (LayoutContext) throws -> Layout++    private(set) var lastLayout: Layout?++    init<Base: LayoutProviderProtocol>(_ base: Base) where Base.Layout == Layout {+        self._layout = { try base.layout(for: $0) }+    }++    func layout(for context: LayoutContext) throws -> Layout {+        let layout = try self._layout(context)+        self.lastLayout = layout+        return layout+    }+}++extension CachingLayoutProvder: AnyCachedLayoutProvider {

Typo? CachingLayoutProvider

wiruzx

comment created time in 2 days

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++import Chatto+import ChattoAdditions++public final class ChatItemPresenter<ChatItem>: ChatItemPresenterProtocol {++    private typealias Key = AnyBindingKey+    private typealias ViewModels = [Key: Any]+    private typealias LayoutProviders = [Key: Any]+    private typealias Cell = ChatItemCell++    private let chatItem: ChatItem+    private let binder: Binder+    private let assembler: ViewAssembler+    private let layoutAssembler: LayoutAssembler+    private let factory: FactoryAggregate<ChatItem>+    private let reuseIdentifier: String++    private var viewModels: ViewModels?+    private var rootViewSizeProvider: AnySizeProvider?+    private var layoutProviders: LayoutProviders?+    private var lifecycleObservers: [ChatItemLifecycleViewModel] = []++    public init(chatItem: ChatItem,+                binder: Binder,+                assembler: ViewAssembler,+                layoutAssembler: LayoutAssembler,+                factory: FactoryAggregate<ChatItem>,+                reuseIdentifier: String) {+        self.chatItem = chatItem+        self.binder = binder+        self.assembler = assembler+        self.layoutAssembler = layoutAssembler+        self.factory = factory+        self.reuseIdentifier = reuseIdentifier+    }++    public static func registerCells(_ collectionView: UICollectionView) {+        fatalError("This method should not be called")+    }++    public static func registerCells(for collectionView: UICollectionView, with reuseID: String) {+        collectionView.register(Cell.self, forCellWithReuseIdentifier: reuseID)+    }++    public let isItemUpdateSupported: Bool = true++    // TODO: Implement support for updating #742+    public func update(with chatItem: ChatItemProtocol) {}++    public func heightForCell(maximumWidth width: CGFloat, decorationAttributes: ChatItemDecorationAttributesProtocol?) -> CGFloat {+        let context = LayoutContext(maxWidth: width)+        let provider = self.makeRootViewSizeProvider()+        do {+            return try provider.height(for: context)+        } catch {+            fatalError(error.localizedDescription)+        }+    }++    public func dequeueCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell {+        collectionView.dequeueReusableCell(withReuseIdentifier: self.reuseIdentifier, for: indexPath)+    }++    public func configureCell(_ cell: UICollectionViewCell, decorationAttributes: ChatItemDecorationAttributesProtocol?) {+        guard let cell = cell as? Cell else { fatalError() }+        do {+            let subviews = self.setupSubviews(of: cell)+            let viewModels = self.makeViewModels()+            self.lifecycleObservers = viewModels.values.compactMap { $0 as? ChatItemLifecycleViewModel }+            try self.binder.bind(subviews: subviews, viewModels: viewModels)+            let layoutProviders = self.makeLayoutProviders()+            let rootContext = LayoutContext(maxWidth: cell.bounds.width)+            try self.layoutAssembler.applyLayout(with: rootContext, views: subviews.subviews, layoutProviders: layoutProviders)+        } catch {+            fatalError(error.localizedDescription)+        }+    }++    public func cellWillBeShown(_ cell: UICollectionViewCell) {+        for observer in self.lifecycleObservers {+            observer.willShow()+        }+    }++    // TODO: Unify viewModels instantiation. We need to create everything at once #743+    private func makeViewModels() -> [Key: Any] {+        if let viewModels = self.viewModels {+            return viewModels+        }++        let viewModels = self.factory.makeViewModels(for: self.chatItem)+        self.viewModels = viewModels+        return viewModels+    }++    private func makeLayoutProviders() -> LayoutProviders {+        if let providers = self.layoutProviders {+            return providers+        }+        let viewModels = self.makeViewModels()+        let layoutProviders = self.factory.makeLayoutProviders(for: viewModels)+        self.layoutProviders = layoutProviders+        return layoutProviders+    }++    private func makeRootViewSizeProvider() -> AnySizeProvider {

Same as above

wiruzx

comment created time in 3 days

Pull request review commentbadoo/Chatto

Composable messages

 class DemoChatViewController: UIViewController {         ]     } -    class func createTextMessageViewModelBuilder() -> DemoTextMessageViewModelBuilder {-        return DemoTextMessageViewModelBuilder()+    private static func makeNewFallbackItemPresenterFactory() -> ChatItemPresenterFactoryProtocol {++        struct DummyItemPresenterFactory: ChatItemPresenterFactoryProtocol {++            typealias PresenterBuilder = ChatItemPresenterBuilderProtocol & ChatItemPresenterBuilderCollectionViewConfigurable++            let presenterBuilder: PresenterBuilder++            func createChatItemPresenter(_ chatItem: ChatItemProtocol) -> ChatItemPresenterProtocol {+                guard self.presenterBuilder.canHandleChatItem(chatItem) else { fatalError() }+                return self.presenterBuilder.createPresenterWithChatItem(chatItem)+            }++            func configure(withCollectionView collectionView: UICollectionView) {+                self.presenterBuilder.configure(with: collectionView)+            }+        }++        var factory = FactoryAggregate<ChatItemProtocol>()++        let dummy = factory.register(+            viewFactory: DummyContentViewFactory(),+            viewModelFactory: DummyViewModelFactory(),+            layoutProviderFactory: DummyLayoutProviderFactory()+        )++        var binder = Binder()+        binder.registerBinding(for: dummy)++        let assembler = ViewAssembler(root: dummy)+        var layoutAssembler = LayoutAssembler(rootKey: dummy)++        // TODO: Remove #746+        layoutAssembler.populateSizeProviders(for: dummy)++        let presenterBuilder = ChatItemPresenterBuilder(+            binder: binder,+            assembler: assembler,+            layoutAssembler: layoutAssembler,+            factory: factory+        )+        return DummyItemPresenterFactory(presenterBuilder: presenterBuilder)+    }++    private static func makeNewPresenterBuilders() -> [ChatItemType: [ChatItemPresenterBuilderProtocol]] {+        return [+            DemoTextMessageModel.chatItemType: [self.makeNewTextMessagePresenterBuilder()],+            ChatItemType.compoundItemType: [self.makeNewCompoundExamplePresenterBuilder()],+            DemoPhotoMessageModel.chatItemType: [self.makeNewImagePresenterBuilder()]+        ]+    }++    private static func makeNewImagePresenterBuilder() -> ChatItemPresenterBuilderProtocol {++        var factory = FactoryAggregate<DemoPhotoMessageModel>()++        let image = factory.register(+            viewFactory: AsyncImageViewFactory(),+            viewModelFactory: AsyncImageViewModelFactory(),+            layoutProviderFactory: AsyncImageLayoutProviderFactory()+        )++        let bubble = factory.register(+            viewFactory: MessageBubbleViewFactory(),+            viewModelFactory: MessageBubbleViewModelFactory(),+            layoutProviderFactory: MessageBubbleLayoutProviderFactory(configuration: .init(percentageToOccupy: 0.4))+        )++        var binder = Binder()++        binder.registerBinding(for: bubble)++        binder.registerBlockBinding(for: image) { view, viewModel in+            view.viewModel = viewModel+        }++        var assembler = ViewAssembler(root: bubble)+        assembler.register(child: image, parent: bubble)++        var layoutAssembler = LayoutAssembler(rootKey: bubble)+        layoutAssembler.register(child: image, for: bubble)++        // TODO: Remove #746+        layoutAssembler.populateSizeProviders(for: bubble)+        layoutAssembler.populateSizeProviders(for: image)++        return ChatItemPresenterBuilder(+            binder: binder,+            assembler: assembler,+            layoutAssembler: layoutAssembler,+            factory: factory+        )+    }++    private static func makeNewCompoundExamplePresenterBuilder() -> ChatItemPresenterBuilderProtocol {+        var factory = FactoryAggregate<DemoCompoundMessageModel>()++        let bubble = factory.register(+            viewFactory: MessageBubbleViewFactory(),+            viewModelFactory: MessageBubbleViewModelFactory(),+            layoutProviderFactory: MessageBubbleLayoutProviderFactory(configuration: .init(percentageToOccupy: 0.8))+        )++        let compound = factory.register(+            viewFactory: CompoundViewFactory(),+            viewModelFactory: CompoundViewModelFactory(),+            layoutProviderFactory: CompoundLayoutProviderFactory()+        )++        let first = factory.register(+            viewFactory: DummyContentViewFactory(),+            viewModelFactory: StaticDummyViewModelFactory(text: "first"),+            layoutProviderFactory: DummyLayoutProviderFactory()+        )++        let second = factory.register(+            viewFactory: DummyContentViewFactory(),+            viewModelFactory: StaticDummyViewModelFactory(text: "second"),+            layoutProviderFactory: DummyLayoutProviderFactory()+        )++        var binder = Binder()++        binder.registerBinding(for: bubble)+        binder.registerNoopBinding(for: compound)+        binder.registerBinding(for: first)+        binder.registerBinding(for: second)++        var assembler = ViewAssembler(root: bubble)

Will the view assembler make the same registrations as the layout assembler. Can we avoid this duplication somehow?

wiruzx

comment created time in 2 days

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++import Chatto+import ChattoAdditions++public final class ChatItemPresenterBuilder<ChatItem>: ChatItemPresenterBuilderProtocol, ChatItemPresenterBuilderCollectionViewConfigurable {++    private let binder: Binder+    private let assembler: ViewAssembler+    private let layoutAssembler: LayoutAssembler+    private let factory: FactoryAggregate<ChatItem>+    private let reuseIdentifier: String++    public init(binder: Binder,+                assembler: ViewAssembler,+                layoutAssembler: LayoutAssembler,+                factory: FactoryAggregate<ChatItem>) {+        self.binder = binder+        self.assembler = assembler+        self.factory = factory+        self.layoutAssembler = layoutAssembler+        self.reuseIdentifier = assembler.reuseIdentifier+    }++    // TODO: Implement me #744+    public func canHandleChatItem(_ chatItem: ChatItemProtocol) -> Bool {+        guard let item = chatItem as? ChatItem else { return false }+        //return self.binder.canHandle(item: item)+        return true+    }++    public func createPresenterWithChatItem(_ chatItem: ChatItemProtocol) -> ChatItemPresenterProtocol {+        guard let item = chatItem as? ChatItem else { fatalError() }+        return ChatItemPresenter(+            chatItem: item, +            binder: self.binder,+            assembler: self.assembler,+            layoutAssembler: self.layoutAssembler,+            factory: self.factory,+            reuseIdentifier: self.reuseIdentifier+        )+    }++    public let presenterType: ChatItemPresenterProtocol.Type = ChatItemPresenter<ChatItemType>.self

Niiiice :)

wiruzx

comment created time in 3 days

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++import Chatto+import ChattoAdditions++public final class ChatItemPresenterBuilder<ChatItem>: ChatItemPresenterBuilderProtocol, ChatItemPresenterBuilderCollectionViewConfigurable {++    private let binder: Binder+    private let assembler: ViewAssembler+    private let layoutAssembler: LayoutAssembler+    private let factory: FactoryAggregate<ChatItem>+    private let reuseIdentifier: String++    public init(binder: Binder,+                assembler: ViewAssembler,+                layoutAssembler: LayoutAssembler,+                factory: FactoryAggregate<ChatItem>) {+        self.binder = binder+        self.assembler = assembler+        self.factory = factory+        self.layoutAssembler = layoutAssembler+        self.reuseIdentifier = assembler.reuseIdentifier+    }++    // TODO: Implement me #744+    public func canHandleChatItem(_ chatItem: ChatItemProtocol) -> Bool {+        guard let item = chatItem as? ChatItem else { return false }+        //return self.binder.canHandle(item: item)+        return true+    }++    public func createPresenterWithChatItem(_ chatItem: ChatItemProtocol) -> ChatItemPresenterProtocol {

What do you think about aligning the APIs to createPresenter(withChatItem chatItem: ChatItemProtocol)

wiruzx

comment created time in 3 days

Pull request review commentbadoo/Chatto

Composable messages

+//+// The MIT License (MIT)+//+// Copyright (c) 2015-present Badoo Trading Limited.+//+// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+//+// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+//+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.++import Chatto+import ChattoAdditions++public final class ChatItemPresenter<ChatItem>: ChatItemPresenterProtocol {++    private typealias Key = AnyBindingKey+    private typealias ViewModels = [Key: Any]+    private typealias LayoutProviders = [Key: Any]+    private typealias Cell = ChatItemCell++    private let chatItem: ChatItem+    private let binder: Binder+    private let assembler: ViewAssembler+    private let layoutAssembler: LayoutAssembler+    private let factory: FactoryAggregate<ChatItem>+    private let reuseIdentifier: String++    private var viewModels: ViewModels?+    private var rootViewSizeProvider: AnySizeProvider?+    private var layoutProviders: LayoutProviders?+    private var lifecycleObservers: [ChatItemLifecycleViewModel] = []++    public init(chatItem: ChatItem,+                binder: Binder,+                assembler: ViewAssembler,+                layoutAssembler: LayoutAssembler,+                factory: FactoryAggregate<ChatItem>,+                reuseIdentifier: String) {+        self.chatItem = chatItem+        self.binder = binder+        self.assembler = assembler+        self.layoutAssembler = layoutAssembler+        self.factory = factory+        self.reuseIdentifier = reuseIdentifier+    }++    public static func registerCells(_ collectionView: UICollectionView) {+        fatalError("This method should not be called")+    }++    public static func registerCells(for collectionView: UICollectionView, with reuseID: String) {+        collectionView.register(Cell.self, forCellWithReuseIdentifier: reuseID)

If this is the case, we should probably use the method above, no?

wiruzx

comment created time in 3 days

more