Giter VIP home page Giter VIP logo

pilot's Introduction

Pilot: Cross-platform MVVM in Swift

If you squint, any modern client application can viewed as a "scrollable list of stuff from the internet". Whether it's a scrollable list of food, photos, videos, merchandise, cats, or cat merchandise -- all applications share common scaffolding.

Pilot provides a suite of robust components to take care of this common scaffolding so you can focus on what matters: your data (Model), business logic (ViewModel), and presentation (View).

These components are not overly-prescriptive to any particular application architecture, so you can adopt them without having to rewrite or commit to Pilot forever.

Component Libraries

Pilot is modularized into components providing building blocks for fast and safe application development (see flight plan for upcoming components).

  • Pilot: Provides a core MVVM stack, various model collections, diff engine, action handling, along with some minimal async, observable, and logging components. This is a Foundation-only framework (i.e. No UIKit or AppKit)
  • PilotUI: UI layer components built atop Pilot for both Mac and iOS. Contains collection view bindings and other macOS/iOS extensions for Pilot development.

Usage

See the Getting Started guide for a basic walkthrough of core concepts.

There is a Sample Project which demonstrates macOS app and iOS app built from the same Pilot MVVM stack.

Otherwise, please see type documentation and let us know if anything is unclear.

Requirements

  • Xcode 9.2
  • Swift 4.0
  • iOS 9.0+ / macOS 10.11+

Installation

Travis CI

Xcode

  • Drag Pilot.xcodeproj into Project Navigator
  • Go to Project > Targets > General > Embed Frameworks, click +, and select Pilot [Platform] and PilotUI [platform] targets.
  • In Project > Targets > Build Phases > Target Dependencies, ensure Pilot [Platform] and PilotUI [Platform] are there.

GYP

The GYP config is an alternative way of using Pilot, it's ONLY for using it in other GYP projects. If you don't know what GYP is, you can safely ignore this section here.

  • Generate iOS Xcode project via gyp Pilot.gyp --depth=. --suffix=.ios.dxbuild -DOS=ios
  • Generate MacOS Xcode project via gyp Pilot.gyp --depth=. --suffix=.osx.dxbuild -DOS=mac
  • Use generated Pilot.ios.dxbuild.xcodeproj to build Pilot for iOS, or Pilot.ios.dxbuild.xcodeproj for macOS.

License

Apache 2.0

pilot's People

Contributors

aeidelson avatar alanjrogers avatar aron avatar bogo avatar danielrhammond avatar jaquish avatar jettsui avatar laposheureux avatar matthewvalentine avatar michaelpetrov avatar wkiefer avatar yanks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pilot's Issues

Create `SectionedModelCollection`

This was started in #48

Still some minor work to do here around design and determination of whether there will be model objects representing the section itself.

Bugs in async coalescing functions

  1. Async.debounce doesn't actually wait (see aa6c8ed)
  2. Async.throttle will swallow an invocation that happens during the reset window for the previous, this is unexpected. Either fix or remove.

CollectionViewModelDataSource - state changes with no diff engine update are not comitted

