Giter Club home page Giter Club logo

splitties's Introduction

Splitties

Splitties is a collection of small Kotlin multiplatform libraries (with Android as first target).

These libraries are intended to reduce the amount of code you have to write, freeing code reading and writing time, so you can focus more on what you want to build for your users (even if you're the only one), or have more time to have fun.

This project is named "Splitties" because it is split in small modules, distributed as independent libraries, so you can add only the ones you need to your project/module, helping reduce the size of the final binary that users devices will need to download and keep in the limited storage (BTW, everything is limited).

Some Android targeting modules have a content similar to what Anko offers. See a short comparison of Splitties with Anko here.

Each module has been designed to have a small footprint and be as efficient as possible.

A few examples

Splitties is all about simplifying your code. Here are a few examples:

Kotlin:

startActivity(Intent(this, DemoActivity::class.java))

Kotlin with Splitties Activities:

start<DemoActivity>()

Kotlin:

Snackbar.make(root, R.string.refresh_successful, Snackbar.LENGTH_SHORT)
    .show()

Kotlin with Splitties Snackbar:

root.snack(R.string.refresh_successful)

Racing coroutines: (raceOf(…) comes from the Coroutines module)

suspend fun awaitUserChoice(ui: SomeUi, choices: List<Stuff>): Stuff? = raceOf({
    ui.awaitSomeUserAction(choices)
}, {
    ui.awaitDismissal()
    null
}, {
    ui.showSomethingInRealtimeUntilCancelled() // Returns Nothing, will run, but never "win".
})

Kotlin:

Snackbar.make(root, getString(R.string.deleted_x_items, deletedCount), Snackbar.LENGTH_LONG)
    .setAction(android.R.string.cancel) {
        deleteOperation.requestRollback()
    }
    .setActionTextColor(ContextCompat.getColor(this, R.color.fancy_color))
    .show()

Kotlin with Splitties Snackbar:

root.longSnack(str(R.string.deleted_x_items, deletedCount)) {
    action(android.R.string.cancel, textColor = color(R.color.fancy_color)) {
        deleteOperation.requestRollback()
    }
}

Overview

System interaction (Android only):

  • App Context: Always have your application Context at hand with appCtx.
  • System Services: No more context.getSystemService(NAME_OF_SERVICE) as NameOfManager.

User input and user interface related splits:

Small messages (Android only)

Dialogs (Android only)

System UI (Android only)

Extensions for Views (Android only)

Creating View based UIs with the power of Kotlin (Android only)

Various UI utilities (Android only)

Material Design helpers (Android only)

Inter and cross app communication: Activities, Fragments, Intents, and Bundles

  • Activities: Start activities with minimal boilerplate.
  • Intents: Transform companion objects into powerful typesafe intent specs, and create PendingIntents the clean and easy way.
  • Fragments: Start activities from fragments and do transactions with minimal boilerplate.
  • Fragment Args: Fragment arguments without ceremony thanks to delegated properties.
  • Bundle: BundleSpec to use Bundle with property syntax for Intent extras and more.

Concurrency (Multiplatform)

Data persistence (Multiplatform)

  • Preferences: Property syntax for Android's SharedPreferences/DataStore and macOS/iOS/watchOS NSUserDefaults.
  • Arch Room: Room helpers to instantiate your DB and perform transactions in Kotlin.

Utilities (Multiplatform)

  • Bit Flags: hasFlag, withFlag and minusFlag extensions on Long, Int, Short, Byte, and their unsigned counterparts.
  • Collections: forEach for Lists without Iterator allocation.

Debugging (Android only)

Legacy (Android only)

  • Exceptions: unexpectedValue(…), unsupportedAction(…) and similar functions that return Nothing.
  • Arch Lifecycle: Extensions to get ViewModels, use LiveData and observe Lifecycles.

Download

Gradle instructions

Make sure you have mavenCentral() in the repositories defined in your project's (root) build.gradle file (default for new Android Studio projects).

To make it easier to take advantage of the contents of Splitties for your Android projects, there are grouping artifacts that include most splits.

Android base

Adding with refreshVersions: Splitties.pack.androidBase or Splitties.pack.androidBaseWithViewsDsl.

These 2 packs don't include AppCompat and are suitable for WearOS apps.

Includes the following modules:

Gradle dependency:

implementation("com.louiscad.splitties:splitties-fun-pack-android-base:3.0.0")

There's also a version with Views DSL. It additionally includes the following modules:

Gradle dependency:

implementation("com.louiscad.splitties:splitties-fun-pack-android-base-with-views-dsl:3.0.0")

Android AppCompat

Adding with refreshVersions: Splitties.pack.appCompat or Splitties.pack.appCompatWithViewsDsl.

These 2 packs include the Android base pack, and the following modules:

Gradle dependency:

implementation("com.louiscad.splitties:splitties-fun-pack-android-appcompat:3.0.0")

There's also a version with Views DSL. It additionally includes the Views DSL version of the Android base pack and the following module:

Gradle dependency:

implementation("com.louiscad.splitties:splitties-fun-pack-android-appcompat-with-views-dsl:3.0.0")

Android Material Components

Adding with refreshVersions: Splitties.pack.androidMdc or Splitties.pack.androidMdcWithViewsDsl.

These 2 packs include the Android AppCompat pack, and the following modules:

Gradle dependency:

implementation("com.louiscad.splitties:splitties-fun-pack-android-material-components:3.0.0")

There's also a version with Views DSL. It additionally includes the Views DSL version of the Android AppCompat pack and the following modules:

Gradle dependency:

implementation("com.louiscad.splitties:splitties-fun-pack-android-material-components-with-views-dsl:3.0.0")

All the artifacts (47)

Since you might use multiple artifacts, to not repeat yourself, we recommend you to put the version in a central place, so it's little effort to upgrade to newer versions.

The best way to do this is to use refreshVersions, it has built-in dependency notations for Splitties, and also many other popular and qualitative libraries, like kotlinx, AndroidX, libraries from Square/CashApp and libraries from Google.

Most importantly, with it, running the refreshVersions task will show you the available updates in a matter of seconds, for all of your dependencies, right into the versions.properties, in a way that makes upgrading effortless, even with just the keyboard.

FYI, the current latest release of Splitties is the version 3.0.0

Here are the maven coordinates of all the artifacts of this library, for reference. (Click to expand)
com.louiscad.splitties:splitties-activities
com.louiscad.splitties:splitties-alertdialog
com.louiscad.splitties:splitties-alertdialog-appcompat
com.louiscad.splitties:splitties-alertdialog-appcompat-coroutines
com.louiscad.splitties:splitties-appctx
com.louiscad.splitties:splitties-arch-lifecycle
com.louiscad.splitties:splitties-arch-room
com.louiscad.splitties:splitties-bitflags
com.louiscad.splitties:splitties-bundle
com.louiscad.splitties:splitties-checkedlazy
com.louiscad.splitties:splitties-collections
com.louiscad.splitties:splitties-coroutines
com.louiscad.splitties:splitties-dimensions
com.louiscad.splitties:splitties-exceptions
com.louiscad.splitties:splitties-fragments
com.louiscad.splitties:splitties-fragmentargs
com.louiscad.splitties:splitties-intents
com.louiscad.splitties:splitties-lifecycle-coroutines
com.louiscad.splitties:splitties-mainhandler
com.louiscad.splitties:splitties-mainthread
com.louiscad.splitties:splitties-material-colors
com.louiscad.splitties:splitties-material-lists
com.louiscad.splitties:splitties-permissions
com.louiscad.splitties:splitties-preferences
com.louiscad.splitties:splitties-resources
com.louiscad.splitties:splitties-snackbar
com.louiscad.splitties:splitties-stetho-init
com.louiscad.splitties:splitties-systemservices
com.louiscad.splitties:splitties-toast
com.louiscad.splitties:splitties-typesaferecyclerview
com.louiscad.splitties:splitties-views
com.louiscad.splitties:splitties-views-appcompat
com.louiscad.splitties:splitties-views-cardview
com.louiscad.splitties:splitties-views-coroutines
com.louiscad.splitties:splitties-views-coroutines-material
com.louiscad.splitties:splitties-views-dsl
com.louiscad.splitties:splitties-views-dsl-appcompat
com.louiscad.splitties:splitties-views-dsl-constraintlayout
com.louiscad.splitties:splitties-views-dsl-coordinatorlayout
com.louiscad.splitties:splitties-views-dsl-ide-preview
com.louiscad.splitties:splitties-views-dsl-material
com.louiscad.splitties:splitties-views-dsl-recyclerview
com.louiscad.splitties:splitties-views-material
com.louiscad.splitties:splitties-views-recyclerview
com.louiscad.splitties:splitties-views-selectable
com.louiscad.splitties:splitties-views-selectable-appcompat
com.louiscad.splitties:splitties-views-selectable-constraintlayout

Snapshots

Let's say you need to try a new feature or a fix that did not make it to a release yet:

You can grab it in the snapshot version by adding the corresponding repository as shown below, and changing the library version to the latest snapshot, 3.0.0-SNAPSHOT:

allProjects {
    repositories {
        mavenCentral()
        google() // Add sonatype snapshots repo below
        maven(url = "https://oss.sonatype.org/content/repositories/snapshots")
    }
}

New versions notifications

Releases are announced on GitHub, you can subscribe by clicking on "Watch", then "Releases only".

However, if you use refreshVersions, you'll also learn about updates when you run the refreshVersions task right in the versions.properties file.

Improve this library

If you want this library to have a new feature or an improvement in a new or in an existing module, please, open an issue or vote/comment a similar one first, so it can be discussed.

Documentation contributions are also welcome. For typos or other small improvements, feel free to submit a PR (pull request) directly. For more significant doc contributions, please open an issue first, so it can be discussed.

If you find a bug, please open an issue with all the important details. If you know a simple fix that is not API breaking and that does not have side effects that need to be considered, you may also directly submit a PR.

You can also join the discussion on Kotlin's Slack in the #splitties channel (you can get an invitation here).

What is a split

A "split" is a module of the Splitties library that you can add as a dependency. It only includes the required transitive dependencies. This allows you to only add what you need in your app or library module, so the final apk/ipa/app is as small as possible and doesn't include stuff not used by your app.

Let's say you're building a Wear OS app using the Views DSL. Wear OS apps don't need AppCompat. Including it would be a waste of bandwidth and storage. The Views DSL core module relies on the Android SDK but not on AppCompat, so you don't bloat your wrist app with AppCompat by using Views DSL. However, if you are building a phone, tablet or computer Android app, there's a Views DSL AppCompat split with a few extensions for you to use.

Credits

Special thanks to Jovche Mitrejchevski for helping in taking decisions for this project.

Thanks to JetBrains and the contributors for Anko, which was a great source of inspiration, especially for Views DSL, and of course thanks for the excellent Kotlin programming language that makes this project possible.

Thanks to Doug Stevenson for his articles "Kotlin & Android: A Brass Tacks Experiment". It is fair to say that Views DSL has its root in this experiment.

License

This library is published under Apache License version 2.0 which you can see here.

splitties's People

Contributors

adammc331 avatar dimezis avatar ivoberger avatar jmfayard avatar libern avatar louiscad avatar miha-x64 avatar mrthegood 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

splitties's Issues

Add extensions for TextInputLayout

Code to add:

import android.support.annotation.IdRes
import android.support.design.widget.TextInputEditText
import android.support.design.widget.TextInputLayout
import splitties.viewdsl.core.add
import splitties.viewdsl.core.matchParent
import splitties.viewdsl.core.wrapContent
import android.widget.LinearLayout.LayoutParams as LP

inline fun TextInputLayout.addInput(
        @IdRes id: Int,
        initView: TextInputEditText.() -> Unit = {}
) = add(::TextInputEditText, id, LP(matchParent, wrapContent), initView)

Check ui thread in Bundle delegates

With already prohibited suspension points thanks to crossinline modifier on the lambdas, this will completely rule out usage that could lead to inconsistent states

Deploy snapshots on oss.jfrog.org

Snapshots would be helpful for development and testing in other projects before making a release.
The goal is to use the artifactory gradle plugin to publish the snapshot versions to oss.jfrog.org.

See PR #43

Release the version 2.0.0-alpha1

This will help dogfooding the newest version (currently have to import the projects you need manually, which is impractical and is more and more inconvenient).

Any help to improve the publishing scripts and add snapshots publishing to nexus sonatype right from gradle is welcome.

Create a viewdsl-appcompat-styles module

This module would provide helper functions ready to use in the View DSL for common AppCompat xml defined styles such as Button and ProgressBar styles.

If other support libraries have such xml only themes that are needed by users of this library, a similar issue may be created for these to create their respective modules

Ditch NestedScrollView for RecyclerView

NestedScrollView is present in the sample and in the viewdsl-support-compat module. This is a very unreliable view, so I'll remove it completely from Splitties. That means the viewdsl-support-compat split will be removed, without having been released in any version (except snapshots).

RecyclerView can replace it without any issue:
https://gist.github.com/LouisCAD/2877b893f26f7f63cec1cea918a5b3c9

A new split could be done to provide this adapter, plus a helper to use it with the simplicity of a ScrollView from View DSL standpoint.

Remove Mutable from stringSet preferences

This is important since editing the returned value from a string set pref delegated property will not propagate changes to the preferences. This will have no runtime impact since the SharedPreferencesImpl wraps the string set in a HashSet regardless of it there was already a HashSet.

Add lambda ViewModelFactory for activityScope and fragmentScope extensions.

Example for FragmentActivity.activityScope extension:

inline fun <reified VM : ViewModel> FragmentActivity.activityScope(noinline factory: () -> VM) = uiLazy {
    ViewModelProviders.of(this, TypeSafeViewModelFactory(factory)).get(VM::class.java)
}

@PublishedApi
internal class TypeSafeViewModelFactory<VM : ViewModel>(
        private val factory: () -> VM
) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>) = factory() as T
}

