Preference via delegates (Flow, Coroutines) + JetPack DataStore Storage + DSL for RecyclerView based preference screens

Overview

About

Release License

Introduction

This library is based on Flows and Coroutines and works with the provided DataStore Storage or even with a custom storage implementation. It supports LiveData by default as Flows can easily be converted to LiveData. Preferences are elegantly declared via delegates. Additionally the preference-screen module provides a DSL to easily set up RecyclerView based preference screens. It also supports custom extensions for custom preference screens.

Following are the key features:

  • define preferences elegantly via delegates
  • flow and coroutine based
  • allows to observe single / some / all preferences
  • provides suspending update functions
  • provides a DSL for a RecyclerView based setting screen

Core

With this library you can declare preferences via kotlin delegates,and observe and update them via kotlin Flows. This works with any storage implementation, an implementation for JetPack DataStore is provided already.

1/4 Define preferences:
Class) val testClass by anyPref(TestClass.CONVERTER, TestClass()) // NULLABLE variants val nullableString by nullableStringPref() val nullableInt by nullableIntPref() val nullableFloat by nullableFloatPref() val nullableDouble by nullableDoublePref() val nullableLong by nullableLongPref() val nullableBool by nullableBoolPref() } ">
object UserSettingsModel : SettingsModel(DataStoreStorage(name = "user")) {

  // Basic
  val name by stringPref("User")
  val alive by boolPref(true)
  val hairColor by intPref(Color.parseColor("#A52A2A"))
  val age by intPref(40)
  val income by floatPref(50000f)
  val dayOfBirth by longPref(0L)
  val doubleTest by doublePref(0.0)
  
  // Sets
  val childrenAges by intSetPref(setOf(20, 18, 16))
  val childrenIncomes by floatSetPref(setOf(30000f, 10000f, 0f))
  val childrenDaysOfBirth by longSetPref(setOf(0L, 0L, 0L))
  
  // Enum
  val car by enumPref(Car.Tesla)
  
  // custom class - provide a custom converter (String <=> Class)
  val testClass by anyPref(TestClass.CONVERTER, TestClass())
  
  // NULLABLE variants
  val nullableString by nullableStringPref()
  val nullableInt by nullableIntPref()
  val nullableFloat by nullableFloatPref()
  val nullableDouble by nullableDoublePref()
  val nullableLong by nullableLongPref()
  val nullableBool by nullableBoolPref()
}
2/4 Observe/Read preferences:
simply returns flow.first() in a blocking way) val name = UserSettingsModel.name.value // 3) observe a setting once UserSettingsModel.name.observeOnce(lifecycleScope) { L.d { "name = $it"} } // 4) observe ALL settings UserSettingsModel.changes.onEach { L.d { "[ALL SETTINGS OBSERVER] Setting '${it.setting.key}' changed its value to ${it.value}" } }.launchIn(lifecycleScope) // 5) observe SOME settings UserSettingsModel.changes´ .filter { it.setting == UserSettingsModel.name || it.setting == UserSettingsModel.age }.onEach { // we know that either the name or the age changes L.d { "[SOME SETTINGS OBSERVER] Setting '${it.setting.key}' changed its value to ${it.value}" } }.launchIn(lifecycleScope) // 6) read multiple settings in a suspending way lifecycleScope.launch(Dispatchers.IO) { val name = UserSettingsModel.childName1.flow.first() val alive = DemoSettingsModel.alive.flow.first() val hairColor = DemoSettingsModel.hairColor.flow.first() withContext(Dispatchers.Main) { textView.text = "Informations: $name, $alive, $hairColor" } } ">
// 1) simply observe a setting
UserSettingsModel.name.observe(lifecycleScope) {
	L.d { "name = $it"}
}

// 2) direct read (not recommended if not necessary but may be useful in many cases => simply returns flow.first() in a blocking way)
val name = UserSettingsModel.name.value

// 3) observe a setting once
UserSettingsModel.name.observeOnce(lifecycleScope) {
	L.d { "name = $it"}
}

// 4) observe ALL settings
UserSettingsModel.changes.onEach {
	L.d { "[ALL SETTINGS OBSERVER] Setting '${it.setting.key}' changed its value to ${it.value}" }
}.launchIn(lifecycleScope)

