Skip to content

Commit 3242459

Browse files
author
Peter Bryant
committed
🎉 Initial commit
0 parents  commit 3242459

File tree

72 files changed

+2171
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+2171
-0
lines changed

.github/workflows/test.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Test
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
- develop
7+
- main
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v2
15+
16+
- name: Build
17+
run: ./gradlew build

.gitignore

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea/caches
5+
/.idea/libraries
6+
/.idea/modules.xml
7+
/.idea/workspace.xml
8+
/.idea/navEditor.xml
9+
/.idea/assetWizardSettings.xml
10+
.DS_Store
11+
/build
12+
/captures
13+
.externalNativeBuild
14+
.cxx
15+
local.properties

.idea/.gitignore

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/.name

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/compiler.xml

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/deploymentTargetDropDown.xml

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/inspectionProfiles/Project_Default.xml

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Kotlin Bloc
2+
3+
An implementation of
4+
the [Bloc pattern](https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc) for
5+
Kotlin and Jetpack Compose.
6+

build.gradle

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
buildscript {
2+
ext {
3+
kotlin_version = '1.5.21'
4+
compose_version = '1.0.2'
5+
6+
}
7+
repositories {
8+
google()
9+
mavenCentral()
10+
maven {
11+
url "https://plugins.gradle.org/m2/"
12+
}
13+
}
14+
dependencies {
15+
classpath "com.android.tools.build:gradle:7.0.2"
16+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
17+
classpath 'org.jlleitschuh.gradle:ktlint-gradle:10.2.0'
18+
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.5.30"
19+
}
20+
}
21+
22+
plugins {
23+
id("org.jetbrains.dokka") version "1.5.30"
24+
}
25+
26+
subprojects {
27+
apply plugin: 'org.jlleitschuh.gradle.ktlint'
28+
}
29+
30+
task clean(type: Delete) {
31+
delete rootProject.buildDir
32+
}

compose/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

compose/build.gradle

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
plugins {
2+
id 'com.android.library'
3+
id 'kotlin-android'
4+
id 'org.jetbrains.dokka'
5+
id 'maven-publish'
6+
}
7+
8+
publishing {
9+
publications {
10+
release(MavenPublication) {
11+
groupId = "com.ptrbrynt.kotlin-bloc"
12+
artifactId = "compose"
13+
}
14+
}
15+
}
16+
17+
android {
18+
compileSdk 30
19+
20+
defaultConfig {
21+
minSdk 21
22+
targetSdk 30
23+
versionCode 1
24+
versionName "1.0"
25+
26+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
27+
consumerProguardFiles "consumer-rules.pro"
28+
}
29+
30+
buildTypes {
31+
release {
32+
minifyEnabled false
33+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
34+
}
35+
}
36+
37+
compileOptions {
38+
sourceCompatibility JavaVersion.VERSION_1_8
39+
targetCompatibility JavaVersion.VERSION_1_8
40+
}
41+
42+
kotlinOptions {
43+
jvmTarget = '1.8'
44+
}
45+
46+
packagingOptions {
47+
resources {
48+
excludes += '/META-INF/{AL2.0,LGPL2.1}'
49+
}
50+
}
51+
52+
buildFeatures {
53+
compose true
54+
}
55+
56+
composeOptions {
57+
kotlinCompilerExtensionVersion compose_version
58+
}
59+
60+
testOptions {
61+
unitTests {
62+
includeAndroidResources = true
63+
}
64+
}
65+
}
66+
67+
ktlint {
68+
android = true
69+
}
70+
71+
dependencies {
72+
implementation 'androidx.core:core-ktx:1.6.0'
73+
implementation 'androidx.appcompat:appcompat:1.3.1'
74+
implementation 'com.google.android.material:material:1.4.0'
75+
76+
implementation "androidx.compose.ui:ui:$compose_version"
77+
api project(path: ':core')
78+
79+
testImplementation 'junit:junit:4.13.2'
80+
testImplementation 'org.robolectric:robolectric:4.6.1'
81+
82+
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
83+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
84+
85+
testImplementation "androidx.compose.material:material:$compose_version"
86+
testImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
87+
88+
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
89+
}
90+
91+
gradle.taskGraph.useFilter { task ->
92+
if (task.name.startsWith("test") && task.name.contains("ReleaseUnitTest")) {
93+
return false;
94+
}
95+
return true;
96+
}