Example usage:

private val viewModel by activityScope {
    val repoType = withExtras(ExtrasSpec) { repoType }
    SubRedditViewModel(ServiceLocator.instance(this@RedditActivity).getRepository(repoType))
}

Add onCreate and onOpen extension functions in arch-room split

Before:

val cheeseDb = roomDb<CheeseDb>(name = "CheeseDatabase") {
    addCallback(object : RoomDatabase.Callback() {
        override fun onCreate(db: SupportSQLiteDatabase) {
            fillInDb()
        }
    })
}

After:

val cheeseDb = roomDb<CheeseDb>(name = "CheeseDatabase") {
    onCreate { db ->
        fillInDb()
    }
}

Complete module specific documentation.

Some modules have their own README (which is great!) but not all of them do. For the sake of consistency (and also to complete the root README file) I think we should finish them. The ones that are missing are:

  • arch-lifecycle
  • arch-room
  • bitflags
  • bundle
  • exceptions
  • fragmentargs
  • initprovider
  • mainhandler
  • preferences
  • resources
  • selectableviews
  • snackbar
  • stetho-init
  • support-fragmentargs
  • systemservices
  • toast
  • typesaferecyclerview
  • uithread

Improve the README

Improvement path:

  • Add snippets to compare with and without, as done in Android KTX README
  • The list of the splits can be made thinner by replacing headings by bullet points
  • The related splits may be grouped (views group, viewdsl group, others group…)