// 5) observe SOME settings
UserSettingsModel.changes´
	.filter {
		it.setting == UserSettingsModel.name ||
		it.setting == UserSettingsModel.age
	}.onEach {
		// we know that either the name or the age changes
		L.d { "[SOME SETTINGS OBSERVER] Setting '${it.setting.key}' changed its value to ${it.value}" }
	}.launchIn(lifecycleScope)
	
// 6) read multiple settings in a suspending way
lifecycleScope.launch(Dispatchers.IO) {
  val name = UserSettingsModel.childName1.flow.first()
  val alive = DemoSettingsModel.alive.flow.first()
  val hairColor = DemoSettingsModel.hairColor.flow.first()
  withContext(Dispatchers.Main) {
	textView.text = "Informations: $name, $alive, $hairColor"
  }
}
3/4 Lifedata:
val lifedata = UserSettingsModel.name.flow.asLiveData()
4/4 Update preferences:
lifecycleScope.launch(Dispatchers.IO)  {
  UserSettingsModel.name.update("Some new name")
  UserSettingsModel.age.update(30)
}

Storage

The Storage is an abstraction to support any storage implementation. The datastore module provides an implementation based on the Android JetPack DataStore.

Check out the corresponding readme here: DataStore Module README

Preference Screen

The preference-screen* modules allow you to create preference screens like following easily via DSL.

Demo 1 Demo 2 Demo 3 Demo 4

Explanations, code examples and more be found here: Preference Screen Modules README

Gradle (via JitPack.io)

  1. add jitpack to your project's build.gradle:
repositories {
    maven { url "https://jitpack.io" }
}
  1. add the compile statement to your module's build.gradle:
" // data store module implementation "com.github.MFlisar.MaterialPreferences:datastore:" // screen modules implementation "com.github.MFlisar.MaterialPreferences:screen:" implementation "com.github.MFlisar.MaterialPreferences:screen-input:" implementation "com.github.MFlisar.MaterialPreferences:screen-choice:" implementation "com.github.MFlisar.MaterialPreferences:screen-color:" } ">
dependencies {

  // core module
  implementation "com.github.MFlisar.MaterialPreferences:core:"

  // data store module
  implementation "com.github.MFlisar.MaterialPreferences:datastore:"
    
  // screen modules
  implementation "com.github.MFlisar.MaterialPreferences:screen:"
  implementation "com.github.MFlisar.MaterialPreferences:screen-input:"
  implementation "com.github.MFlisar.MaterialPreferences:screen-choice:"
  implementation "com.github.MFlisar.MaterialPreferences:screen-color:"
}

TODO

  • Preference Types
    • SeekBar Preference
    • Collapse Preference - add sub items ONCE on click
    • Dropdown Preference
    • Spacer Preference
  • Others
    • Global Setting - enable title numbering (Count numbers of categories yes/no)
    • use MaterialDialogFragments dialog fragments so that even the dialogs restore their state and remember temporary user changes inside the dialogs
You might also like...
Built with Jetpack compose, multi modules MVVM clean architecture, coroutines + flow, dependency injection, jetpack navigation and other jetpack components

RickAndMortyCompose - Work in progress A simple app using Jetpack compose, clean architecture, multi modules, coroutines + flows, dependency injection

This SDK can be used to identify a user via passport or ID Card prove identity of user via Biometry comparing selfie and photo from chip of ID Doc
This SDK can be used to identify a user via passport or ID Card prove identity of user via Biometry comparing selfie and photo from chip of ID Doc

Verdi Mobile SDK This SDK can be used to identify a user via passport or Id Card. In this repository, you can find the library itself and the Sample a

This SDK can be used to identify a user via passport or ID Card prove identity of user via Biometry comparing selfie and photo from chip of ID Doc ANDROID. ChipsLayoutManager (SpanLayoutManager, FlowLayoutManager). A custom layout manager for RecyclerView which mimicric TextView span behaviour, flow layouts behaviour with support of amazing recyclerView features
ANDROID. ChipsLayoutManager (SpanLayoutManager, FlowLayoutManager). A custom layout manager for RecyclerView which mimicric TextView span behaviour, flow layouts behaviour with support of amazing recyclerView features

ChipsLayoutManager This is ChipsLayoutManager - custom Recycler View's LayoutManager which moves item to the next line when no space left on the curre

