All Projects → GetStream → butterfly

GetStream / butterfly

Licence: Apache-2.0 License
🦋 Butterfly helps you to build adaptive and responsive UIs for Android with Jetpack WindowManager.

Programming Languages

kotlin
9241 projects

Projects that are alternatives of or similar to butterfly

GitReposCompose
GitReposCompose is an Android application 📱 for showcasing Jetpack Compose for building declarative UI in Android. This demo app uses Github public API for fetching public repositories.
Stars: ✭ 32 (-81.07%)
Mutual labels:  jetpack, jetpack-compose
GitMessengerBot-Android
타입스크립트, V8 엔진의 자바스크립트, 파이썬 그리고 Git을 지원하는 최첨단 메신저 봇!
Stars: ✭ 51 (-69.82%)
Mutual labels:  jetpack, jetpack-compose
neon
Provides Jetpack Compose support for different image loading libraries.
Stars: ✭ 13 (-92.31%)
Mutual labels:  jetpack, jetpack-compose
Awesome-Android-Open-Source-Projects
👓 A curated list of awesome android projects by open-source contributors.
Stars: ✭ 401 (+137.28%)
Mutual labels:  jetpack, jetpack-compose
Holi
Holi is a lightweight Jetpack Compose library of colors, gradients and cool utility functions for all your palette needs!
Stars: ✭ 160 (-5.33%)
Mutual labels:  jetpack, jetpack-compose
PCard
Demo project to showcase adding payment card details using JetPack Compose
Stars: ✭ 61 (-63.91%)
Mutual labels:  jetpack, jetpack-compose
compose-ratingbar
A ratingbar composable for jetpack compose 🚀🌟
Stars: ✭ 89 (-47.34%)
Mutual labels:  jetpack, jetpack-compose
Scout
Scout is a kotlin multiplatform application that allows users to search and save games to lists to be browsed later.
Stars: ✭ 28 (-83.43%)
Mutual labels:  jetpack, jetpack-compose
RocketXDelight-Playground
Native Android application built with Kotlin and Jetpack Compose. This project also illustrates the usage of advanced libraries such as Ktor, SqlDelight, Hilt, etc with the recommended practices and Unit Tests.
Stars: ✭ 37 (-78.11%)
Mutual labels:  jetpack, jetpack-compose
Jetpack Compose News
基于Jetpack Compose实现的一款集新闻、视频、美图、音乐、天气等功能的资讯App,持续完善中...
Stars: ✭ 58 (-65.68%)
Mutual labels:  jetpack, jetpack-compose
Strict-DataBinding
善用 DataBinding 彻底解决 “View 实例的 Null 安全一致性问题”
Stars: ✭ 84 (-50.3%)
Mutual labels:  jetpack, jetpack-compose
MovieBox
TMDb + Kotlin + Coroutines + Retrofit2 + Moshi + Clean Architecture + Koin 2 + Glide
Stars: ✭ 46 (-72.78%)
Mutual labels:  jetpack, jetpack-compose
Compose-Settings
Android #JetpackCompose Settings library
Stars: ✭ 188 (+11.24%)
Mutual labels:  jetpack, jetpack-compose
Wiggles
🐶 Beautiful Puppy adoption app with Jetpack Compose #AndroidDevChallenge
Stars: ✭ 365 (+115.98%)
Mutual labels:  jetpack, jetpack-compose
Delish
Delish, a Food Recipes App in Jetpack Compose and Hilt based on modern Android tech-stacks and MVI clean architecture.
Stars: ✭ 356 (+110.65%)
Mutual labels:  jetpack, jetpack-compose
SSJetpackComposeSwipeableView
SSJetpackComposeSwipeableView is a small library which provides support for the swipeable views. You can use this in your lazyColumns or can add a simple view which contains swipe to edit/delete functionality.
Stars: ✭ 57 (-66.27%)
Mutual labels:  jetpack, jetpack-compose
ComposeBird
Flappy Bird game
Stars: ✭ 193 (+14.2%)
Mutual labels:  jetpack, jetpack-compose
android-developer-roadmap
🗺 The 2022 Android Developer Roadmap suggests learning paths to understanding Android development.
Stars: ✭ 5,533 (+3173.96%)
Mutual labels:  jetpack, jetpack-compose
arkitekt
Arkitekt is a set of architectural tools based on Android Architecture Components, which gives you a solid base to implement the concise, testable and solid application.
Stars: ✭ 114 (-32.54%)
Mutual labels:  jetpack, jetpack-compose
JsonPlaceholderApp
This was originally a code challenge for a company, but now is an example of MVI on Android.
Stars: ✭ 26 (-84.62%)
Mutual labels:  jetpack, jetpack-compose

Butterfly

Google
License API Build Status Kotlin Weekly Android Weekly Dokka


🦋 Butterfly helps you to build adaptive and responsive UIs for Android with Jetpack WindowManager.
Also, it supports useful functions for Jetpack Compose and LiveData integration.


Preview

🌗 See dark theme

Dark Theme

Demo Project

The demo project was 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:

Contribution 💙

Butterfly is maintained by Stream. If you’re interested in adding powerful In-App Messaging to your app, check out the Stream Chat SDK for Android! Also, anyone can contribute to improving code, docs, or something following our Contributing Guideline.

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.1"
    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.2-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            
        }
    }
}

You can also get the following information from the WindowLayoutInfo as in the following extensions:

val isSeparating: Boolean = WindowLayoutInfo.isSeparating
val occlusionType: FoldingFeature.OcclusionType = WindowLayoutInfo.occlusionType 
val orientation: FoldingFeature.Orientation = WindowLayoutInfo.orientation
val state: FoldingFeature.State = WindowLayoutInfo.state

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

Hinge Size

If your foldable device is separated by a hinge, you can get a hinge size with the extensions below:

val hingePxSize: Int = foldingFeature.hingePxSize
val hingeDpSize: Int = foldingFeature.hingeDpSize
val hingeWidthPxSize: Int = foldingFeature.hingeWidthPxSize
val hingeHeightPxSize: Int = foldingFeature.hingeHeightPxSize
val hingeWidthDpSize: Int = foldingFeature.hingeWidthDpSize
val hingeHeightDpSize: Int = foldingFeature.hingeHeightDpSize

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.1"
}

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
    ...                
}

Hinge Size

If your foldable device is separated by a hinge, you can get a hinge size with the extensions below:

val hingeDp: Dp = FoldingFeature.hingeDp
val hingeDpSize: DpSize = FoldingFeature.hingeDpSize
val hingeWidthDp: Dp = FoldingFeature.hingeWidthDp
val hingeHeightDp: Dp = FoldingFeature.hingeHeightDp

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.1"
}

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.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].