Skip to content

Commit

Permalink
Merge pull request #79 from icerockdev/develop
Browse files Browse the repository at this point in the history
Release 0.15.0
  • Loading branch information
Alex009 authored Apr 10, 2023
2 parents c9d1ca4 + 89e8569 commit bbadb95
Show file tree
Hide file tree
Showing 36 changed files with 279 additions and 144 deletions.
58 changes: 55 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- **Permission** - enumeration with primary types of device permissions
- **PermissionsController** - handler for runtime permission requests can be used in the common code with lifecycle safety for Android
- **DeniedException** and **DeniedAlwaysException** - exceptions to handle user denial of permissions
- **Compose Multiplatform** support

## Requirements
- Gradle version 6.8+
Expand All @@ -38,9 +39,12 @@ allprojects {
project **build.gradle**
```groovy
dependencies {
commonMainApi("dev.icerock.moko:permissions:0.14.0")
androidMainApi("dev.icerock.moko:permissions-compose:0.14.0") // permissions api + compose extensions
commonTestImplementation("dev.icerock.moko:permissions-test:0.14.0")
commonMainApi("dev.icerock.moko:permissions:0.15.0")
// compose multiplatform
commonMainApi("dev.icerock.moko:permissions-compose:0.15.0") // permissions api + compose extensions
commonTestImplementation("dev.icerock.moko:permissions-test:0.15.0")
}
```

Expand Down Expand Up @@ -116,6 +120,54 @@ iOS:
let viewModel = ViewModel(permissionsController: PermissionsController())
```

### Compose Multiplatform
```kotlin
@Composable
fun Sample() {
val factory: PermissionsControllerFactory = rememberPermissionsControllerFactory()
val controller: PermissionsController = remember(factory) { factory.createPermissionsController() }
val coroutineScope: CoroutineScope = rememberCoroutineScope()

Button(
onClick = {
coroutineScope.launch {
controller.providePermission(Permission.REMOTE_NOTIFICATION)
}
}
) {
Text(text = "give permissions")
}
}
```

Or with `moko-mvvm` with correct configuration change handle on android:
```kotlin
@Composable
fun Sample() {
val factory: PermissionsControllerFactory = rememberPermissionsControllerFactory()
val viewModel: PermissionsViewModel = getViewModel(
key = "permissions-screen",
factory = viewModelFactory { PermissionsViewModel(factory.createPermissionsController()) }
)

BindEffect(viewModel.permissionsController)

Button(onClick = viewModel::onButtonClick) {
Text(text = "give permissions")
}
}

class PermissionsViewModel(
val permissionsController: PermissionsController
) : ViewModel() {
fun onButtonClick() {
viewModelScope.launch {
permissionsController.providePermission(Permission.REMOTE_NOTIFICATION)
}
}
}
```

## Samples
More examples can be found in the [sample directory](sample).

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ buildscript {
dependencies {
classpath(libs.kotlinGradlePlugin)
classpath(libs.androidGradlePlugin)
classpath(libs.googleServicesGradlePlugin)
classpath(libs.mokoGradlePlugin)
classpath(libs.mobileMultiplatformGradlePlugin)
classpath(libs.kotlinSerializationGradlePlugin)
classpath(libs.composeJetBrainsGradlePlugin)
classpath(libs.detektGradlePlugin)
}
}

Expand Down
5 changes: 2 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ org.gradle.configureondemand=false
org.gradle.parallel=true

kotlin.code.style=official
kotlin.native.enableDependencyPropagation=false
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.mpp.enableCompatibilityMetadataVariant=true

kotlin.mpp.androidSourceSetLayoutVersion=2

android.useAndroidX=true

Expand Down
32 changes: 15 additions & 17 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
[versions]
kotlinVersion = "1.6.10"
androidAppCompatVersion = "1.2.0"
composeCompilerVersion = "1.1.1"
composeMaterialVersion = "1.3.1"
composeActivityVersion = "1.6.1"
materialDesignVersion = "1.0.0"
androidLifecycleVersion = "2.1.0"
androidCoreTestingVersion = "2.1.0"
coroutinesVersion = "1.6.0-native-mt"
mokoMvvmVersion = "0.12.0"
mokoPermissionsVersion = "0.14.0"
composeJetBrainsVersion = "1.1.1"
lifecycleRuntime = "2.5.1"
kotlinVersion = "1.8.10"
androidAppCompatVersion = "1.6.1"
composeMaterialVersion = "1.4.1"
composeActivityVersion = "1.7.0"
materialDesignVersion = "1.8.0"
androidLifecycleVersion = "2.2.0"
androidCoreTestingVersion = "2.2.0"
coroutinesVersion = "1.6.4"
mokoMvvmVersion = "0.16.0"
mokoPermissionsVersion = "0.15.0"
composeJetBrainsVersion = "1.3.1"
lifecycleRuntime = "2.6.1"

[libraries]
appCompat = { module = "androidx.appcompat:appcompat", version.ref = "androidAppCompatVersion" }
Expand All @@ -28,10 +27,9 @@ androidCoreTesting = { module = "androidx.arch.core:core-testing", version.ref =


kotlinGradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlinVersion" }
androidGradlePlugin = { module = "com.android.tools.build:gradle", version = "7.0.4" }
googleServicesGradlePlugin = { module = "com.google.gms:google-services", version = "4.3.8" }
firebaseGradlePlugin = { module = "com.google.firebase:firebase-crashlytics-gradle", version = "2.2.0" }
androidGradlePlugin = { module = "com.android.tools.build:gradle", version = "7.4.2" }
mokoGradlePlugin = { module = "dev.icerock.moko:moko-gradle-plugin", version = "0.2.0" }
mobileMultiplatformGradlePlugin = { module = "dev.icerock:mobile-multiplatform", version = "0.14.1" }
mobileMultiplatformGradlePlugin = { module = "dev.icerock:mobile-multiplatform", version = "0.14.2" }
kotlinSerializationGradlePlugin = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlinVersion" }
composeJetBrainsGradlePlugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "composeJetBrainsVersion" }
detektGradlePlugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version = "1.22.0" }
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
21 changes: 15 additions & 6 deletions permissions-compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@
*/

plugins {
id("dev.icerock.moko.gradle.android.library")
id("dev.icerock.moko.gradle.android.publication")
id("dev.icerock.moko.gradle.multiplatform.mobile")
id("dev.icerock.moko.gradle.publication")
id("dev.icerock.moko.gradle.stub.javadoc")
id("dev.icerock.moko.gradle.detekt")
id("org.jetbrains.compose")
}

android {
namespace = "dev.icerock.moko.permissions.compose"

defaultConfig {
minSdk = 21
}
}

dependencies {
api(projects.permissions)
api(compose.runtime)
api(libs.appCompat)
api(libs.composeActivity)
commonMainApi(projects.permissions)
commonMainApi(compose.runtime)

androidMainImplementation(libs.appCompat)
androidMainImplementation(libs.composeActivity)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,25 @@

package dev.icerock.moko.permissions.compose

import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner
import dev.icerock.moko.permissions.PermissionsController

@Suppress("FunctionNaming")
@Composable
fun BindEffect(permissionsController: PermissionsController) {
val lifecycleOwner = LocalLifecycleOwner.current
val fragmentManager = (LocalContext.current as FragmentActivity).supportFragmentManager
actual fun BindEffect(permissionsController: PermissionsController) {
val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
val context: Context = LocalContext.current

LaunchedEffect(permissionsController, lifecycleOwner, context) {
val fragmentManager: FragmentManager = (context as FragmentActivity).supportFragmentManager

LaunchedEffect(true) {
permissionsController.bind(lifecycleOwner.lifecycle, fragmentManager)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.permissions.compose

import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import dev.icerock.moko.permissions.PermissionsController

@Composable
actual fun rememberPermissionsControllerFactory(): PermissionsControllerFactory {
val context: Context = LocalContext.current
return remember(context) {
PermissionsControllerFactory {
PermissionsController(applicationContext = context.applicationContext)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.permissions.compose

import androidx.compose.runtime.Composable
import dev.icerock.moko.permissions.PermissionsController

@Suppress("FunctionNaming")
@Composable
expect fun BindEffect(permissionsController: PermissionsController)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.permissions.compose

import androidx.compose.runtime.Composable
import dev.icerock.moko.permissions.PermissionsController

fun interface PermissionsControllerFactory {
fun createPermissionsController(): PermissionsController
}

@Composable
expect fun rememberPermissionsControllerFactory(): PermissionsControllerFactory
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.permissions.compose

import androidx.compose.runtime.Composable
import dev.icerock.moko.permissions.PermissionsController

// on iOS side we should not do anything to prepare PermissionsController to work
@Suppress("FunctionNaming")
@Composable
actual fun BindEffect(permissionsController: PermissionsController) = Unit
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.permissions.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember

@Composable
actual fun rememberPermissionsControllerFactory(): PermissionsControllerFactory {
return remember {
PermissionsControllerFactory {
dev.icerock.moko.permissions.ios.PermissionsController()
}
}
}
2 changes: 0 additions & 2 deletions permissions-compose/src/main/AndroidManifest.xml

This file was deleted.

5 changes: 4 additions & 1 deletion permissions-test/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
plugins {
id("org.jetbrains.kotlin.multiplatform")
id("dev.icerock.moko.gradle.multiplatform.mobile")
id("dev.icerock.mobile.multiplatform.android-manifest")
id("dev.icerock.moko.gradle.publication")
id("dev.icerock.moko.gradle.stub.javadoc")
id("dev.icerock.moko.gradle.detekt")
}

android {
namespace = "dev.icerock.moko.permissions.test"
}

dependencies {
commonMainImplementation(libs.coroutines)

Expand Down
2 changes: 0 additions & 2 deletions permissions-test/src/androidMain/AndroidManifest.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import dev.icerock.moko.permissions.PermissionsController
actual abstract class PermissionsControllerMock : PermissionsController {
actual abstract override suspend fun providePermission(permission: Permission)

actual abstract override fun isPermissionGranted(permission: Permission): Boolean
actual abstract override suspend fun isPermissionGranted(permission: Permission): Boolean

override fun bind(
lifecycle: androidx.lifecycle.Lifecycle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import dev.icerock.moko.permissions.PermissionsController
expect abstract class PermissionsControllerMock constructor() : PermissionsController {
abstract override suspend fun providePermission(permission: Permission)

abstract override fun isPermissionGranted(permission: Permission): Boolean
abstract override suspend fun isPermissionGranted(permission: Permission): Boolean

companion object
}
Expand All @@ -33,7 +33,7 @@ fun createPermissionControllerMock(
throw DeniedException(permission, "mock block permission")
}

override fun isPermissionGranted(permission: Permission): Boolean {
override suspend fun isPermissionGranted(permission: Permission): Boolean {
return this.granted.contains(permission)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import dev.icerock.moko.permissions.PermissionsController
actual abstract class PermissionsControllerMock : PermissionsController {
actual abstract override suspend fun providePermission(permission: Permission)

actual abstract override fun isPermissionGranted(permission: Permission): Boolean
actual abstract override suspend fun isPermissionGranted(permission: Permission): Boolean

actual companion object
}
5 changes: 4 additions & 1 deletion permissions/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ plugins {
id("dev.icerock.moko.gradle.publication")
id("dev.icerock.moko.gradle.stub.javadoc")
id("dev.icerock.moko.gradle.detekt")
id("dev.icerock.mobile.multiplatform.android-manifest")
}

android {
namespace = "dev.icerock.moko.permissions"
}

dependencies {
Expand Down
2 changes: 0 additions & 2 deletions permissions/src/androidMain/AndroidManifest.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import androidx.lifecycle.Lifecycle

actual interface PermissionsController {
actual suspend fun providePermission(permission: Permission)
actual fun isPermissionGranted(permission: Permission): Boolean
actual suspend fun isPermissionGranted(permission: Permission): Boolean
actual suspend fun getPermissionState(permission: Permission): PermissionState
actual fun openAppSettings()

Expand Down
Loading

0 comments on commit bbadb95

Please sign in to comment.