🦄 Android Pokedex-AR using ARCore, Sceneform, Hilt, Coroutines, Flow, Jetpack (Room, ViewModel, LiveData) based on MVVM architecture.
🦄 Android Pokedex-AR using ARCore, Sceneform, Hilt, Coroutines, Flow, Jetpack (Room, ViewModel, LiveData) based on MVVM architecture.

🦄 Android Pokedex-AR using ARCore, Sceneform, Hilt, Coroutines, Flow, Jetpack (Room, ViewModel, LiveData) based on MVVM architecture.

🦄 Android Pokedex-AR using ARCore, Sceneform, Hilt, Coroutines, Flow, Jetpack based on MVVM architecture.
🦄 Android Pokedex-AR using ARCore, Sceneform, Hilt, Coroutines, Flow, Jetpack based on MVVM architecture.

Pokedex-AR Pokedex-AR is a small demo application based on AR, modern Android application tech-stacks, and MVVM architecture. This project focuses on

Simple Notes app demonstrates modern Android development with Hilt, Material Motion, Coroutines, Flow, Jetpack (Room, ViewModel) based on MVVM architecture.
Simple Notes app demonstrates modern Android development with Hilt, Material Motion, Coroutines, Flow, Jetpack (Room, ViewModel) based on MVVM architecture.

Simple Notes app demonstrates modern Android development with Hilt, Material Motion, Coroutines, Flow, Jetpack (Room, ViewModel) based on MVVM architecture.

 🗡️ Deddit demonstrates modern Android development with Hilt, Coroutines, Flow, Jetpack, and Material Design based on MVVM architecture
🗡️ Deddit demonstrates modern Android development with Hilt, Coroutines, Flow, Jetpack, and Material Design based on MVVM architecture

Deddit demonstrates modern Android development with Hilt, Coroutines, Flow, Jetpack (ViewModel,Paging3), and Material Design based on MVVM

🪐 Modern Android development with Hilt, Coroutines, Flow, JetPack(ViewModel) based on MVVM architecture.

Ceres 🪐 Modern Android development with Hilt, Coroutines, Flow, JetPack(ViewModel) based on MVVM architecture. Download Gradle Add the dependency bel

A simple, classic Kotlin MVI implementation based on coroutines with Android support, clean DSL and easy to understand logic

A simple, classic Kotlin MVI implementation based on coroutines with Android support, clean DSL and easy to understand logic

Recycler-coroutines - RecyclerView Auto Add Data Using Coroutines

Sample RecyclerView Auto Add With Coroutine Colaborator Very open to anyone, I'l

Elegant design and convenient to use RecyclerView adapter library based on Kotlin DSL.
Elegant design and convenient to use RecyclerView adapter library based on Kotlin DSL.

xAdapter: Kotlin DSL 风格的 Adapter 封装 1、简介 该项目是 KotlinDSL 风格的 Adapter 框架封装,用来简化 Adapter 调用,思想是采用工厂和构建者方式获取 Adapter 避免代码中定义大量的 Adapter 类。该项目在 BRVAH 的 Ada

Extensions to encrypt DataStore using Tink

encrypted-datastore Extensions to encrypt DataStore using Tink. ⚠️ This tiny library will be maintained until an official solution for DataStore encry

Android Clean Architechture with MVVM, LiveData, Coroutine, Dagger Hilt, Room, DataStore
Android Clean Architechture with MVVM, LiveData, Coroutine, Dagger Hilt, Room, DataStore

MovKu An application that displays a list of popular movies and detail Concepts Tech Stack Kotlin -A modern programming language that makes developers

:blowfish: An Android & JVM key-value storage powered by Protobuf and Coroutines

PufferDB PufferDB is a ⚡ key-value storage powered by Protocol Buffers (aka Protobuf) and Coroutines. The purpose of this library is to provide an eff

A lightweight Kotlin DSL to render DSL style Json to String.
A lightweight Kotlin DSL to render DSL style Json to String.

A lightweight Kotlin DSL to render DSL style Json to String.

A Collection on all Jetpack compose UI elements, Layouts, Widgets and Demo screens to see it's potential
A Collection on all Jetpack compose UI elements, Layouts, Widgets and Demo screens to see it's potential

ComposeCookBook Declarative UI A Collection of all Jetpack compose UI elements, Layouts, Widgets and Demo screens to see it's potential. Jetpack Compo

a set of Settings like composable items to help android Jetpack Compose developers build complex settings screens
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

