mirror of
https://github.com/Tencent/QMUI_Android.git
synced 2026-10-29 03:26:44 +08:00
feat: compose init and modal and flipper.
This commit is contained in:
+2
-2
@@ -7,8 +7,8 @@ buildscript {
|
||||
mavenLocal()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:7.0.3")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31")
|
||||
classpath("com.android.tools.build:gradle:7.0.4")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,79 @@
|
||||
import com.qmuiteam.plugin.Dep
|
||||
import java.io.FileInputStream
|
||||
import java.util.*
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
|
||||
android {
|
||||
compileSdk = Dep.compileSdk
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdk = Dep.minSdk
|
||||
targetSdk = Dep.targetSdk
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
getByName("release"){
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = Dep.javaVersion
|
||||
targetCompatibility = Dep.javaVersion
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = Dep.kotlinJvmTarget
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = Dep.Compose.version
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(Dep.AndroidX.annotation)
|
||||
api(Dep.AndroidX.appcompat)
|
||||
api(Dep.AndroidX.coreKtx)
|
||||
api(Dep.Compose.ui)
|
||||
api(Dep.Compose.animation)
|
||||
api(Dep.Compose.material)
|
||||
api(Dep.Compose.compiler)
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
val file = rootProject.file("gradle/deploy.properties")
|
||||
if(file.exists()) {
|
||||
val properties = Properties()
|
||||
properties.load(FileInputStream(file))
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("release") {
|
||||
from(components.getByName("release"))
|
||||
groupId = Dep.QMUI.group
|
||||
artifactId = project.name
|
||||
version = Dep.QMUI.composeVer
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
setUrl(properties.getProperty("maven.url"))
|
||||
credentials {
|
||||
username = properties.getProperty("maven.username")
|
||||
password = properties.getProperty("maven.password")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.qmuiteam.compose
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.qmuiteam.compose", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.qmuiteam.compose">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.qmuiteam.compose.modal
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.OnBackPressedDispatcher
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.AnimatedVisibilityScope
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.core.view.isVisible
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
internal abstract class QMUIModalPresent(
|
||||
private val rootLayout: FrameLayout,
|
||||
private val onBackPressedDispatcher: OnBackPressedDispatcher,
|
||||
val mask: Color = DefaultMaskColor,
|
||||
val systemCancellable: Boolean = true,
|
||||
val maskCancellable: Boolean = true
|
||||
) : QMUIModal {
|
||||
|
||||
private val onShowListeners = arrayListOf<QMUIModal.Action>()
|
||||
private val onDismissListeners = arrayListOf<QMUIModal.Action>()
|
||||
private val visibleFlow = MutableStateFlow(false)
|
||||
private var isShown = false
|
||||
private var isDismissing = false
|
||||
|
||||
private val composeLayout = ComposeView(rootLayout.context).apply {
|
||||
visibility = View.GONE
|
||||
}
|
||||
|
||||
private val onBackPressedCallback = object : OnBackPressedCallback(systemCancellable) {
|
||||
override fun handleOnBackPressed() {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
composeLayout.setContent {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
val visible by visibleFlow.collectAsState(initial = false)
|
||||
ModalContent(visible = visible) {
|
||||
if (isDismissing) {
|
||||
doAfterDismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doAfterDismiss() {
|
||||
isDismissing = false
|
||||
composeLayout.isVisible = false
|
||||
composeLayout.disposeComposition()
|
||||
rootLayout.removeView(composeLayout)
|
||||
onBackPressedCallback.remove()
|
||||
}
|
||||
|
||||
@Composable
|
||||
abstract fun ModalContent(visible: Boolean, dismissFinishAction: () -> Unit)
|
||||
|
||||
override fun isShowing(): Boolean {
|
||||
return isShown
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
if (isShown || isDismissing) {
|
||||
return
|
||||
}
|
||||
isShown = true
|
||||
rootLayout.addView(composeLayout, generateLayoutParams())
|
||||
composeLayout.visibility = View.VISIBLE
|
||||
visibleFlow.value = true
|
||||
onBackPressedDispatcher.addCallback(onBackPressedCallback)
|
||||
}
|
||||
|
||||
open fun generateLayoutParams(): FrameLayout.LayoutParams {
|
||||
return FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
if (!isShown) {
|
||||
return
|
||||
}
|
||||
isShown = false
|
||||
isDismissing = true
|
||||
visibleFlow.value = false
|
||||
}
|
||||
|
||||
override fun doOnShow(listener: QMUIModal.Action) {
|
||||
onShowListeners.add(listener)
|
||||
}
|
||||
|
||||
override fun doOnDismiss(listener: QMUIModal.Action) {
|
||||
onDismissListeners.add(listener)
|
||||
}
|
||||
|
||||
override fun removeOnShowAction(listener: QMUIModal.Action) {
|
||||
onShowListeners.remove(listener)
|
||||
}
|
||||
|
||||
override fun removeOnDismissAction(listener: QMUIModal.Action) {
|
||||
onDismissListeners.remove(listener)
|
||||
}
|
||||
}
|
||||
|
||||
internal class StillModalImpl(
|
||||
rootLayout: FrameLayout,
|
||||
onBackPressedDispatcher: OnBackPressedDispatcher,
|
||||
mask: Color = DefaultMaskColor,
|
||||
systemCancellable: Boolean = true,
|
||||
maskCancellable: Boolean = true,
|
||||
val content: @Composable (modal: QMUIModal) -> Unit
|
||||
) : QMUIModalPresent(rootLayout, onBackPressedDispatcher, mask, systemCancellable, maskCancellable) {
|
||||
|
||||
@Composable
|
||||
override fun ModalContent(visible: Boolean, dismissFinishAction: () -> Unit) {
|
||||
if (visible) {
|
||||
var modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(mask)
|
||||
if (maskCancellable) {
|
||||
modifier = modifier.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null
|
||||
) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
Box(modifier = modifier)
|
||||
} else {
|
||||
dismissFinishAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class AnimateModalImpl(
|
||||
rootLayout: FrameLayout,
|
||||
onBackPressedDispatcher: OnBackPressedDispatcher,
|
||||
mask: Color = DefaultMaskColor,
|
||||
systemCancellable: Boolean = true,
|
||||
maskCancellable: Boolean = true,
|
||||
val content: @Composable AnimatedVisibilityScope.(modal: QMUIModal) -> Unit
|
||||
) : QMUIModalPresent(rootLayout, onBackPressedDispatcher, mask, systemCancellable, maskCancellable) {
|
||||
|
||||
@Composable
|
||||
override fun ModalContent(visible: Boolean, dismissFinishAction: () -> Unit) {
|
||||
AnimatedVisibility(
|
||||
visible = visible,
|
||||
enter = fadeIn(tween(300), 0f),
|
||||
exit = fadeOut(tween(300), 0f)
|
||||
) {
|
||||
var modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(mask)
|
||||
if (maskCancellable) {
|
||||
modifier = modifier.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null
|
||||
) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
Box(modifier = modifier)
|
||||
content(this@AnimateModalImpl)
|
||||
DisposableEffect("") {
|
||||
onDispose {
|
||||
dismissFinishAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.qmuiteam.compose.modal
|
||||
|
||||
import android.view.View
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
val DefaultDialogPaddingHor = 20.dp
|
||||
|
||||
@Composable
|
||||
fun QMUIDialog(
|
||||
modal: QMUIModal,
|
||||
horEdge: Dp = 20.dp,
|
||||
verEdge: Dp = 20.dp,
|
||||
widthLimit: Dp = 360.dp,
|
||||
radius: Dp = 12.dp,
|
||||
background: Color = Color.White,
|
||||
content: @Composable (QMUIModal) -> Unit
|
||||
) {
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = horEdge, vertical = verEdge),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
var modifier = if (widthLimit < maxWidth) {
|
||||
Modifier.width(widthLimit)
|
||||
} else {
|
||||
Modifier.fillMaxWidth()
|
||||
}
|
||||
if (radius > 0.dp) {
|
||||
modifier = modifier.clip(RoundedCornerShape(radius))
|
||||
}
|
||||
modifier = modifier
|
||||
.background(background)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null
|
||||
) { }
|
||||
Box(modifier = modifier) {
|
||||
content(modal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun QMUIDialogTitle(
|
||||
text: String,
|
||||
fontSize: TextUnit = 15.sp,
|
||||
textAlign: TextAlign? = null,
|
||||
color: Color = Color.Black,
|
||||
fontWeight: FontWeight? = FontWeight.Bold,
|
||||
fontFamily: FontFamily? = null,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
lineHeight: TextUnit = 20.sp,
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
top = 24.dp,
|
||||
start = DefaultDialogPaddingHor,
|
||||
end = DefaultDialogPaddingHor,
|
||||
),
|
||||
textAlign = textAlign,
|
||||
color = color,
|
||||
fontSize = fontSize,
|
||||
fontWeight = fontWeight,
|
||||
fontFamily = fontFamily,
|
||||
maxLines = maxLines,
|
||||
lineHeight = lineHeight
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun QMUIDialogMessageContent(
|
||||
text: String,
|
||||
fontSize: TextUnit = 14.sp,
|
||||
textAlign: TextAlign? = null,
|
||||
color: Color = Color.Black,
|
||||
fontWeight: FontWeight? = FontWeight.Bold,
|
||||
fontFamily: FontFamily? = null,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
lineHeight: TextUnit = 16.sp,
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = DefaultDialogPaddingHor,
|
||||
end = DefaultDialogPaddingHor,
|
||||
top = 16.dp,
|
||||
bottom = 24.dp
|
||||
),
|
||||
textAlign = textAlign,
|
||||
color = color,
|
||||
fontSize = fontSize,
|
||||
fontWeight = fontWeight,
|
||||
fontFamily = fontFamily,
|
||||
maxLines = maxLines,
|
||||
lineHeight = lineHeight
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun View.qmuiDialog(
|
||||
mask: Color = DefaultMaskColor,
|
||||
systemCancellable: Boolean = true,
|
||||
maskCancellable: Boolean = true,
|
||||
modalHostProvider: ModalHostProvider = DefaultModalHostProvider,
|
||||
horEdge: Dp = 20.dp,
|
||||
verEdge: Dp = 20.dp,
|
||||
widthLimit: Dp = 360.dp,
|
||||
radius: Dp = 12.dp,
|
||||
background: Color = Color.White,
|
||||
content: @Composable (QMUIModal) -> Unit
|
||||
): QMUIModal {
|
||||
return qmuiModal(mask, systemCancellable, maskCancellable, modalHostProvider) { modal ->
|
||||
QMUIDialog(modal, horEdge, verEdge, widthLimit, radius, background, content)
|
||||
}
|
||||
}
|
||||
|
||||
fun View.qmuiStillDialog(
|
||||
mask: Color = DefaultMaskColor,
|
||||
systemCancellable: Boolean = true,
|
||||
maskCancellable: Boolean = true,
|
||||
modalHostProvider: ModalHostProvider = DefaultModalHostProvider,
|
||||
horEdge: Dp = 20.dp,
|
||||
verEdge: Dp = 20.dp,
|
||||
widthLimit: Dp = 360.dp,
|
||||
radius: Dp = 12.dp,
|
||||
background: Color = Color.White,
|
||||
content: @Composable (QMUIModal) -> Unit
|
||||
): QMUIModal {
|
||||
return qmuiStillModal(mask, systemCancellable, maskCancellable, modalHostProvider) { modal ->
|
||||
QMUIDialog(modal, horEdge, verEdge, widthLimit, radius, background, content)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.qmuiteam.compose.modal
|
||||
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.OnBackPressedDispatcher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.animation.AnimatedVisibilityScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.DisposableEffectResult
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
|
||||
val DefaultMaskColor = Color.Black.copy(alpha = 0.5f)
|
||||
|
||||
private class ModalHolder(var current: QMUIModal? = null)
|
||||
|
||||
@Composable
|
||||
fun QMUIModal(
|
||||
isVisible: Boolean,
|
||||
mask: Color = DefaultMaskColor,
|
||||
systemCancellable: Boolean = true,
|
||||
maskCancellable: Boolean = true,
|
||||
doOnShow: QMUIModal.Action? = null,
|
||||
doOnDismiss: QMUIModal.Action? = null,
|
||||
modalHostProvider: ModalHostProvider = DefaultModalHostProvider,
|
||||
content: @Composable AnimatedVisibilityScope.(QMUIModal) -> Unit
|
||||
) {
|
||||
val modalHolder = remember {
|
||||
ModalHolder(null)
|
||||
}
|
||||
if (isVisible) {
|
||||
if (modalHolder.current == null) {
|
||||
val modal = LocalView.current.qmuiModal(mask, systemCancellable, maskCancellable, modalHostProvider, content)
|
||||
doOnShow?.let { modal.doOnShow(it) }
|
||||
doOnDismiss?.let { modal.doOnDismiss(it) }
|
||||
modalHolder.current = modal
|
||||
}
|
||||
} else {
|
||||
modalHolder.current?.dismiss()
|
||||
}
|
||||
DisposableEffect("") {
|
||||
object : DisposableEffectResult {
|
||||
override fun dispose() {
|
||||
modalHolder.current?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface QMUIModal {
|
||||
fun show()
|
||||
fun dismiss()
|
||||
fun isShowing(): Boolean
|
||||
|
||||
fun doOnShow(listener: Action)
|
||||
fun doOnDismiss(listener: Action)
|
||||
fun removeOnShowAction(listener: Action)
|
||||
fun removeOnDismissAction(listener: Action)
|
||||
|
||||
fun interface Action {
|
||||
fun invoke(modal: QMUIModal)
|
||||
}
|
||||
}
|
||||
|
||||
fun interface ModalHostProvider {
|
||||
fun provide(view: View): Pair<FrameLayout, OnBackPressedDispatcher>
|
||||
}
|
||||
|
||||
class ActivityHostModalProvider : ModalHostProvider {
|
||||
override fun provide(view: View): Pair<FrameLayout, OnBackPressedDispatcher> {
|
||||
val contentLayout =
|
||||
view.rootView.findViewById<FrameLayout>(Window.ID_ANDROID_CONTENT) ?: throw RuntimeException("View is not attached to Activity")
|
||||
val activity = contentLayout.context as? AppCompatActivity ?: throw RuntimeException("view's rootView's context is not AppCompatActivity")
|
||||
return contentLayout to activity.onBackPressedDispatcher
|
||||
}
|
||||
}
|
||||
|
||||
val DefaultModalHostProvider = ActivityHostModalProvider()
|
||||
|
||||
fun View.qmuiModal(
|
||||
mask: Color = DefaultMaskColor,
|
||||
systemCancellable: Boolean = true,
|
||||
maskCancellable: Boolean = true,
|
||||
modalHostProvider: ModalHostProvider = DefaultModalHostProvider,
|
||||
content: @Composable AnimatedVisibilityScope.(QMUIModal) -> Unit
|
||||
): QMUIModal {
|
||||
if (!isAttachedToWindow) {
|
||||
throw RuntimeException("View is not attached to window")
|
||||
}
|
||||
val modalHost = modalHostProvider.provide(this)
|
||||
return AnimateModalImpl(modalHost.first, modalHost.second, mask, systemCancellable, maskCancellable, content)
|
||||
}
|
||||
|
||||
fun View.qmuiStillModal(
|
||||
mask: Color = DefaultMaskColor,
|
||||
systemCancellable: Boolean = true,
|
||||
maskCancellable: Boolean = true,
|
||||
modalHostProvider: ModalHostProvider = DefaultModalHostProvider,
|
||||
content: @Composable (QMUIModal) -> Unit
|
||||
): QMUIModal {
|
||||
if (!isAttachedToWindow) {
|
||||
throw RuntimeException("View is not attached to window")
|
||||
}
|
||||
val modalHost = modalHostProvider.provide(this)
|
||||
return StillModalImpl(modalHost.first, modalHost.second, mask, systemCancellable, maskCancellable, content)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.qmuiteam.compose
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
`java-gradle-plugin`
|
||||
idea
|
||||
kotlin("jvm") version "1.5.31"
|
||||
kotlin("jvm") version "1.6.0"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ object Dep {
|
||||
|
||||
val javaVersion = JavaVersion.VERSION_11
|
||||
const val kotlinJvmTarget = "11"
|
||||
const val kotlinVer = "1.5.31"
|
||||
const val compileSdk = 31
|
||||
const val minSdk = 21
|
||||
const val targetSdk = 31
|
||||
@@ -17,6 +16,7 @@ object Dep {
|
||||
const val qmuiVer = "2.0.1"
|
||||
const val archVer = "2.0.1"
|
||||
const val typeVer = "0.0.14"
|
||||
const val composeVer = "0.0.1"
|
||||
}
|
||||
|
||||
object AndroidX {
|
||||
@@ -28,6 +28,20 @@ object Dep {
|
||||
val fragment = "androidx.fragment:fragment:1.4.0"
|
||||
}
|
||||
|
||||
object Compose {
|
||||
val version = "1.1.0-rc01"
|
||||
val animation = "androidx.compose.animation:animation:$version"
|
||||
val ui = "androidx.compose.ui:ui:$version"
|
||||
val material = "androidx.compose.material:material:$version"
|
||||
val compiler = "androidx.compose.compiler:compiler:$version"
|
||||
}
|
||||
|
||||
object Flipper {
|
||||
private const val version = "0.96.1"
|
||||
const val soLoader = "com.facebook.soloader:soloader:0.10.1"
|
||||
const val flipper = "com.facebook.flipper:flipper:$version"
|
||||
}
|
||||
|
||||
object MaterialDesign {
|
||||
const val material = "com.google.android.material:material:1.4.0"
|
||||
}
|
||||
|
||||
@@ -43,6 +43,14 @@ android {
|
||||
targetCompatibility = Dep.javaVersion
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = Dep.Compose.version
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.qmuiteam.qmuidemo"
|
||||
minSdk = Dep.minSdk
|
||||
@@ -70,6 +78,9 @@ dependencies {
|
||||
implementation(project(":qmui"))
|
||||
implementation(project(":arch"))
|
||||
implementation(project(":type"))
|
||||
implementation(project(":compose"))
|
||||
implementation(Dep.Flipper.soLoader)
|
||||
implementation(Dep.Flipper.flipper)
|
||||
kapt(project(":compiler"))
|
||||
kapt(project(":arch-compiler"))
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.flipper.android.AndroidFlipperClient;
|
||||
import com.facebook.flipper.core.FlipperClient;
|
||||
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
|
||||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import com.qmuiteam.qmui.QMUILog;
|
||||
import com.qmuiteam.qmui.arch.QMUISwipeBackActivityManager;
|
||||
import com.qmuiteam.qmui.qqface.QMUIQQFaceCompiler;
|
||||
@@ -78,6 +83,11 @@ public class QDApplication extends Application {
|
||||
QMUISwipeBackActivityManager.init(this);
|
||||
QMUIQQFaceCompiler.setDefaultQQFaceManager(QDQQFaceManager.getInstance());
|
||||
QDSkinManager.install(this);
|
||||
|
||||
SoLoader.init(this, false);
|
||||
FlipperClient client = AndroidFlipperClient.getInstance(this);
|
||||
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,8 +17,15 @@ package com.qmuiteam.qmuidemo.fragment.components
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.ui.Modifier
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import com.qmuiteam.compose.modal.QMUIDialogMessageContent
|
||||
import com.qmuiteam.compose.modal.QMUIDialogTitle
|
||||
import com.qmuiteam.compose.modal.qmuiDialog
|
||||
import com.qmuiteam.qmui.arch.annotation.LatestVisitRecord
|
||||
import com.qmuiteam.qmui.arch.effect.MapEffect
|
||||
import com.qmuiteam.qmui.kotlin.onClick
|
||||
import com.qmuiteam.qmui.kotlin.skin
|
||||
@@ -30,6 +37,7 @@ import com.qmuiteam.qmuidemo.lib.annotation.Widget
|
||||
import com.qmuiteam.qmuidemo.manager.QDDataManager
|
||||
import com.qmuiteam.qmuidemo.model.QDItemDescription
|
||||
|
||||
@LatestVisitRecord
|
||||
@Widget(name = "QMUIRoundButton", iconRes = R.mipmap.icon_grid_button)
|
||||
class QDButtonFragment : BaseFragment() {
|
||||
@BindView(R.id.topbar)
|
||||
@@ -56,6 +64,15 @@ class QDButtonFragment : BaseFragment() {
|
||||
|
||||
private fun initTopBar() {
|
||||
mTopBar.addLeftBackImageButton().onClick { popBackStack() }
|
||||
mTopBar.addRightTextButton("test", View.generateViewId()).onClick {
|
||||
it.qmuiDialog {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
QMUIDialogTitle(text = "这是标题")
|
||||
QMUIDialogMessageContent(text = "这是一点点有意思的内容")
|
||||
}
|
||||
|
||||
}.show()
|
||||
}
|
||||
mTopBar.setTitle(mQDItemDescription.name)
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ include(":arch")
|
||||
include(":arch-compiler")
|
||||
include(":arch-annotation")
|
||||
include(":type")
|
||||
include(":compose")
|
||||
|
||||
includeBuild("./plugin")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user