From 1f0aef77b4eb374aac142e82d9e6fe2f5374cb9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20G=C3=B3mez?= Date: Sun, 29 Mar 2026 17:58:15 +0200 Subject: [PATCH 1/2] readme updated --- README.md | 285 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 228 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 5075cb7d..567e8ffb 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,232 @@ -Android Commons -========== +# Android Commons - +[![Continuous Delivery](https://github.com/raxden/android-commons/workflows/Continuous%20Delivery/badge.svg)](https://github.com/raxden/android-commons/actions/workflows/deploy_library.yml) [![codecov](https://codecov.io/gh/raxden/android-commons/branch/master/graph/badge.svg?token=E55S5DHJ9B)](https://codecov.io/gh/raxden/android-commons) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android) +[![API](https://img.shields.io/badge/API-24%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=24) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -Android Commons is a set of libraries that I have been creating and collecting throughout these -years -of development and that I use continuously in my new developments in order to avoid having to -maintain -the code in different sources. - -With the purpose of avoiding having to depend on only one library, I decided to split the library in -different modules since the user that needs only use some utils or extensions from Retrofit library -don't need to download nothing related with the coroutines and vice-versa. That approach permits us -to reduce the size of the application that we are developing. - -## Getting started - -### Setting up the dependency that you requires. - -```groovy -implementation "com.raxdenstudios:commons-android:x.y.z" -implementation "com.raxdenstudios:commons-android-test:x.y.z" -implementation "com.raxdenstudios:commons-coroutines:x.y.z" -implementation "com.raxdenstudios:commons-coroutines-test:x.y.z" -implementation "com.raxdenstudios:commons-glide:x.y.z" -implementation "com.raxdenstudios:commons-threeten:x.y.z" -implementation "com.raxdenstudios:commons-okhttp3:x.y.z" -implementation "com.raxdenstudios:commons-pagination:x.y.z" -implementation "com.raxdenstudios:commons-pagination-co:x.y.z" -implementation "com.raxdenstudios:commons-pagination-rx:x.y.z" -implementation "com.raxdenstudios:commons-permissions:x.y.z" -implementation "com.raxdenstudios:commons-preferences:x.y.z" -implementation "com.raxdenstudios:commons-retrofit:x.y.z" -implementation "com.raxdenstudios:commons-retrofit-co:x.y.z" -implementation "com.raxdenstudios:commons-retrofit-rx:x.y.z" -implementation "com.raxdenstudios:commons-rx:x.y.z" -implementation "com.raxdenstudios:commons-rx-test:x.y.z" -implementation "com.raxdenstudios:commons-threeten:x.y.z" -``` - -Please replace `x`, `y` and `z` with the latest version numbers --> [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android) - -## LICENSE - - Copyright 2015 Ángel GΓ³mez - - 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. +A comprehensive collection of modular Android libraries providing utilities, extensions, and common functionality for modern Android development. + +## πŸ“‹ Overview + +Android Commons is a curated set of libraries designed to accelerate Android development by providing reusable components and utilities. Each module is independent, allowing you to include only what you need, keeping your app size minimal. + +### ✨ Key Features + +- 🎯 **Modular Architecture** - Include only the modules you need +- πŸš€ **Modern Android** - Built with Kotlin, Coroutines, and Jetpack Compose +- πŸ§ͺ **Well Tested** - Comprehensive unit test coverage +- πŸ“¦ **Small Footprint** - Minimal dependencies per module +- πŸ”„ **Active Maintenance** - Regular updates and improvements + +## πŸ“š Available Modules + +| Module | Description | Latest Version | +|--------|-------------|----------------| +| **Core & Android** | +| `commons-core` | Core utilities and extensions | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-core.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-core) | +| `commons-android` | Android-specific utilities and extensions | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-android) | +| `commons-android-binding` | View binding utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-binding.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-android-binding) | +| `commons-android-compose` | Jetpack Compose utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-compose.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-android-compose) | +| `commons-android-test` | Android testing utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-test.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-android-test) | +| **Async & Concurrency** | +| `commons-coroutines` | Kotlin Coroutines extensions | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-coroutines.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-coroutines) | +| `commons-coroutines-test` | Coroutines testing utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-coroutines-test.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-coroutines-test) | +| **Networking** | +| `commons-network` | Network utilities and interceptors | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-network.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-network) | +| **Pagination** | +| `commons-pagination` | Base pagination framework | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-pagination.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-pagination) | +| `commons-pagination-co` | Coroutines-based pagination | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-pagination-co.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-pagination-co) | +| **Permissions** | +| `commons-permissions` | Runtime permissions management | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-permissions.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-permissions) | +| **Storage** | +| `commons-preferences` | Advanced SharedPreferences wrapper | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-preferences.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-preferences) | +| **Date & Time** | +| `commons-threeten` | ThreeTen date/time utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-threeten.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-threeten) | +| `commons-threeten-test` | ThreeTen testing utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-threeten-test.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-threeten-test) | + +## πŸš€ Getting Started + +### Requirements + +- **Min SDK**: 24 (Android 7.0) +- **Target SDK**: 35 (Android 15) +- **Kotlin**: 1.9+ +- **Java**: 17 + +### Installation + +Add the desired modules to your `build.gradle.kts`: + +```kotlin +dependencies { + // Core modules + implementation("com.raxdenstudios:commons-core:x.y.z") + implementation("com.raxdenstudios:commons-android:x.y.z") + + // Coroutines support + implementation("com.raxdenstudios:commons-coroutines:x.y.z") + testImplementation("com.raxdenstudios:commons-coroutines-test:x.y.z") + + // Networking + implementation("com.raxdenstudios:commons-network:x.y.z") + + // Pagination + implementation("com.raxdenstudios:commons-pagination:x.y.z") + implementation("com.raxdenstudios:commons-pagination-co:x.y.z") + + // Permissions + implementation("com.raxdenstudios:commons-permissions:x.y.z") + + // Preferences + implementation("com.raxdenstudios:commons-preferences:x.y.z") + + // Date & Time + implementation("com.raxdenstudios:commons-threeten:x.y.z") + testImplementation("com.raxdenstudios:commons-threeten-test:x.y.z") + + // Testing + testImplementation("com.raxdenstudios:commons-android-test:x.y.z") +} +``` + +> **Note:** Replace `x.y.z` with the latest version: [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android) + +## πŸ’‘ Usage Examples + +### Preferences + +```kotlin +// Create preferences instance +val preferences = AdvancedPreferences.Default(context) + +// Save data with extension +preferences.edit { + put("username", "john_doe") + put("age", 25) + put("settings", Settings(theme = "dark")) +} + +// Read data +val username = preferences.get("username", "") +val age = preferences.get("age", 0) +val settings = preferences.get("settings", Settings()) +``` + +### Permissions + +```kotlin +class MainActivity : ComponentActivity() { + private val permissionsManager = PermissionsManagerImpl() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + permissionsManager.attach(this) + + // Request permissions + permissionsManager.requestPermission( + callbacks = PermissionsManager.Callbacks( + onGranted = { permission -> + // Permission granted + }, + onDenied = { permission -> + // Permission denied + } + ), + Permission.Camera, + Permission.AccessFineLocation + ) + } +} +``` + +### Pagination + +```kotlin +// Create pagination instance +val pagination = CoPagination( + config = Pagination.Config.default, + coroutineScope = viewModelScope +) + +// Request first page +pagination.requestFirstPage( + pageRequest = { page, pageSize -> + repository.getItems(page.value, pageSize.value) + }, + pageResponse = { result -> + when (result) { + is PageResult.Loading -> showLoading() + is PageResult.Content -> showItems(result.items) + is PageResult.Error -> showError(result.error) + is PageResult.NoMoreResults -> hideLoadMore() + } + } +) +``` + +### Network Interceptors + +```kotlin +val okHttpClient = OkHttpClient.Builder() + .addInterceptor(AuthTokenInterceptor { getAuthToken() }) + .addInterceptor(RetryInterceptor(maxRetries = 3)) + .addInterceptor(NetworkMonitorInterceptor(networkMonitor)) + .addInterceptor(HeadersInterceptor.userAgent("MyApp/1.0")) + .build() +``` + +## πŸ§ͺ Testing + +All modules include comprehensive unit tests. Run tests with: + +```bash +./gradlew test +``` + +For coverage reports: + +```bash +./gradlew jacocoTestReport +``` + +## πŸ“– Documentation + +Detailed documentation for each module is available in their respective directories: + +- [Core](libraries/core/README.md) +- [Android](libraries/android/README.md) +- [Coroutines](libraries/coroutines/README.md) +- [Network](libraries/network/README.md) +- [Pagination](libraries/pagination/README.md) +- [Permissions](libraries/permissions/README.md) +- [Preferences](libraries/preferences/README.md) + +## 🀝 Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +1. Fork the repository +2. Create your feature branch (`git checkout -b feature/amazing-feature`) +3. Commit your changes (`git commit -m 'Add some amazing feature'`) +4. Push to the branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +## πŸ“„ License + +``` +Copyright 2015 Ángel GΓ³mez + +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. +``` From 972061036e500eb3c767fd0d3c9073e3a0ea2988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20G=C3=B3mez?= Date: Sun, 29 Mar 2026 18:03:53 +0200 Subject: [PATCH 2/2] readme updated --- README.md | 175 +++++++---------------- libraries/network/README.md | 237 ++++++++++++++++++++++++++++++++ libraries/pagination/README.md | 212 ++++++++++++++++++++++++++++ libraries/permissions/README.md | 161 ++++++++++++++++++++++ libraries/preferences/README.md | 146 ++++++++++++++++++++ 5 files changed, 802 insertions(+), 129 deletions(-) create mode 100644 libraries/network/README.md create mode 100644 libraries/pagination/README.md create mode 100644 libraries/permissions/README.md create mode 100644 libraries/preferences/README.md diff --git a/README.md b/README.md index 567e8ffb..c9356159 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Android Commons -[![Continuous Delivery](https://github.com/raxden/android-commons/workflows/Continuous%20Delivery/badge.svg)](https://github.com/raxden/android-commons/actions/workflows/deploy_library.yml) +[![Continuous Delivery](https://github.com/raxden/android-commons/workflows/Continuous%20Delivery/badge.svg)](https://github.com/raxden/android-commons/actions/workflows/ci_publish.yml) [![codecov](https://codecov.io/gh/raxden/android-commons/branch/master/graph/badge.svg?token=E55S5DHJ9B)](https://codecov.io/gh/raxden/android-commons) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android) +[![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-bom.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-bom) [![API](https://img.shields.io/badge/API-24%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=24) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) @@ -22,29 +22,31 @@ Android Commons is a curated set of libraries designed to accelerate Android dev ## πŸ“š Available Modules -| Module | Description | Latest Version | -|--------|-------------|----------------| +| Module | Description | Documentation | Latest Version | +|--------|-------------|---------------|----------------| +| **Bill of Materials** | +| `commons-bom` | BOM for version management | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-bom.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-bom) | | **Core & Android** | -| `commons-core` | Core utilities and extensions | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-core.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-core) | -| `commons-android` | Android-specific utilities and extensions | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-android) | -| `commons-android-binding` | View binding utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-binding.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-android-binding) | -| `commons-android-compose` | Jetpack Compose utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-compose.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-android-compose) | -| `commons-android-test` | Android testing utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-test.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-android-test) | +| `commons-core` | Core utilities and extensions | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-core.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-core) | +| `commons-android` | Android-specific utilities and extensions | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-android) | +| `commons-android-binding` | View binding utilities | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-binding.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-android-binding) | +| `commons-android-compose` | Jetpack Compose utilities | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-compose.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-android-compose) | +| `commons-android-test` | Android testing utilities | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-android-test.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-android-test) | | **Async & Concurrency** | -| `commons-coroutines` | Kotlin Coroutines extensions | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-coroutines.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-coroutines) | -| `commons-coroutines-test` | Coroutines testing utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-coroutines-test.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-coroutines-test) | +| `commons-coroutines` | Kotlin Coroutines extensions | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-coroutines.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-coroutines) | +| `commons-coroutines-test` | Coroutines testing utilities | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-coroutines-test.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-coroutines-test) | | **Networking** | -| `commons-network` | Network utilities and interceptors | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-network.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-network) | +| `commons-network` | Network utilities and interceptors | [πŸ“– Docs](libraries/network/README.md) | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-network.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-network) | | **Pagination** | -| `commons-pagination` | Base pagination framework | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-pagination.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-pagination) | -| `commons-pagination-co` | Coroutines-based pagination | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-pagination-co.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-pagination-co) | +| `commons-pagination` | Base pagination framework | [πŸ“– Docs](libraries/pagination/README.md) | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-pagination.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-pagination) | +| `commons-pagination-co` | Coroutines-based pagination | [πŸ“– Docs](libraries/pagination/README.md) | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-pagination-co.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-pagination-co) | | **Permissions** | -| `commons-permissions` | Runtime permissions management | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-permissions.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-permissions) | +| `commons-permissions` | Runtime permissions management | [πŸ“– Docs](libraries/permissions/README.md) | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-permissions.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-permissions) | | **Storage** | -| `commons-preferences` | Advanced SharedPreferences wrapper | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-preferences.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-preferences) | +| `commons-preferences` | Advanced SharedPreferences wrapper | [πŸ“– Docs](libraries/preferences/README.md) | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-preferences.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-preferences) | | **Date & Time** | -| `commons-threeten` | ThreeTen date/time utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-threeten.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-threeten) | -| `commons-threeten-test` | ThreeTen testing utilities | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-threeten-test.svg)](https://search.maven.org/artifact/com.raxdenstudios/commons-threeten-test) | +| `commons-threeten` | ThreeTen date/time utilities | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-threeten.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-threeten) | +| `commons-threeten-test` | ThreeTen testing utilities | - | [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-threeten-test.svg?label=version)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-threeten-test) | ## πŸš€ Getting Started @@ -57,125 +59,40 @@ Android Commons is a curated set of libraries designed to accelerate Android dev ### Installation -Add the desired modules to your `build.gradle.kts`: +#### Using BOM (Bill of Materials) 🎯 -```kotlin -dependencies { - // Core modules - implementation("com.raxdenstudios:commons-core:x.y.z") - implementation("com.raxdenstudios:commons-android:x.y.z") - - // Coroutines support - implementation("com.raxdenstudios:commons-coroutines:x.y.z") - testImplementation("com.raxdenstudios:commons-coroutines-test:x.y.z") - - // Networking - implementation("com.raxdenstudios:commons-network:x.y.z") - - // Pagination - implementation("com.raxdenstudios:commons-pagination:x.y.z") - implementation("com.raxdenstudios:commons-pagination-co:x.y.z") - - // Permissions - implementation("com.raxdenstudios:commons-permissions:x.y.z") - - // Preferences - implementation("com.raxdenstudios:commons-preferences:x.y.z") - - // Date & Time - implementation("com.raxdenstudios:commons-threeten:x.y.z") - testImplementation("com.raxdenstudios:commons-threeten-test:x.y.z") - - // Testing - testImplementation("com.raxdenstudios:commons-android-test:x.y.z") -} -``` - -> **Note:** Replace `x.y.z` with the latest version: [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.raxdenstudios/commons-android) - -## πŸ’‘ Usage Examples - -### Preferences +The **Bill of Materials (BOM)** manages all library versions automatically, ensuring compatibility between modules. -```kotlin -// Create preferences instance -val preferences = AdvancedPreferences.Default(context) - -// Save data with extension -preferences.edit { - put("username", "john_doe") - put("age", 25) - put("settings", Settings(theme = "dark")) -} - -// Read data -val username = preferences.get("username", "") -val age = preferences.get("age", 0) -val settings = preferences.get("settings", Settings()) -``` - -### Permissions +**Latest BOM version:** [![Maven Central](https://img.shields.io/maven-central/v/com.raxdenstudios/commons-bom.svg)](https://central.sonatype.com/artifact/com.raxdenstudios/commons-bom) ```kotlin -class MainActivity : ComponentActivity() { - private val permissionsManager = PermissionsManagerImpl() +dependencies { + // Import the BOM with the latest version (check badge above) + implementation(platform("com.raxdenstudios:commons-bom:")) + + // Add modules without specifying versions + implementation("com.raxdenstudios:commons-core") + implementation("com.raxdenstudios:commons-android") + implementation("com.raxdenstudios:commons-coroutines") + implementation("com.raxdenstudios:commons-network") + implementation("com.raxdenstudios:commons-pagination") + implementation("com.raxdenstudios:commons-pagination-co") + implementation("com.raxdenstudios:commons-permissions") + implementation("com.raxdenstudios:commons-preferences") + implementation("com.raxdenstudios:commons-threeten") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - permissionsManager.attach(this) - - // Request permissions - permissionsManager.requestPermission( - callbacks = PermissionsManager.Callbacks( - onGranted = { permission -> - // Permission granted - }, - onDenied = { permission -> - // Permission denied - } - ), - Permission.Camera, - Permission.AccessFineLocation - ) - } + // Testing modules + testImplementation("com.raxdenstudios:commons-coroutines-test") + testImplementation("com.raxdenstudios:commons-threeten-test") + testImplementation("com.raxdenstudios:commons-android-test") } ``` -### Pagination - -```kotlin -// Create pagination instance -val pagination = CoPagination( - config = Pagination.Config.default, - coroutineScope = viewModelScope -) - -// Request first page -pagination.requestFirstPage( - pageRequest = { page, pageSize -> - repository.getItems(page.value, pageSize.value) - }, - pageResponse = { result -> - when (result) { - is PageResult.Loading -> showLoading() - is PageResult.Content -> showItems(result.items) - is PageResult.Error -> showError(result.error) - is PageResult.NoMoreResults -> hideLoadMore() - } - } -) -``` - -### Network Interceptors - -```kotlin -val okHttpClient = OkHttpClient.Builder() - .addInterceptor(AuthTokenInterceptor { getAuthToken() }) - .addInterceptor(RetryInterceptor(maxRetries = 3)) - .addInterceptor(NetworkMonitorInterceptor(networkMonitor)) - .addInterceptor(HeadersInterceptor.userAgent("MyApp/1.0")) - .build() -``` +**Benefits of using BOM:** +- βœ… No need to specify versions for each module +- βœ… Guaranteed compatibility between all modules +- βœ… Easier updates - just change the BOM version +- βœ… Prevents version conflicts ## πŸ§ͺ Testing diff --git a/libraries/network/README.md b/libraries/network/README.md new file mode 100644 index 00000000..16807070 --- /dev/null +++ b/libraries/network/README.md @@ -0,0 +1,237 @@ +# Network Module + +Network utilities and OkHttp interceptors for modern Android networking. + +## πŸ“¦ Installation + +```kotlin +dependencies { + implementation(platform("com.raxdenstudios:commons-bom:")) + implementation("com.raxdenstudios:commons-network") +} +``` + +## πŸš€ Usage + +### OkHttp Interceptors + +#### Auth Token Interceptor + +```kotlin +val okHttpClient = OkHttpClient.Builder() + .addInterceptor(AuthTokenInterceptor { + getAuthToken() // Your token provider + }) + .build() +``` + +#### Retry Interceptor + +```kotlin +val okHttpClient = OkHttpClient.Builder() + .addInterceptor(RetryInterceptor( + maxRetries = 3, + delayMillis = 1000L + )) + .build() + +// With custom retry predicate +val retryInterceptor = RetryInterceptor( + maxRetries = 3, + shouldRetry = { response -> + response.code == 503 || response.code == 429 + } +) +``` + +#### Network Monitor Interceptor + +```kotlin +val okHttpClient = OkHttpClient.Builder() + .addInterceptor(NetworkMonitorInterceptor(networkMonitor)) + .build() + +// Throws NoNetworkException if network is unavailable +``` + +#### Headers Interceptor + +```kotlin +// Add custom headers +val headersInterceptor = HeadersInterceptor( + mapOf( + "X-API-Key" to "your-api-key", + "X-Client-Version" to "1.0.0" + ) +) + +// Or use factory methods +val userAgentInterceptor = HeadersInterceptor.userAgent("MyApp/1.0") +val apiVersionInterceptor = HeadersInterceptor.apiVersion("v1") + +val okHttpClient = OkHttpClient.Builder() + .addInterceptor(headersInterceptor) + .addInterceptor(userAgentInterceptor) + .build() +``` + +#### Request Timing Interceptor + +```kotlin +val okHttpClient = OkHttpClient.Builder() + .addInterceptor(RequestTimingInterceptor { url, durationMs -> + Log.d("Network", "Request to $url took ${durationMs}ms") + analytics.trackRequestDuration(url, durationMs) + }) + .build() +``` + +#### Error Response Interceptor + +```kotlin +val okHttpClient = OkHttpClient.Builder() + .addInterceptor(ErrorResponseInterceptor()) + .build() + +// Throws typed exceptions based on HTTP status codes: +// - UnauthorizedException (401) +// - ForbiddenException (403) +// - NotFoundException (404) +// - ServerErrorException (500+) +// - ClientErrorException (400-499) +``` + +### Complete Setup Example + +```kotlin +val okHttpClient = OkHttpClient.Builder() + .addInterceptor(NetworkMonitorInterceptor(networkMonitor)) + .addInterceptor(AuthTokenInterceptor { tokenProvider.getToken() }) + .addInterceptor(HeadersInterceptor.userAgent("MyApp/1.0")) + .addInterceptor(RequestTimingInterceptor { url, duration -> + analytics.trackRequest(url, duration) + }) + .addInterceptor(RetryInterceptor(maxRetries = 3)) + .addInterceptor(ErrorResponseInterceptor()) + .build() + +val retrofit = Retrofit.Builder() + .baseUrl("https://api.example.com") + .client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create()) + .build() +``` + +## πŸ“‹ Available Interceptors + +| Interceptor | Description | +|-------------|-------------| +| `AuthTokenInterceptor` | Adds Authorization header with token | +| `RetryInterceptor` | Retries failed requests with configurable strategy | +| `NetworkMonitorInterceptor` | Checks network availability before requests | +| `HeadersInterceptor` | Adds custom headers to all requests | +| `RequestTimingInterceptor` | Measures and reports request duration | +| `ErrorResponseInterceptor` | Throws typed exceptions for HTTP errors | + +## ✨ Features + +- βœ… Production-ready OkHttp interceptors +- βœ… Automatic retry with exponential backoff +- βœ… Network availability checking +- βœ… Request timing and analytics +- βœ… Typed HTTP error exceptions +- βœ… Token-based authentication +- βœ… Custom headers management +- βœ… Comprehensive unit tests + +## πŸ“– API Reference + +### AuthTokenInterceptor + +```kotlin +AuthTokenInterceptor(tokenProvider: () -> String?) +``` + +### RetryInterceptor + +```kotlin +RetryInterceptor( + maxRetries: Int = 3, + delayMillis: Long = 1000L, + shouldRetry: (Response) -> Boolean = { !it.isSuccessful } +) +``` + +### NetworkMonitorInterceptor + +```kotlin +NetworkMonitorInterceptor(networkMonitor: NetworkMonitor) +``` + +### HeadersInterceptor + +```kotlin +HeadersInterceptor(headers: Map) + +// Factory methods +HeadersInterceptor.userAgent(userAgent: String) +HeadersInterceptor.apiVersion(version: String) +``` + +### RequestTimingInterceptor + +```kotlin +RequestTimingInterceptor( + onRequestCompleted: (url: String, durationMs: Long) -> Unit +) +``` + +### ErrorResponseInterceptor + +```kotlin +ErrorResponseInterceptor() + +// Throws: +// - UnauthorizedException +// - ForbiddenException +// - NotFoundException +// - ServerErrorException +// - ClientErrorException +``` + +## πŸ’‘ Best Practices + +### Interceptor Order + +```kotlin +OkHttpClient.Builder() + .addInterceptor(NetworkMonitorInterceptor(...)) // 1. Check network first + .addInterceptor(AuthTokenInterceptor(...)) // 2. Add auth + .addInterceptor(HeadersInterceptor(...)) // 3. Add headers + .addInterceptor(RequestTimingInterceptor(...)) // 4. Measure timing + .addInterceptor(RetryInterceptor(...)) // 5. Retry if needed + .addInterceptor(ErrorResponseInterceptor()) // 6. Handle errors last + .build() +``` + +### Error Handling + +```kotlin +try { + val response = api.getData() +} catch (e: UnauthorizedException) { + // Refresh token and retry +} catch (e: ServerErrorException) { + // Show server error message +} catch (e: NoNetworkException) { + // Show no internet message +} +``` + +## πŸ§ͺ Testing + +All interceptors include comprehensive unit tests. + +```bash +./gradlew :libraries:network:testDebugUnitTest +``` diff --git a/libraries/pagination/README.md b/libraries/pagination/README.md new file mode 100644 index 00000000..4bf35357 --- /dev/null +++ b/libraries/pagination/README.md @@ -0,0 +1,212 @@ +# Pagination Module + +Base pagination framework for Android with support for RecyclerView and Jetpack Compose. + +## πŸ“¦ Installation + +```kotlin +dependencies { + implementation(platform("com.raxdenstudios:commons-bom:")) + implementation("com.raxdenstudios:commons-pagination") + + // For coroutines support + implementation("com.raxdenstudios:commons-pagination-co") +} +``` + +## πŸš€ Usage + +### With Coroutines (Recommended) + +```kotlin +class MyViewModel : ViewModel() { + private val pagination = CoPagination( + config = Pagination.Config.default, + coroutineScope = viewModelScope + ) + + fun loadFirstPage() { + pagination.requestFirstPage( + pageRequest = { page, pageSize -> + repository.getItems(page.value, pageSize.value) + }, + pageResponse = { result -> + when (result) { + is PageResult.Loading -> _state.value = State.Loading + is PageResult.Content -> _state.value = State.Success(result.items) + is PageResult.Error -> _state.value = State.Error(result.error) + is PageResult.NoResults -> _state.value = State.Empty + is PageResult.NoMoreResults -> _hasMore.value = false + } + } + ) + } + + fun loadNextPage() { + pagination.requestNextPage( + pageRequest = { page, pageSize -> + repository.getItems(page.value, pageSize.value) + }, + pageResponse = { result -> handlePageResult(result) } + ) + } +} +``` + +### With RecyclerView + +```kotlin +recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + val layoutManager = recyclerView.layoutManager as LinearLayoutManager + val pageIndex = layoutManager.toPageIndex() + + pagination.requestPage( + pageIndex = pageIndex, + pageRequest = { page, pageSize -> loadPage(page, pageSize) }, + pageResponse = { result -> handleResult(result) } + ) + } +}) +``` + +### With Jetpack Compose LazyColumn + +```kotlin +val lazyListState = rememberLazyListState() + +LazyColumn(state = lazyListState) { + items(items) { item -> + ItemCard(item) + } +} + +LaunchedEffect(lazyListState) { + snapshotFlow { lazyListState.toPageIndex() } + .collect { pageIndex -> + pagination.requestPage( + pageIndex = pageIndex, + pageRequest = { page, pageSize -> loadPage(page, pageSize) }, + pageResponse = { result -> handleResult(result) } + ) + } +} +``` + +## πŸ“‹ Configuration + +### Custom Configuration + +```kotlin +val pagination = CoPagination( + config = Pagination.Config( + initialPage = Page(0), + pageSize = PageSize(20), + prefetchDistance = 5 + ), + coroutineScope = viewModelScope +) +``` + +### Default Configuration + +```kotlin +Pagination.Config.default // Page(0), PageSize(10), prefetchDistance = 3 +``` + +## 🎯 Page Results + +### PageResult Types + +```kotlin +sealed class PageResult { + object Loading : PageResult() + data class Content(val items: List) : PageResult() + data class Error(val error: Throwable) : PageResult() + object NoResults : PageResult() + object NoMoreResults : PageResult() +} +``` + +### Handling Results + +```kotlin +when (result) { + is PageResult.Loading -> { + // Show loading indicator + } + is PageResult.Content -> { + // Add items to list + items.addAll(result.items) + } + is PageResult.Error -> { + // Show error message + showError(result.error) + } + is PageResult.NoResults -> { + // Show empty state + } + is PageResult.NoMoreResults -> { + // Hide load more button + } +} +``` + +## ✨ Features + +- βœ… Automatic page management +- βœ… Prefetch distance configuration +- βœ… Support for RecyclerView and Compose +- βœ… Coroutine-based async loading +- βœ… Request cancellation support +- βœ… Thread-safe implementation +- βœ… Comprehensive error handling + +## πŸ“– API Reference + +### CoPagination + +#### Methods + +- `requestFirstPage(pageRequest, pageResponse)` - Load first page +- `requestPreviousPage(pageRequest, pageResponse)` - Load previous page +- `requestNextPage(pageRequest, pageResponse)` - Load next page +- `requestPage(pageIndex, pageRequest, pageResponse)` - Load specific page +- `cancelCurrentRequest()` - Cancel ongoing request + +### Extension Functions + +- `LinearLayoutManager.toPageIndex(): PageIndex` - Get current page index +- `LazyListState.toPageIndex(): PageIndex` - Get current page index +- `LazyGridState.toPageIndex(): PageIndex` - Get current page index + +## πŸ’‘ Advanced Usage + +### Cancel Requests + +```kotlin +// Cancel current request when user scrolls rapidly +pagination.cancelCurrentRequest() +``` + +### Custom Page Request + +```kotlin +suspend fun loadPage(page: Page, pageSize: PageSize): PageList { + val response = api.getItems( + page = page.value, + limit = pageSize.value + ) + return PageList( + items = response.items, + page = page + ) +} +``` + +## πŸ§ͺ Testing + +```bash +./gradlew :libraries:pagination:testDebugUnitTest +./gradlew :libraries:pagination-co:testDebugUnitTest +``` diff --git a/libraries/permissions/README.md b/libraries/permissions/README.md new file mode 100644 index 00000000..fc79859c --- /dev/null +++ b/libraries/permissions/README.md @@ -0,0 +1,161 @@ +# Permissions Module + +Runtime permissions management for Android with lifecycle-aware handling. + +## πŸ“¦ Installation + +```kotlin +dependencies { + implementation(platform("com.raxdenstudios:commons-bom:")) + implementation("com.raxdenstudios:commons-permissions") +} +``` + +## πŸš€ Usage + +### Basic Setup + +```kotlin +class MainActivity : ComponentActivity() { + private val permissionsManager = PermissionsManagerImpl() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + permissionsManager.attach(this) + } +} +``` + +### Request Single Permission + +```kotlin +permissionsManager.requestPermission( + callbacks = PermissionsManager.Callbacks( + onGranted = { permission -> + // Permission granted + Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show() + }, + onDenied = { permission -> + // Permission denied + Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show() + }, + onRationale = { permission -> + // Show rationale to user + showRationaleDialog(permission) + } + ), + Permission.Camera +) +``` + +### Request Multiple Permissions + +```kotlin +permissionsManager.requestPermission( + callbacks = PermissionsManager.Callbacks( + onGranted = { permission -> + handleGrantedPermission(permission) + }, + onDenied = { permission -> + handleDeniedPermission(permission) + } + ), + Permission.Camera, + Permission.AccessFineLocation, + Permission.RecordAudio +) +``` + +### Check Permission Status + +```kotlin +permissionsManager.hasPermission( + onGranted = { isGranted -> + if (isGranted) { + // Permission is granted + startCamera() + } else { + // Permission not granted + requestCameraPermission() + } + }, + permission = Permission.Camera +) +``` + +## πŸ“‹ Available Permissions + +### Predefined Permissions + +- `Permission.Camera` - Camera access +- `Permission.AccessFineLocation` - Fine location +- `Permission.AccessCoarseLocation` - Coarse location +- `Permission.ReadContacts` - Read contacts +- `Permission.WriteContacts` - Write contacts +- `Permission.RecordAudio` - Record audio +- `Permission.CallPhone` - Make phone calls +- `Permission.ReadExternalStorage` - Read external storage +- `Permission.WriteExternalStorage` - Write external storage + +### Custom Permissions + +```kotlin +val customPermission = Permission.Other("android.permission.CUSTOM_PERMISSION") +``` + +## ✨ Features + +- βœ… Lifecycle-aware permission handling +- βœ… Multiple permissions support +- βœ… Rationale callback for better UX +- βœ… Type-safe permission definitions +- βœ… Automatic permission status checking +- βœ… Easy integration with ComponentActivity + +## πŸ“– API Reference + +### PermissionsManager + +#### Methods + +- `attach(activity: ComponentActivity)` - Attach to activity lifecycle +- `requestPermission(callbacks: Callbacks, vararg permissions: Permission)` - Request permissions +- `hasPermission(onGranted: (Boolean) -> Unit, permission: Permission)` - Check permission status + +### Callbacks + +```kotlin +PermissionsManager.Callbacks( + onGranted: (Permission) -> Unit = {}, + onRationale: (Permission) -> Unit = {}, + onDenied: (Permission) -> Unit = {} +) +``` + +## πŸ’‘ Best Practices + +### Show Rationale + +```kotlin +private fun showRationaleDialog(permission: Permission) { + AlertDialog.Builder(this) + .setTitle("Permission Required") + .setMessage("This permission is needed to...") + .setPositiveButton("Grant") { _, _ -> + // Request permission again + permissionsManager.requestPermission(callbacks, permission) + } + .setNegativeButton("Cancel", null) + .show() +} +``` + +### Handle Already Granted Permissions + +The library automatically checks if permissions are already granted before requesting them, calling `onGranted` immediately if they are. + +## πŸ§ͺ Testing + +```bash +./gradlew :libraries:permissions:testDebugUnitTest +``` diff --git a/libraries/preferences/README.md b/libraries/preferences/README.md new file mode 100644 index 00000000..0a3d35b9 --- /dev/null +++ b/libraries/preferences/README.md @@ -0,0 +1,146 @@ +# Preferences Module + +Advanced SharedPreferences wrapper with type-safe storage and Gson support. + +## πŸ“¦ Installation + +```kotlin +dependencies { + implementation(platform("com.raxdenstudios:commons-bom:")) + implementation("com.raxdenstudios:commons-preferences") +} +``` + +## πŸš€ Usage + +### Basic Setup + +```kotlin +// Create preferences instance +val preferences = AdvancedPreferences.Default(context) + +// Or create private preferences +val privatePrefs = AdvancedPreferences.Private( + context = context, + name = "my_preferences" +) +``` + +### Saving Data + +```kotlin +preferences.edit { + put("username", "john_doe") + put("age", 25) + put("isActive", true) + put("score", 99.5f) +} + +// With commit (synchronous) +preferences.edit(commit = true) { + put("important_data", "value") +} +``` + +### Reading Data + +```kotlin +val username = preferences.get("username", "default_name") +val age = preferences.get("age", 0) +val isActive = preferences.get("isActive", false) +val score = preferences.get("score", 0.0f) +``` + +### Supported Types + +- **Primitives**: `Int`, `String`, `Boolean`, `Float`, `Long` +- **Collections**: `Set` +- **JSON**: `JSONObject`, `JSONArray` +- **Custom Objects**: Any object serializable with Gson + +### Custom Objects + +```kotlin +data class User(val name: String, val email: String) + +// Save +preferences.edit { + put("user", User("John", "john@example.com")) +} + +// Read +val user = preferences.get("user", User("", "")) +``` + +### Advanced Operations + +```kotlin +// Check if key exists +if (preferences.contains("username")) { + // Key exists +} + +// Get all preferences +val allPrefs = preferences.getAll() + +// Remove specific key +preferences.edit { + remove("old_key") +} + +// Clear all preferences +preferences.edit { + clear() +} +``` + +## ✨ Features + +- βœ… Type-safe storage with automatic type detection +- βœ… Gson integration for custom objects +- βœ… JSON support (JSONObject, JSONArray) +- βœ… Extension function for cleaner syntax +- βœ… Support for both apply() and commit() +- βœ… Safe null handling +- βœ… Exception handling for corrupted data + +## πŸ“– API Reference + +### AdvancedPreferences + +#### Constructors + +- `AdvancedPreferences.Default(context: Context, gson: Gson = Gson())` +- `AdvancedPreferences.Private(context: Context, name: String, gson: Gson = Gson())` + +#### Methods + +- `get(key: String, defaultValue: Any): Any` - Get value with default +- `contains(key: String): Boolean` - Check if key exists +- `getAll(): Map` - Get all preferences +- `edit(): Editor` - Get editor instance + +### Editor + +- `put(key: String, value: Any): Editor` - Put value +- `remove(key: String): Editor` - Remove key +- `clear(): Editor` - Clear all +- `apply()` - Apply changes asynchronously +- `commit(): Boolean` - Commit changes synchronously + +### Extension Functions + +```kotlin +fun AdvancedPreferences.edit( + commit: Boolean = false, + action: AdvancedPreferences.Editor.() -> Unit +) +``` + +## πŸ§ͺ Testing + +The module includes comprehensive unit tests covering all functionality. + +```bash +./gradlew :libraries:preferences:testDebugUnitTest +```