This library will make it easier to pass arguments between screens in Jetpack Compose.
This library will make it easier to pass arguments between screens in Jetpack Compose.

Compose Navigation This library will make it easier to pass arguments between screens in Jetpack Compose Setup allprojects { repositories { ...

Comments
  • memory leak when switch app theme

    memory leak when switch app theme

    when switching between fragment no leak as before but got 3 leaks if I switched app theme in the settings fragment as the parent activity is recreated and the pervious instance is not cleared as settingsview is holding a reference to its context. and i really suggest that you setup a settings fragment in the test app so you catch errors and leaks that will only show in fragment as it has some differences than activity.

    opened by amrg101 2
  • settings items aren't displayed.

    settings items aren't displayed.

    I investigated it and found the source of the problem, fixed it myself until I found this good-looking comment, uncomment it and bug was fixed. https://github.com/MFlisar/MaterialPreferences/blob/2e5ad6da7af581386560b963605186659d669c9f/library-preference-screen/src/main/java/com/michaelflisar/materialpreferences/preferencescreen/recyclerview/PreferenceAdapter.kt#L47 the only way to update rv adapter was to add a visibilityDependsOn with Dependency object which was triggering updateCurrentFilteredItems(true) that updated the adapter list, also I found out that the object is leaking when in fragment, so I hope you investigate and fix it.

    Keep up the good work!

    opened by amrg101 2
  • fix disabled switch

    fix disabled switch

    fixes #5 I think it presents switches better that way. see image after fix: https://ibb.co/wzN5Fsv and now color can be customized by overriding "colorOnSurface", have no idea why didn't work before.

    opened by amrg101 1
  • crash when upgrade to v1.0.4

    crash when upgrade to v1.0.4

    opened settings screen and boom runtime crash at my face

    java.lang.NullPointerException: Attempt to invoke interface method 'int java.lang.CharSequence.length()' on a null object reference
                                                                	at android.text.StaticLayout.<init>(StaticLayout.java:455)
                                                                	at androidx.appcompat.widget.SwitchCompat.makeLayout(SwitchCompat.java:995)
                                                                	at androidx.appcompat.widget.SwitchCompat.onMeasure(SwitchCompat.java:916)
                                                                	at android.view.View.measure(View.java:25833)
                                                                	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6980)
                                                                	at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
                                                                	at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1204)
                                                                	at android.widget.LinearLayout.onMeasure(LinearLayout.java:723)
                                                                	at android.view.View.measure(View.java:25833)
                                                                  .......
    

    log of catched exception

    java.lang.UnsupportedOperationException: Failed to resolve attribute at index 0: TypedValue{t=0x2/d=0x7f040107 a=-1}
                                                                	at android.content.res.TypedArray.getColor(TypedArray.java:529)
                                                                	at androidx.core.content.res.ColorStateListInflaterCompat.inflate(ColorStateListInflaterCompat.java:160)
                                                                	at androidx.core.content.res.ColorStateListInflaterCompat.createFromXmlInner(ColorStateListInflaterCompat.java:125)
                                                                	at androidx.core.content.res.ColorStateListInflaterCompat.createFromXml(ColorStateListInflaterCompat.java:104)
                                                                	at androidx.core.content.res.ResourcesCompat.inflateColorStateList(ResourcesCompat.java:262)
                                                                	at androidx.core.content.res.ResourcesCompat.getColorStateList(ResourcesCompat.java:236)
                                                                	at androidx.core.content.ContextCompat.getColorStateList(ContextCompat.java:558)
                                                                	at androidx.appcompat.content.res.AppCompatResources.getColorStateList(AppCompatResources.java:48)
                                                                	at androidx.appcompat.widget.TintTypedArray.getColorStateList(TintTypedArray.java:179)
                                                                	at com.google.android.material.materialswitch.MaterialSwitch.<init>(MaterialSwitch.java:101)
                                                                	at com.google.android.material.materialswitch.MaterialSwitch.<init>(MaterialSwitch.java:72)
                                                                	at java.lang.reflect.Constructor.newInstance0(Native Method)
                                                                	at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
                                                                	at android.view.LayoutInflater.createView(LayoutInflater.java:858)
                                                                	at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1010)
                                                                	at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:965)
                                                                	at android.view.LayoutInflater.inflate(LayoutInflater.java:663)
                                                                	at android.view.LayoutInflater.inflate(LayoutInflater.java:538)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.bool.databinding.WidgetSwitchBinding.inflate(WidgetSwitchBinding.java:42)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.bool.switches.SwitchViewHolder.createSubBinding(SwitchViewHolder.kt:23)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.bool.switches.SwitchViewHolder.createSubBinding(SwitchViewHolder.kt:12)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.recyclerview.viewholders.base.BaseViewHolderWithWidget$subBinding$2.invoke(BaseViewHolderWithWidget.kt:31)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.recyclerview.viewholders.base.BaseViewHolderWithWidget$subBinding$2.invoke(BaseViewHolderWithWidget.kt:31)
                                                                	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.recyclerview.viewholders.base.BaseViewHolderWithWidget.getSubBinding(BaseViewHolderWithWidget.kt:31)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.bool.switches.SwitchViewHolder.bindWidget(SwitchViewHolder.kt:26)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.bool.switches.SwitchViewHolder.bindWidget(SwitchViewHolder.kt:12)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.recyclerview.viewholders.base.BaseViewHolderWithWidget.rebind(BaseViewHolderWithWidget.kt:92)
                                                                	at com.michaelflisar.materialpreferences.preferencescreen.recyclerview.viewholders.base.BaseViewHolderWithWidget$bind$1$1.invokeSuspend(BaseViewHolderWithWidget.kt:70)
    
    opened by amrg101 1