Any other ideas to improve it further are welcome!

Add lint error when views are added in lParams lambda

Can you spot the error in the snippet below?

add(::verticalLayout, lParams(width = matchParent) {
    val inputLParams = lParams(width = matchParent)
    add(firstNameInput, inputLParams)
    add(lastNameInput, inputLParams)
    add(emailInput, inputLParams)
    add(mobilePhoneNumberInput, inputLParams)
})

Here's the fixed version:

add(::verticalLayout, lParams(width = matchParent)) {
    val inputLParams = lParams(width = matchParent)
    add(firstNameInput, inputLParams)
    add(lastNameInput, inputLParams)
    add(emailInput, inputLParams)
    add(mobilePhoneNumberInput, inputLParams)
}

Did you notice? I hopefully managed to notice my mistake. I added the views from the lParams lambda instead of from the add lambda, which made them be added to the parent of the verticalLayout instead of in the verticalLayout itself.

A lint should be able to catch such mistake and show an error

Add lint warning for AppCtx

A persistent lint warning should be present for any Context.injectAsAppCtx() usage since it's potentially unsafe to use. This should escalate to fatal if directly called with a subclass of the types know to Context.canLeakMemory().

There could also lint warnings when using appCtx to get resources that are commonly invalidated with common configuration changes (dimensions with screen rotation for example) or which rely on theme.