compose/consumer-rules.pro

Whitespace-only changes.

compose/proguard-rules.pro

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile

compose/src/main/AndroidManifest.xml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest package="com.ptrbrynt.kotlin_bloc.compose" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.ptrbrynt.kotlin_bloc.compose
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.collectAsState
5+
import androidx.compose.runtime.getValue
6+
import com.ptrbrynt.kotlin_bloc.core.BlocBase
7+
import kotlinx.coroutines.flow.filter
8+
9+
/**
10+
* [BlocComposer] handles re-composition of its [content] in response to new [State]s.
11+
*
12+
* Please use [BlocListener] if you want to *do* anything in response to [State] changes
13+
* e.g. display a Snackbar.
14+
*
15+
* ```kotlin
16+
* BlocBuilder(myBloc) { state ->
17+
* // Add your composables here
18+
* }
19+
* ```
20+
*
21+
* An optional [composeWhen] can be implemented for more granular control over
22+
* how often [BlocComposer] re-composes.
23+
* [composeWhen] will be invoked whenever the [bloc] state changes.
24+
* [composeWhen] is optional and, when omitted, will default to `true`.
25+
*
26+
* @param bloc The bloc or cubit that the [BlocComposer] will interact with.
27+
* @param content The composable function which is re-composed on each new [bloc] state.
28+
* @param composeWhen Provides more granular control over how often [BlocComposer] re-composes.
29+
* @see BlocListener
30+
*/
31+
@Composable
32+
fun <B : BlocBase<State>, State> BlocComposer(
33+
bloc: B,
34+
composeWhen: (State) -> Boolean = { true },
35+
content: @Composable (State) -> Unit,
36+
) {
37+
val state by bloc.stateFlow.filter { composeWhen(it) }.collectAsState(initial = bloc.state)
38+
39+
content(state)
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.ptrbrynt.kotlin_bloc.compose
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.LaunchedEffect
5+
import androidx.compose.runtime.collectAsState
6+
import androidx.compose.runtime.getValue
7+
import com.ptrbrynt.kotlin_bloc.core.BlocBase
8+
import kotlinx.coroutines.flow.filter
9+
10+
/**
11+
* Takes a [bloc] and an [onState] callback and invokes [onState] in response to `state` changes
12+
* in the [bloc].
13+
*
14+
* It should be used for side-effects resulting from new `state`s being emitted by the [bloc] e.g.
15+
* navigation, showing a snackbar etc.
16+
*
17+
* If you want to build composables in response to new states, use [BlocComposer]
18+
*
19+
* ```kotlin
20+
* BlocListener(bloc) { state ->
21+
* // React to the new state here
22+
* }
23+
* ```
24+
*
25+
* An optional [reactWhen] can be implemented for more granular control over when [onState] is
26+
* called.
27+
* [reactWhen] will be invoked on every [bloc] state change.
28+
* [reactWhen] is optional and, when omitted, will default to `true`.
29+
*
30+
* @param bloc The bloc or cubit that the [BlocListener] will interact with.
31+
* @param onState The callback function which will be invoked whenever a new `state` is emitted by the [bloc].
32+
* @param reactWhen Provides more granular control over when [onState] is invoked.
33+
* @see BlocComposer
34+
*/
35+
@Composable
36+
fun <B : BlocBase<State>, State> BlocListener(
37+
bloc: B,
38+
reactWhen: (State) -> Boolean = { true },
39+
onState: suspend (State) -> Unit,
40+
) {
41+
val state by bloc.stateFlow.filter { reactWhen(it) }.collectAsState(initial = null)
42+
43+
state?.let {
44+
LaunchedEffect(it) {
45+
onState(it)
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)