If state changes (e.g. from .loading(someModel) to .loaded(someModel) but there are no diff engine deltas, the hasUpdates check below prevents the state from being committed.

In practice, this is rare - but needs to be fixed. We also need to flesh out the tests in this area to be confident about future changes.

    fileprivate func applyCurrentDataToCollectionView() {
        precondition(collectionViewState == .synced)

        let (updates, commitCollectionChanges) = currentCollection.beginUpdate(underlyingCollection)
        guard updates.hasUpdates else {
            // still synced
            // no need to update lastKnownCollectionViewContents
            return
        }

https://github.com/dropbox/pilot/blob/master/UI/Source/CollectionViews/CollectionViewModelDataSource.swift#L460

CollectionViewController: more ergonomic initializer w/ default model/layout/binders

From @danielrhammond 's comment in #109 :

random idea, but since we do a lot of things like this in our app it might be nice to provide an optional protocol CVCs can conform to with some static funcs which if conformed to provide a convenience init(context:) initializer

static func defaultModel() -> ModelCollection
static func defaultLayout() -> NSCollectionViewLayout
static func viewBinder() -> ViewBindingProvider

Crash on macOS 10.11

Preliminary investigation tracking down app crash suggests theres a seg fault when going from .loading(nil) to .loaded([[...]]) which is alleviated by always starting with a single empty section (.loading([[]]))

Needs help tracking down whether this is a radar'able NSCV bug and/or something that needs to be addressed in pilot.

Support for 3D Touch peek/pop

Ideally, view models will handle the core ability to support peek/pop via a new ViewModelUserEvent - but most of the handling will need to happen at the UIKit layer.

  • CollectionViewController handles registerForPreviewing/unregisterForPreviewing
  • Since the previewing APIs need a UIViewController returned synchronously, we'll need to figure out the best way to let the higher app layers actually return it (potentially closures on the CVC to generate/commit a preview VC from a view model aeek action.

Change `selected` on `View` to `selectionStyle`

selected has issues when you subclass an Objective-C NSView or UIView with an isSelected getter (example is NSTableRowView) and also conform it to View.

The synthesized swift name (isSelected) cannot coexist with the View conformance selected.

This seemed to work ok in Swift <3.2, but no longer works in Swift 3.2+.

We should move this to an emum of selectionStyle to match highlightStyle. This will also give us a bit more flexibility in types of selection state.

We should also give NSView and UIView classes that have a selected property easy free implementations of selectionState.

This is a breaking change.

Mac Example

Flesh out the views for the mac example app

Make model conform to Hashable

Building on the work in #157 we can remove ModelVersion and ModelVersionMixer entirely from Pilot by making model conform to Hashable as part of its requirements.

Pros:

  • Very common that we want Hashable (or at bare minimum Equatable) for our models,
  • Swift 4.2 autogen'ing conformance for simple structs makes this not a pain for most models
  • Makes things feel more swifty (having a separate hasher is definitely a drag in the post 4.2 world)

Cons:

  • Forces Equatable for models (not sure this is actually bad but could be perceived to be higher bar than ModelVersion implementation)
  • Can't separate out hashing for pilots benefit from generic hashing function (this is mostly a good thing, but we exploited this once or twice in $RIP_SECRET_PROJECT to drop noisy user updates for example)
  • Breaking change

I'm solidly pro but wanted to check for feedback before proceeding (cc @wkiefer)

Let a `CollectionSupportingView` invalidate its own layout

It would be great to allow a CollectionSupportingView to be able to invalidate it's own layout in response to some view state that changes it's bounds.

Eg. a input text field that grows in height as the user types.

See #102 for a naive implementation.

That implementation needs 2 things to be generally useful in pilot:

  1. It should only invalidate the layout of the single view (not the whole CV)
  2. It should have a more robust way of getting a reference to the collectionView.

ModelCollection loading state regression

The change to when the CurrentCollection state was updated in #19 causes issues with changes to state in the underlying ModelCollection. Especially when going from notLoaded to loading(_) for example.

The CurrentCollection state is now updated in a commit closure however it's not guaranteed this closure will be called, which means sometimes state changes are swallowed. For example in:

let (updates, commitCollectionChanges) = currentCollection.beginUpdate(underlyingCollection)
guard updates.hasUpdates else {
  // still synced
  // no need to update lastKnownCollectionViewContents
  return
}

let (updates, commitCollectionChanges) = currentCollection.beginUpdate(underlyingCollection)
guard updates.hasUpdates else {
// still synced
// no need to update lastKnownCollectionViewContents
return
}

In this case a ModelCollection going from notLoaded to loading will have no updates and so the underlying state will never be updated and the CollectionViewController won't display a loading spinner.

`ModelCollection` Rename & Functionality Pass

As part of the 0.9 release, we'll be consolidating the breaking changes from #52 with breaking ModelCollection renames.

Tasks

  • Complete Table Below
Need Legacy Name Notes New Name โœ…
_ SimpleModelCollection TBD ๐Ÿ…พ๏ธ
_ SwitchableModelCollection TBD ๐Ÿ…พ๏ธ
_ SortedModelCollection SortedModelCollection ๐Ÿ…พ๏ธ
Static Data StaticModelCollection TBD ๐Ÿ…พ๏ธ
Ranking ScoredModelCollection TBD ๐Ÿ…พ๏ธ
_ MultiplexModelColletion TBD ๐Ÿ…พ๏ธ
_ MappedModelCollection TBD ๐Ÿ…พ๏ธ
Filter FilteredModelCollection TBD ๐Ÿ…พ๏ธ
Limit ^ FilteredModelCollection FilteredModelCollection ๐Ÿ…พ๏ธ
_ EmptyModelCollection TBD ๐Ÿ…พ๏ธ
Block Based Population AsyncModelCollection TBD ๐Ÿ…พ๏ธ
Section Support n/a SectionedModelCollection ๐Ÿ…พ๏ธ
Paging n/a PagingModelCollectionType (protocol) PagingModelCollection (convenience impl) ๐Ÿ…พ๏ธ
Sorting n/a TBD ๐Ÿ…พ๏ธ
Windowing n/a TBD ๐Ÿ…พ๏ธ

Fix drag drop accessibility

From internal comment/bug:

iOS assigns accessibilityDragSourceDescriptors and accessibilityDropPointDescriptors to the cell, but doesn't look up the hierarchy from elements to their ancestors to see if drag and drop applies, If this cell were directly isAccessibilityElement = YES then this would not be a problem, but since we're hosting something else which (may be) an accessibility element, we need to find it and copy over the location descriptors so drag&drop applies.

So CollectionViewHostCell needs to set these properties on its host view (and maybe on the child View itself too?)

Support double click in ViewModelUserEvents

Currently we only support click and right click events, double click would be a useful addition to the macOS platform as it currently has to be manually implemented by each view outside of the regular user event handling.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.