Allow disabling default tint in Material List Items

Example of how it could be done:

class IconOneLineListItem(
        context: Context,
        disableDefaultTint: Boolean
) : SelectableConstraintLayout(context) {

    constructor(context: Context) : this(context, disableDefaultTint = false)

    val icon = v(::imageView, R.id.icon) {
        if (!disableDefaultTint) imgTintList = styledColorSL(android.R.attr.textColorSecondary)
    }

    // Class body
}

Also, the AttributeSet and style parameters could be removed since the one that only takes a Context is the only one needed. This would decrease the methods count (View constructors even if useless, are not proguarded).

Find an eye catching description/tagline

The current short description is "A collection of light, general purpose Android libraries. Kotlin friendly."

Since the library is now 99% Kotlin and GitHub shows it, "Kotlin friendly" is no longer necessary.
Also, I'm not so satisfied with this description that is old. The upcoming 2.0.0-alpha1 version has more features, and I'm looking for an appropriate description. This will probably get easier once the doc is updated though (which is very WIP).

Rename lParams() from View DSL Design to avoid overload resolution ambiguity

When in the same file you want to use lParams(…) extension function for both LinearLayout and AppBarLayout, you get an overload resolution ambiguity that prevents compilation because the LinearLayout extension could also work for AppBarLayout. Same when using CoordinatorLayout and FrameLayout in the same file.
Using named imports can solve this issue, but it's not ideal and it can make naming unconventional.