Releases(1.0.9)
  • 1.0.9(Jan 7, 2023)

    Changes:

    • reorder SettingsActivity create events to support dynamic colors in it
    • added function to convert image preference value before displaying it
    • boolean dependency extension adjusted
    • BooleanDependency extended: allows to define true/false dependency now

    Dependencies: MaterialDialogs: 0.8.5

    Full Changelog: https://github.com/MFlisar/MaterialPreferences/compare/1.0.8...1.0.9

    Source code(tar.gz)
    Source code(zip)
  • 1.0.8(Dec 7, 2022)

    • added onCreate/onDestroy callbacks to IScreenCreator (can be used for activity callback registration e.g. or other lifecycle aware functions so that you don't need to use a custom activity for this simple use cases)
    • added optional and hidden long press events to infos and buttons (to show debug/developer dialogs or similar)
    • default badge color is red now
    • a default primary material toolbar is used in the screen module now
    • defined a view styles that are used inside the screen module now so that you can overwrite them if desired (`MaterialPreferences.Preferences.*´)
    • material version updated to 1.7.0

    This release depends on version 0.7.0 of the MaterialDialogs library

    Full Changelog: https://github.com/MFlisar/MaterialPreferences/compare/1.0.7...1.0.8

    Source code(tar.gz)
    Source code(zip)
  • 1.0.7(Oct 19, 2022)

  • 1.0.6(Oct 17, 2022)

    • a lot of changes have been made inside the dialog library that is used as dependency
    • added a non clickable info preference
    • small bugfixes

    Full Changelog: https://github.com/MFlisar/MaterialPreferences/compare/1.0.5...1.0.6

    Source code(tar.gz)
    Source code(zip)
  • 1.0.5(Sep 29, 2022)

    • screen-image module added to "simply" add image based settings
    • DialogExtra can internally wrap some other parcelable now
    • dialog dependency updated to 0.3.2

    Full Changelog: https://github.com/MFlisar/MaterialPreferences/compare/1.0.4...1.0.5

    Source code(tar.gz)
    Source code(zip)
  • 1.0.4(Sep 23, 2022)

  • 1.0.3(Sep 23, 2022)

    Added 2 switch styles:

    • switch... a M3 styled switch
    • switchCompact... a M2 styled switch, a lot more compact

    Improvements:

    • Sliders do support discrete mode now,
    • int/long sliders do set step size to 1 internally to avoid intermediate float values
    • PreferenceScreen can call notifyItemChanded for a preference item now
    • bugfix if subscreens are filtered
    Source code(tar.gz)
    Source code(zip)
  • 1.0.2(Sep 23, 2022)

    • added SliderPreference
    • added a small utility class SettingsGroup for convenient handling of a combination of settings including observing their changes
    • small bugfixes
    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Sep 15, 2022)

    added min/max values + checks to number preferences

    This is a beautiful extension to the canChange callback. Those min/max values will be used inside the dialog directly and won't allow the user to close the dialog if the rule is violated. The canChange callback can still be used to evaluate a dependency to another rule and similar checks.

    Dependency

    MaterialDialogs: 0.3.1

    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Sep 15, 2022)

    Library depends on https://github.com/MFlisar/MaterialDialogs (Release 0.3) now, this means small visual changes will be visible.

    This version now depends on Material3 theme, so you need to use such a theme now!

    Small changes have been made, but mostly adjustments should be minimal and self explanatory.

    New features:

    • show/hide dependency in addition to the enable/disable dependency
    • support for all 4 main number types as input preference (int, long, float, double)
    • dialogs are fragments now and save + restore their state on screen rotation
    Source code(tar.gz)
    Source code(zip)
  • 0.5.7(Sep 13, 2022)

    • added the ability to force a ViewHolder Update on button click
    • added 2 types of dependencies: one for enabled and one for visibility
    • move boolean screen settings into their own module
    Source code(tar.gz)
    Source code(zip)
  • 0.5.6(Jul 21, 2022)

  • 0.5.5(Jul 21, 2022)

  • 0.5.1(Mar 25, 2021)

  • 0.5(Mar 25, 2021)

Owner
null
This project provides declarative camunda delegates for Spring based application

camunda-delegator-lib Features Declarative style for delegate code Generated delegates documentation and templates for camunda modeler(this feature is

Tinkoff.ru 27 Aug 12, 2022
A minimal notes application in Jetpack Compose with MVVM architecture. Built with components like DataStore, Coroutines, ViewModel, LiveData, Room, Navigation-Compose, Coil, koin etc.

Paper - A Minimal Notes App A minimal notes application in Jetpack Compose with MVVM architecture. Built with components like DataStore, Coroutines, V

Akshay Sharma 139 Jan 2, 2023
MVVM ,Hilt DI ,LiveData ,Flow ,Room ,Retrofit ,Coroutine , Navigation Component ,DataStore ,DataBinding , ViewBinding, Coil

MVVM ,Hilt DI ,LiveData ,Flow ,Room ,Retrofit ,Coroutine , Navigation Component ,DataStore ,DataBinding , ViewBinding, Coil

Ali Assalem 12 Nov 1, 2022
MVVM ,Hilt DI ,LiveData ,Flow ,SharedFlow ,Room ,Retrofit ,Coroutine , Navigation Component ,DataStore ,DataBinding , ViewBinding, Coil

RickMorty This is a simple app which has been implemented using Clean Architecture alongside MVVM design to run (online/offline) using : [ MVVM ,Hilt

Ali Assalem 13 Jan 5, 2023
An easy-to-use Android library that will help you to take screenshots of specif views of your app and save them to external storage (Including API 29 Q+ with Scope Storage)

???? English | ???? Português (pt-br) ???? English: An easy to use Library that will help you to take screenshots ?? of the views in your app Step 1.

Thyago Neves Silvestre 2 Dec 25, 2021
🧶 Library to handling files for persistent storage with Google Cloud Storage and Amazon S3-compatible server, made in Kotlin

?? Remi Library to handling files for persistent storage with Google Cloud Storage and Amazon S3-compatible server, made in Kotlin! Why is this built?

Noelware 8 Dec 17, 2022
Epoxy is an Android library for building complex screens in a RecyclerView

Epoxy Epoxy is an Android library for building complex screens in a RecyclerView. Models are automatically generated from custom views or databinding

Airbnb 8.1k Jan 4, 2023
Epoxy is an Android library for building complex screens in a RecyclerView

Epoxy Epoxy is an Android library for building complex screens in a RecyclerView. Models are automatically generated from custom views or databinding

Airbnb 8.1k Dec 29, 2022
Kotlin-client-dsl - A kotlin-based dsl project for a (Client) -> (Plugin) styled program

kotlin-client-dsl a kotlin-based dsl project for a (Client) -> (Plugin) styled p

jackson 3 Dec 10, 2022
MiHawk 🦅👁️ is simple and secure 🔒 Android Library to store and retrieve pair of key-value data with encryption , internally it use jetpack DataStore Preferences 💽 to store data.

MiHawk MiHawk ?? ??️ is simple and secure ?? Android Library to store and retrieve pair of key-value data with encryption , internally it use jetpack

Nedal Hasan Ibrahem 5 Sep 3, 2022