Butterfly - Butterfly helps to build adaptive and responsive UIs for Android with Jetpack WindowManager

Overview

Butterfly

License API Build Status Dokka


πŸ¦‹ Butterfly helps to build adaptive and responsive UIs for Android with Jetpack WindowManager.
Also, supports useful functions for Jetpack Compose and LiveData integration.


Preview

πŸŒ— See dark theme

Dark Theme

Demo Project

The demo project built with the Stream Chat SDK for Jetpack Compose. It would be helpful to understand the demo project if you check out the links below:

Download

Maven Central

Gradle

Add the codes below to your root build.gradle file (not your module build.gradle file).

allprojects {
    repositories {
        mavenCentral()
    }
}

Next, add the dependency below to your module's build.gradle file.

dependencies {
    implementation "io.getstream:butterfly:1.0.0"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
}

Note: Butterfly includes Jetpack WindowManager to compute window internally. So if you're using WindowManager in your project, please make sure your project uses the same version or exclude the dependency to adapt yours.

SNAPSHOT

See how to import the snapshot

Including the SNAPSHOT

Snapshots of the current development version of Butterfly are available, which track the latest versions.

To import snapshot versions on your project, add the code snippet below on your gradle file.

repositories {
   maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}

Next, add the below dependency to your module's build.gradle file.

dependencies {
    implementation "io.getstream:butterfly:1.0.1-SNAPSHOT"
}

Set up Foldable Emulator

If you don't have foldable devices or emulators, you can set up a foldable emulator environment following the below instruction:

πŸ‘‰ Check out the Set up Foldable Emulator (Surface Duo 2)

Usage

Butterfly uses Jetpack WindowManager, so it would be helpful to understand if you have background knowledge of the WindowManager APIs.

WindowSize

WindowSize represents breakpoints, which are the screen size at which a layout will adapt to best fit content and conform to responsive layout requirements. Butterfly follows three breakpoints by Material Design.

  • WindowSize.Compact: Most phones in portrait mode. (0-599 dp range)
  • WindowSize.Medium: Most foldables and tablets in portrait mode. (600-839 dp range)
  • WindowSize.Expanded: Most tablets in landscape mode. (840+ dp range)

You can get an instance of the WindowSize class with getWindowSize() method on your Activity or Fragment as following below:

val windowSize: WindowSize = getWindowSize()
when (windowSize) {
    is WindowSize.Compact -> // the window size is compact.
    is WindowSize.Medium -> // the window size is medium.
    is WindowSize.Expanded -> // the window size is expanded.
}

GlobalWindowSize

You can customize the pre-defined breakpoints, which used to getWindowSize() with GlobalWindowSize object class as following below:

GlobalWindowSize.compactWindowDpSize = 600
GlobalWindowSize.mediumWindowDpSize = 840

Also, you can fully customize a factory function of the WindowSize class as following below:

GlobalWindowSize.windowSizeFactory = { windowPixelSize ->
    when {
        windowPixelSize.width < 0 -> throw IllegalArgumentException("Can't be negative")
        windowPixelSize.width < 600.dp2Px() -> WindowSize.Compact(windowPixelSize)
        windowPixelSize.width < 840.dp2Px() -> WindowSize.Medium(windowPixelSize)
        else -> WindowSize.Expanded(windowPixelSize)
    }
}

Posture

Fold state: FLAT and HALF-OPENED from Google.

Posture class represents device postures in the flexible display or a hinge between two physical display panels.

  • Posture.TableTop - Device posture is in tabletop mode (half open with the hinge horizontal).
  • Posture.Book - Device posture is in book mode (half open with the hinge vertical).
  • Posture.Normal - Device posture is in normal mode.

You can observe the posture as a Kotlin Flow on you Activity or Fragment as following below:

lifecycleScope.launch(Dispatchers.Main) {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        postureFlow.collect { posture ->
            when (posture) {
                Posture.Normal -> // posture is Normal
                is Posture.TableTop -> // posture is TableTop
                is Posture.Book -> // posture is Book
            }
        }
        windowLayoutInfo.collect(::onWindowLayoutInfoUpdated)
    }
}

Note: Make sure your project includes Coroutines and androidx.lifecycle:lifecycle-runtime-ktx:2.4.0 dependencies.

WindowLayoutInfo

WindowLayoutInfo contains the list of DisplayFeature-s located within the window. You can observe the WindowLayoutInfo as following below:

lifecycleScope.launch(Dispatchers.Main) {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        windowLayoutInfo.collect { windowLayoutInfo ->
            // something stuff            
        }
    }
}

FoldingFeature

FoldingFeature that describes a fold in the flexible display or a hinge between two physical display panels. You can utilize the extensions below to check folding states and device postures:

val foldingFeature = windowLayoutInfo.displayFeatures.findFoldingFeature()
val posture = foldingFeature?.toPosture()
val isTableTopPosture = foldingFeature?.isTableTopPosture
val isBookPosture = foldingFeature?.isBookPosture
val isHalfOpened = foldingFeature?.isHalfOpened
val isFlat = foldingFeature?.isFlat
val isVertical = foldingFeature?.isVertical
val isHorizontal = foldingFeature?.isHorizontal

WindowInfoActivity

Butterfly supports WindowInfoActivity, which tracks window configurations and update the WindowLayoutInfo. It has a default windowSize property and onWindowLayoutInfoUpdated abstract method as in the example below:

class MainActivity : WindowInfoActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // windowSize property will be initialized lazily.
        when (windowSize) {
            is WindowSize.Compact -> 
            ...
        }
    }

    override fun onWindowLayoutInfoUpdated(windowLayoutInfo: WindowLayoutInfo) {
        val foldingFeature = windowLayoutInfo.displayFeatures.findFoldingFeature() ?: return
        when (val posture = foldingFeature.toPosture()) {
            Posture.Normal -> Log.d(tag, "[Posture.Normal] ${posture.size}")
            is Posture.TableTop -> Log.d(tag, "[Posture.TableTop] ${posture.size}")
            ...
        }
    }
}

The pre-defined windowSize property will be initialized lazily and the onWindowLayoutInfoUpdated will be updated when the WindowLayoutInfo configuration changed. As the same concept, you can extend WindowInfoFragment for your Fragment.

Butterfly for Jetpack Compose

Maven Central

Butterfly supports Jetpack Compose to build adaptive and responsive UIs. First, add the dependency below to your module's build.gradle file.

dependencies {
    implementation "io.getstream:butterfly-compose:1.0.0"
}

WindowDpSize

WindowDpSize represents breakpoints, which are the screen size at which a layout will adapt to best fit content and conform to responsive layout requirements. Butterfly follows three breakpoints by Material Design.

You can remember an instance of the WindowDpSize class with rememberWindowDpSize() method on your Activity or Fragment as following below:

val windowDpSize: WindowDpSize = rememberWindowDpSize()
when (windowDpSize) {
    is WindowSize.Compact -> MainScreenRegular()
    is WindowSize.Medium -> MainScreenMedium()
    is WindowSize.Expanded -> MainScreenExpanded()
}

Note: Likewise the WindowSize, you can also customize the pre-defined breakpoints, which used to rememberWindowDpSize with the GlobalWindowSize object class.

Posture

You can get a State of Posture to build adaptive and responsive UIs with the postureState extension on your Activity and Fragment as following below:

val postureState: State<Posture> = postureState
when (postureState.value) {
    Posture.Normal -> // posture is Normal
    is Posture.TableTop -> // posture is TableTop
    is Posture.Book -> // posture is Book
}

WindowLayoutInfo

WindowLayoutInfo contains the list of DisplayFeature-s located within the window. You can get the State of the WindowLayoutInfo as following below:

val windowLayoutInfoState: State<WindowLayoutInfo> = windowLayoutInfoState
val foldingFeature = windowLayoutInfoState.value.displayFeatures.findFoldingFeature()
...

CompositionLocal

You can pass instances of the WindowDpSize and Posture down through the Composition implicitly as following below:

CompositionLocalProvider(LocalWindowDpSize provides rememberWindowDpSize()) {
    val windowDpSize = LocalWindowDpSize.current
    ...
}

CompositionLocalProvider(LocalPosture provides postureState.value) {
    val posture = LocalPosture.current
    ...                
}

Butterfly for LiveData Integration

Maven Central

Butterfly supports LiveData integration to let observing layout changes as LiveData. First, add the dependency below to your module's build.gradle file.

dependencies {
    implementation "io.getstream:butterfly-livedata:1.0.0"
}

You can observe LiveData of Posture and WindowLayoutInfo on your Activity and Fragment as in the following example below:

postureLiveData().observe(this) { posture ->
    // do something
}

windowLayoutInfoLiveData().observe(this) { windowLayoutInfo ->
    // do something
}

Find this library useful? ❀️

Support it by joining stargazers for this repository. ⭐️
Also, follow Stream on Twitter for our next creations!

License

Copyright 2022 Stream.IO, Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
You might also like...
Add IndustrialTNT like from old IC2 mod which keeps items after explosion and helps to mine resources
Add IndustrialTNT like from old IC2 mod which keeps items after explosion and helps to mine resources

IndustrialTNT Add IndustrialTNT like from old IC2 mod which keeps items after ex