To avoid this issue, only the classes that have ViewGroup as their direct parent class (like FrameLayout, LinearLayout and ConstraintLayout) should have an lParams extension function. Subclasses should follow a different naming convention.

defaultLParams(…) could replace lParams(…) for these indirect ViewGroup child classes.
If anyone has a better name idea, please, comment here (even if the issue is closed).

See issues KT-22770 and KT-22323 for more details.

Add mapNotNull, switchMap and switchMapNotNull extensions for LiveData

Snippets for switchMap:

import android.arch.lifecycle.LiveData
import android.arch.lifecycle.Transformations

inline fun <X, Y> LiveData<X>.switchMap(
        crossinline transform: (X?) -> LiveData<Y>?
): LiveData<Y> = Transformations.switchMap(this, { input -> transform(input) })

inline fun <X, Y> LiveData<X>.switchMapNotNull(
        crossinline transform: (X) -> LiveData<Y>?
): LiveData<Y> = Transformations.switchMap(this, { input: X? ->
    input?.let { transform(it) }
})

Add KDoc in bundle split

Should be pretty easy to do for anyone as there's a README that explains how to use it.

Any help is appreciated as this library is a lot of work for me, and this is (very) far from being the only project I work on.

Create a module for android collections

Example of what could be included in the module:

/**
 * Iterate the receiver [List] using an index instead of an [Iterator] like [forEach] would do.
 * Using this function saves an [Iterator] allocation, which is good for immutable lists or usages
 * confined to a single thread like UI thread only use.
 * However, this method will not detect concurrent modification, which may lead to unpredictable
 * behavior.
 *
 * @f the action to invoke on each list element.
 */
inline fun <T> List<T>.forEachByIndex(f: (T) -> Unit) {
    for (i in 0..lastIndex) f(get(i))
}

Helpers for Android SparseArrays could also be added in this module, or in another module.
If you have some opinions about this, please, add them in a comment.

Add extensions to ConstraintLayout.LayoutParams

Thanks to such extensions, the following snippet:

add(container, lParams(width = matchParent) {
    topToBottom = appBar.id
    bottomToTop = bottomNav.id
})

could become:

add(container, lParams(width = matchParent) {
    topToBottomOf(appBar)
    bottomToTopOf(bottomNav)
})

Also, there could be a check for a valid View id

Create views-cardview module

So extensions like contentPadding can be added:

import android.support.v7.widget.CardView

var CardView.contentPadding: Int
    @Deprecated(NO_GETTER, level = DeprecationLevel.HIDDEN) get() = noGetter
    set(value) = setContentPadding(value, value, value, value)

Add tests to checkedlazy module

There's multiple ways to test (JUnit, Espresso, kotlintest, spek, etc). I'm not sure which one should be picked at the moment, but I know checkedlazy is a module that can greatly be tested, and should be to make sure any change that could be made to it never breaks it.

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.