Desktop app build with compose UI
Desktop app build with compose UI

Desktop App POS UI desktop app build with compose ui

A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose
A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose

Authentication A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose Scree

Compose-navigation - Set of utils to help with integrating Jetpack Compose and Jetpack's Navigation

Jetpack Compose Navigation Set of utils to help with integrating Jetpack Compose

An application that i developed with a aim of learning Jetpack compose and many other jetpack libraries
An application that i developed with a aim of learning Jetpack compose and many other jetpack libraries

An application that i developed with a aim of learning Jetpack compose and many other jetpack libraries, The application make use of jikan Api which displays a list of animations,there more details and even trailers of the animations.

Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.
Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.

Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.

Jetpack Compose Boids | Flocking Insect 🐜. bird or Fish simulation using Jetpack Compose Desktop πŸš€, using Canvas API 🎨
Jetpack Compose Boids | Flocking Insect 🐜. bird or Fish simulation using Jetpack Compose Desktop πŸš€, using Canvas API 🎨

🐜 🐜 🐜 Compose flocking Ants(boids) 🐜 🐜 🐜 Jetpack compose Boids | Flocking Insect. bird or Fish simulation using Jetpack Compose Desktop πŸš€ , usi

This is a sample app(For beginners - App #2) built using Jetpack Compose. It demonstrates the concept of State Hoisting in Jetpack Compose.
This is a sample app(For beginners - App #2) built using Jetpack Compose. It demonstrates the concept of State Hoisting in Jetpack Compose.

JetBMICalculator This is a sample app(For beginners - App #2) built using Jetpack Compose. It demonstrates the concept of State Hoisting in Jetpack Co

Jetpack-Compose-Demo - Instagram Profile UI using Jetpack Compose
Jetpack-Compose-Demo - Instagram Profile UI using Jetpack Compose

Jetpack-Compose-Demo Instagram Profile UI using Jetpack Compose

Comments
  • Create CODE_OF_CONDUCT.md

    Create CODE_OF_CONDUCT.md

    🎯 Goal

    Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.

    πŸ›  Implementation details

    Describe the implementation details for this Pull Request.

    ✍️ Explain examples

    Explain examples with code for this updates.

    Preparing a pull request for review

    Ensure your change is properly formatted by running:

    $ ./gradlew spotlessApply
    

    Please correct any failures before requesting a review.

    opened by skydoves 0
  • Implement hinge relevant extensions

    Implement hinge relevant extensions

    🎯 Goal

    Implement hinge-relevant extensions.

    πŸ›  Implementation details

    • Added LocalWindowLayoutInfo
    • Added WindowOrientation enum class and windowOrientation extension.

    FoldingFeature

    • FoldingFeature.hingeWidthPxSize: Int
    • FoldingFeature.hingeHeightPxSize: Int
    • FoldingFeature.hingePxSize: Int
    • FoldingFeature.hingeWidthDpSize: Int
    • FoldingFeature.hingeHeightDpSize: Int
    • FoldingFeature.hingeDpSize: Int

    FoldingFeature for Jetpack Compose

    • FoldingFeature.hingeWidthDp: Dp
    • FoldingFeature.hingeHeightDp: Dp
    • FoldingFeature.hingeDp: Dp

    WindowLayoutInfo

    • WindowLayoutInfo.isSeparating: Boolean
    • WindowLayoutInfo.occlusionType: FoldingFeature.OcclusionType
    • WindowLayoutInfo.orientation: FoldingFeature.Orientation
    • WindowLayoutInfo.state: FoldingFeature.State
    opened by skydoves 0
  • keep selectedChannelId when screen rotate

    keep selectedChannelId when screen rotate

    🎯 Goal

    keep selectedChannelId when screen rotate

    πŸ›  Implementation details

    Describe the implementation details for this Pull Request.

    ✍️ Explain examples

    Explain examples with code for this updates.

    Preparing a pull request for review

    Ensure your change is properly formatted by running:

    $ ./gradlew spotlessApply
    

    Please correct any failures before requesting a review.

    opened by HuixingWong 0
  • Folding Feature & state is null always

    Folding Feature & state is null always

    I am using a CompositionLocalProvider like

    CompositionLocalProvider(
                        LocalWindowDpSize provides rememberWindowDpSize(),
                        LocalWindowLayoutInfo provides windowLayoutInfoState.value,
                        LocalPosture provides postureState.value
                    )
    

    and in my composable

    LocalWindowLayoutInfo.current.isSeparating is always false

    and

    val foldingFeature = LocalWindowLayoutInfo.current.findFoldingFeature()
                if (foldingFeature?.state != FoldingFeature.State.HALF_OPENED) {
                    Text(
                        stringResource(screen.resourceId),
                        maxLines = 1,
                        style = SlackCloneTypography.overline,
                    )
                }
    

    foldingFeature?.state is always null.

    good first issue 
    opened by oianmol 6
Releases(1.0.1)
  • 1.0.1(Jan 27, 2022)

    πŸŽ‰ Released a new version 1.0.1! πŸŽ‰

    What's Changed

    • Updated Jetpack WindowManager to 1.0.0 stable by @skydoves in https://github.com/GetStream/butterfly/pull/3
    • Added hinge relevant extensions by @skydoves in https://github.com/GetStream/butterfly/pull/2

    πŸ›  Implementation details

    • Added LocalWindowLayoutInfo
    • Added WindowOrientation enum class and windowOrientation extension.

    FoldingFeature

    • FoldingFeature.hingeWidthPxSize: Int
    • FoldingFeature.hingeHeightPxSize: Int
    • FoldingFeature.hingePxSize: Int
    • FoldingFeature.hingeWidthDpSize: Int
    • FoldingFeature.hingeHeightDpSize: Int
    • FoldingFeature.hingeDpSize: Int

    FoldingFeature for Jetpack Compose

    • FoldingFeature.hingeWidthDp: Dp
    • FoldingFeature.hingeHeightDp: Dp
    • FoldingFeature.hingeDp: Dp

    WindowLayoutInfo

    • WindowLayoutInfo.isSeparating: Boolean
    • WindowLayoutInfo.occlusionType: FoldingFeature.OcclusionType
    • WindowLayoutInfo.orientation: FoldingFeature.Orientation
    • WindowLayoutInfo.state: FoldingFeature.State
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Jan 24, 2022)

Owner
Stream
Build scalable newsfeeds, activity streams, chat and messaging in a few hours instead of weeks
Stream
Jetpack-compose-uis - A collection of some UIs using Jetpack Compose. built using Katalog

Jetpack Compose UIs This is a collection of some UIs using Jetpack Compose. It i

Mori Atsushi 3 Dec 15, 2022
A framework for building responsive Android apps using Jetpack Compose

Jetmagic - A framework for building responsive Android apps using Jetpack Compose Jetmagic is an Android framework that can be used to develop respons

Johann Blake 93 Dec 17, 2022
A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!

Why Not Compose! A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!

Md. Mahmudul Hasan Shohag 186 Jan 1, 2023
Forget about bunch of XML files for maintaining UIs. Jetpack Compose is Android’s modern toolkit for building native UI. Here is a small example to get started.

Jetpack Compose Sample Description This repository is to get started with new Jetpack Compose Toolkit for Android. By using Jetpack Compose you no nee

Simform Solutions 39 Nov 10, 2022
πŸ”¦ Showkase is an annotation-processor based Android library that helps you organize, discover, search and visualize Jetpack Compose UI elements

Showkase is an annotation-processor based Android library that helps you organize, discover, search and visualize Jetpack Compose UI elements. With minimal configuration it generates a UI browser that helps you easily find your components, colors & typography. It also renders your components in common situations like dark mode, right-to-left layouts, and scaled fonts which help in finding issues early.

Airbnb 1.7k Jan 2, 2023
FullMangement - an application that helps you manage your tasks effectively. built with the latest tachs like Compose UI, Jetpack libraries, and MVVM design pattern.

Full Management is an application that helps you manage your tasks effectively. built with the latest tachs like Compose UI, Jetpack libraries and MVVM design pattern.

Amr algnyat 4 Nov 1, 2022
🎨 Jetpack Compose canvas library that helps you draw paths, images on canvas with color pickers and palettes

?? Jetpack Compose canvas library that helps you draw paths and images on canvas with color pickers and palettes. Sketchbook also provides useful components and functions that can easily interact with canvas.

Stream 342 Dec 30, 2022
PapriCoin demonstrates Jetpack Compose usage to build modern app based on Clean Architecture and newest Tech-Stack

PapriCoin demonstrates Jetpack Compose usage to build modern app based on Clean Architecture and newest Tech-Stack. Repository also has loca

Malik Mukhametzyanov 15 Nov 9, 2022
a set of Settings like composable items to help android Jetpack Compose developers build complex settings screens

This library provides a set of Settings like composable items to help android Jetpack Compose developers build complex settings screens without all the boilerplate

Bernat BorrΓ‘s Paronella 178 Jan 4, 2023
Build a StateFlow stream using Jetpack Compose

Molecule Build a StateFlow or Flow stream using Jetpack Compose1. fun CoroutineScope.launchCounter(): StateFlow<Int> = launchMolecule { val count by

Cash App 1.3k Dec 29, 2022