├── .github
└── workflows
│ └── deploy.yml
├── .gitignore
├── LICENSE
├── README.md
├── androidApp
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── d10ng
│ │ └── compose
│ │ └── android
│ │ └── demo
│ │ ├── MainActivity.kt
│ │ └── ui
│ │ └── theme
│ │ ├── Color.kt
│ │ ├── Theme.kt
│ │ └── Type.kt
│ └── res
│ ├── drawable
│ ├── ic_launcher_background.xml
│ └── ic_launcher_foreground.xml
│ ├── mipmap-anydpi
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-mdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── values
│ ├── colors.xml
│ ├── strings.xml
│ └── themes.xml
│ └── xml
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── build.gradle.kts
├── color.md
├── composeApp
├── build.gradle.kts
└── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── area_phone_code.json
│ ├── ic_launcher-playstore.png
│ ├── kotlin
│ │ └── com
│ │ │ └── d10ng
│ │ │ └── compose
│ │ │ └── demo
│ │ │ ├── App.android.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── pages
│ │ │ ├── ImagePreviewScreen.kt
│ │ │ └── IndexBarScreen.kt
│ │ │ └── stores
│ │ │ └── AreaStore.kt
│ └── res
│ │ ├── drawable
│ │ ├── ic_launcher_background.xml
│ │ └── ic_launcher_foreground.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ └── values
│ │ ├── ic_launcher_background.xml
│ │ └── strings.xml
│ ├── commonMain
│ ├── composeResources
│ │ ├── drawable
│ │ │ ├── apple.webp
│ │ │ ├── compose-multiplatform.xml
│ │ │ ├── ic_avatar_40.xml
│ │ │ ├── ic_command_center_avatar_40.xml
│ │ │ ├── ic_group_avatar_40.xml
│ │ │ ├── ic_launcher_foreground.xml
│ │ │ ├── round_add_circle_outline_24.xml
│ │ │ ├── round_cruelty_free_24.xml
│ │ │ └── round_mood_24.xml
│ │ └── font
│ │ │ ├── MiSans_Bold.ttf
│ │ │ ├── MiSans_Demibold.ttf
│ │ │ ├── MiSans_ExtraLight.ttf
│ │ │ ├── MiSans_Heavy.ttf
│ │ │ ├── MiSans_Light.ttf
│ │ │ ├── MiSans_Medium.ttf
│ │ │ ├── MiSans_Normal.ttf
│ │ │ ├── MiSans_Regular.ttf
│ │ │ ├── MiSans_Semibold.ttf
│ │ │ └── MiSans_Thin.ttf
│ └── kotlin
│ │ └── com
│ │ └── d10ng
│ │ └── compose
│ │ └── demo
│ │ ├── App.kt
│ │ ├── Nav.kt
│ │ └── pages
│ │ ├── AvatarScreen.kt
│ │ ├── BadgeScreen.kt
│ │ ├── ButtonScreen.kt
│ │ ├── CellScreen.kt
│ │ ├── CheckButtonScreen.kt
│ │ ├── CheckboxScreen.kt
│ │ ├── ColorScreen.kt
│ │ ├── DialogScreen.kt
│ │ ├── FieldScreen.kt
│ │ ├── HomeScreen.kt
│ │ ├── NavBarScreen.kt
│ │ ├── NotifyScreen.kt
│ │ ├── PopoverScreen.kt
│ │ ├── PullRefreshScreen.kt
│ │ ├── SearchScreen.kt
│ │ ├── ShapeScreen.kt
│ │ ├── SheetScreen.kt
│ │ ├── StepperScreen.kt
│ │ ├── StepsScreen.kt
│ │ ├── SwitchScreen.kt
│ │ ├── TagScreen.kt
│ │ ├── ToastScreen.kt
│ │ └── TypographyScreen.kt
│ ├── iosMain
│ └── kotlin
│ │ └── com
│ │ └── d10ng
│ │ └── compose
│ │ └── demo
│ │ ├── App.ios.kt
│ │ └── MainViewController.kt
│ └── wasmJsMain
│ ├── kotlin
│ └── com
│ │ └── d10ng
│ │ └── compose
│ │ ├── demo
│ │ └── App.wasmJs.kt
│ │ └── multiplatform
│ │ └── demo
│ │ └── main.kt
│ └── resources
│ ├── index.html
│ └── styles.css
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── iosApp
├── Configuration
│ └── Config.xcconfig
├── iosApp.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── iosApp
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ └── app-icon-1024.png
│ └── Contents.json
│ ├── ContentView.swift
│ ├── Info.plist
│ ├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
│ └── iOSApp.swift
├── kotlin-js-store
├── wasm
│ └── yarn.lock
└── yarn.lock
├── library
├── build.gradle.kts
└── src
│ ├── androidMain
│ └── kotlin
│ │ └── com
│ │ └── d10ng
│ │ └── compose
│ │ ├── ui
│ │ ├── navigation
│ │ │ └── IndexBar.kt
│ │ └── show
│ │ │ └── ImagePreview.kt
│ │ └── utils
│ │ └── BackHandlerUtils.android.kt
│ ├── commonMain
│ ├── composeResources
│ │ └── drawable
│ │ │ ├── ic_baseline_arrow_drop_down_24.xml
│ │ │ ├── ic_baseline_arrow_drop_up_24.xml
│ │ │ ├── ic_baseline_keyboard_arrow_right_24.xml
│ │ │ ├── ic_baseline_visibility_24.xml
│ │ │ ├── ic_baseline_visibility_off_24.xml
│ │ │ ├── ic_false_102.xml
│ │ │ ├── ic_round_add_24.xml
│ │ │ ├── ic_round_add_circle_24.xml
│ │ │ ├── ic_round_back_22.xml
│ │ │ ├── ic_round_cancel_24.xml
│ │ │ ├── ic_round_check_24.xml
│ │ │ ├── ic_round_error_160.xml
│ │ │ ├── ic_round_forward_16.xml
│ │ │ ├── ic_round_remove_24.xml
│ │ │ ├── ic_round_remove_circle_24.xml
│ │ │ ├── ic_round_search_22.xml
│ │ │ ├── ic_round_steps_active_20.xml
│ │ │ ├── ic_round_success_160.xml
│ │ │ └── ic_success_102.xml
│ └── kotlin
│ │ └── com
│ │ └── d10ng
│ │ └── compose
│ │ ├── model
│ │ ├── IUiViewModel.kt
│ │ ├── UiViewModel.kt
│ │ └── UiViewModelManager.kt
│ │ ├── ui
│ │ ├── Color.kt
│ │ ├── Modifier.kt
│ │ ├── Shape.kt
│ │ ├── Type.kt
│ │ ├── base
│ │ │ ├── Button.kt
│ │ │ ├── Cell.kt
│ │ │ └── Toast.kt
│ │ ├── dialog
│ │ │ ├── Dialog.kt
│ │ │ └── builder
│ │ │ │ ├── ConfirmDialogBuilder.kt
│ │ │ │ ├── DialogBuilder.kt
│ │ │ │ ├── InputDialogBuilder.kt
│ │ │ │ ├── ProgressDialogBuilder.kt
│ │ │ │ ├── ResultDialogBuilder.kt
│ │ │ │ └── TipsDialogBuilder.kt
│ │ ├── feedback
│ │ │ ├── Notify.kt
│ │ │ ├── Overlay.kt
│ │ │ └── PullRefresh.kt
│ │ ├── form
│ │ │ ├── CheckButton.kt
│ │ │ ├── Checkbox.kt
│ │ │ ├── DatePicker.kt
│ │ │ ├── Field.kt
│ │ │ ├── Picker.kt
│ │ │ ├── Radio.kt
│ │ │ ├── Search.kt
│ │ │ ├── Stepper.kt
│ │ │ ├── Switch.kt
│ │ │ └── TimePicker.kt
│ │ ├── navigation
│ │ │ └── NavBar.kt
│ │ ├── sheet
│ │ │ ├── Sheet.kt
│ │ │ └── builder
│ │ │ │ ├── ActionSheetBuilder.kt
│ │ │ │ ├── DatePickerSheetBuilder.kt
│ │ │ │ ├── MultiPickerSheetBuilder.kt
│ │ │ │ ├── RadioSheetBuilder.kt
│ │ │ │ ├── SheetBuilder.kt
│ │ │ │ ├── SinglePickerSheetBuilder.kt
│ │ │ │ └── TimePickerSheetBuilder.kt
│ │ └── show
│ │ │ ├── Avatar.kt
│ │ │ ├── BDSignalBeamBox.kt
│ │ │ ├── Badge.kt
│ │ │ ├── Divider.kt
│ │ │ ├── Popover.kt
│ │ │ ├── Steps.kt
│ │ │ └── Tag.kt
│ │ ├── utils
│ │ ├── BackHandlerUtils.kt
│ │ └── ColorUtils.kt
│ │ └── view
│ │ ├── Input.kt
│ │ └── ListItem.kt
│ ├── iosMain
│ └── kotlin
│ │ └── com
│ │ └── d10ng
│ │ └── compose
│ │ └── utils
│ │ └── BackHandlerUtils.ios.kt
│ └── wasmJsMain
│ └── kotlin
│ └── com
│ └── d10ng
│ └── compose
│ └── utils
│ └── BackHandlerUtils.wasmJs.kt
└── settings.gradle.kts
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy to GitHub Pages
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | workflow_dispatch:
7 |
8 | permissions:
9 | contents: read
10 | pages: write
11 | id-token: write
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - name: Set up JDK 17
20 | uses: actions/setup-java@v3
21 | with:
22 | java-version: '17'
23 | distribution: 'temurin'
24 |
25 | - name: Grant execute permission for gradlew
26 | run: chmod +x gradlew
27 |
28 | - name: Build WASM/JS
29 | run: ./gradlew -Pbds100MavenUsername=${{ secrets.BDS100MAVENUSERNAME }} -Pbds100MavenPassword=${{ secrets.BDS100MAVENPASSWORD }} :composeApp:wasmJsBrowserDistribution
30 |
31 | - name: Upload artifact
32 | uses: actions/upload-pages-artifact@v3
33 | with:
34 | path: composeApp/build/dist/wasmJs/productionExecutable
35 |
36 | deploy:
37 | environment:
38 | name: github-pages
39 | url: ${{ steps.deployment.outputs.page_url }}
40 | needs: build
41 | runs-on: ubuntu-latest
42 | steps:
43 | - name: Deploy to GitHub Pages
44 | id: deployment
45 | uses: actions/deploy-pages@v4
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .kotlin
3 | .gradle
4 | **/build/
5 | xcuserdata
6 | !src/**/build/
7 | local.properties
8 | .idea
9 | .DS_Store
10 | captures
11 | .externalNativeBuild
12 | .cxx
13 | *.xcodeproj/*
14 | !*.xcodeproj/project.pbxproj
15 | !*.xcodeproj/xcshareddata/
16 | !*.xcodeproj/project.xcworkspace/
17 | !*.xcworkspace/contents.xcworkspacedata
18 | **/xcshareddata/WorkspaceSettings.xcsettings
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 D10NG
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/androidApp/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/androidApp/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.android.application)
3 | alias(libs.plugins.kotlin.android)
4 | alias(libs.plugins.kotlin.compose)
5 | }
6 |
7 | android {
8 | namespace = "com.d10ng.compose.android.demo"
9 | compileSdk = libs.versions.android.compileSdk.get().toInt()
10 |
11 | defaultConfig {
12 | applicationId = "com.d10ng.compose.android.demo"
13 | minSdk = libs.versions.android.minSdk.get().toInt()
14 | targetSdk = libs.versions.android.targetSdk.get().toInt()
15 | versionCode = 1
16 | versionName = "1.0"
17 |
18 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
19 | }
20 |
21 | buildTypes {
22 | release {
23 | isMinifyEnabled = false
24 | proguardFiles(
25 | getDefaultProguardFile("proguard-android-optimize.txt"),
26 | "proguard-rules.pro"
27 | )
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility = JavaVersion.VERSION_11
32 | targetCompatibility = JavaVersion.VERSION_11
33 | }
34 | buildFeatures {
35 | compose = true
36 | }
37 | }
38 |
39 | dependencies {
40 |
41 | implementation(libs.androidx.core.ktx)
42 | implementation(libs.androidx.lifecycle.runtime.ktx)
43 | implementation(libs.androidx.activity.compose)
44 | implementation(platform(libs.androidx.compose.bom))
45 | implementation(libs.androidx.ui)
46 | implementation(libs.androidx.ui.graphics)
47 | implementation(libs.androidx.ui.tooling.preview)
48 | implementation(libs.androidx.material3)
49 | testImplementation(libs.junit)
50 | androidTestImplementation(libs.androidx.test.junit)
51 | androidTestImplementation(libs.androidx.test.espresso)
52 | androidTestImplementation(platform(libs.androidx.compose.bom))
53 | androidTestImplementation(libs.androidx.ui.test.junit4)
54 | debugImplementation(libs.androidx.ui.tooling)
55 | debugImplementation(libs.androidx.ui.test.manifest)
56 |
57 | implementation(project(":DLJetpackComposeUtil"))
58 | }
--------------------------------------------------------------------------------
/androidApp/proguard-rules.pro:
--------------------------------------------------------------------------------
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
--------------------------------------------------------------------------------
/androidApp/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/d10ng/compose/android/demo/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.android.demo.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val Purple80 = Color(0xFFD0BCFF)
6 | val PurpleGrey80 = Color(0xFFCCC2DC)
7 | val Pink80 = Color(0xFFEFB8C8)
8 |
9 | val Purple40 = Color(0xFF6650a4)
10 | val PurpleGrey40 = Color(0xFF625b71)
11 | val Pink40 = Color(0xFF7D5260)
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/d10ng/compose/android/demo/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.android.demo.ui.theme
2 |
3 | import android.os.Build
4 | import androidx.compose.foundation.isSystemInDarkTheme
5 | import androidx.compose.material3.MaterialTheme
6 | import androidx.compose.material3.darkColorScheme
7 | import androidx.compose.material3.dynamicDarkColorScheme
8 | import androidx.compose.material3.dynamicLightColorScheme
9 | import androidx.compose.material3.lightColorScheme
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.platform.LocalContext
12 |
13 | private val DarkColorScheme = darkColorScheme(
14 | // primary = Purple80,
15 | // secondary = PurpleGrey80,
16 | // tertiary = Pink80
17 | )
18 |
19 | private val LightColorScheme = lightColorScheme(
20 | // primary = Purple40,
21 | // secondary = PurpleGrey40,
22 | // tertiary = Pink40
23 |
24 | /* Other default colors to override
25 | background = Color(0xFFFFFBFE),
26 | surface = Color(0xFFFFFBFE),
27 | onPrimary = Color.White,
28 | onSecondary = Color.White,
29 | onTertiary = Color.White,
30 | onBackground = Color(0xFF1C1B1F),
31 | onSurface = Color(0xFF1C1B1F),
32 | */
33 | )
34 |
35 | @Composable
36 | fun ComposeDemoTheme(
37 | darkTheme: Boolean = isSystemInDarkTheme(),
38 | // Dynamic color is available on Android 12+
39 | dynamicColor: Boolean = true,
40 | content: @Composable () -> Unit
41 | ) {
42 | val colorScheme = when {
43 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
44 | val context = LocalContext.current
45 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
46 | }
47 |
48 | darkTheme -> DarkColorScheme
49 | else -> LightColorScheme
50 | }
51 |
52 | MaterialTheme(
53 | //colorScheme = colorScheme,
54 | //typography = Typography,
55 | content = content
56 | )
57 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/d10ng/compose/android/demo/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.android.demo.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | // Set of Material typography styles to start with
10 | val Typography = Typography(
11 | /*bodyLarge = TextStyle(
12 | fontFamily = FontFamily.Default,
13 | fontWeight = FontWeight.Normal,
14 | fontSize = 16.sp,
15 | lineHeight = 24.sp,
16 | letterSpacing = 0.5.sp
17 | )
18 | Other default text styles to override
19 | titleLarge = TextStyle(
20 | fontFamily = FontFamily.Default,
21 | fontWeight = FontWeight.Normal,
22 | fontSize = 22.sp,
23 | lineHeight = 28.sp,
24 | letterSpacing = 0.sp
25 | ),
26 | labelSmall = TextStyle(
27 | fontFamily = FontFamily.Default,
28 | fontWeight = FontWeight.Medium,
29 | fontSize = 11.sp,
30 | lineHeight = 16.sp,
31 | letterSpacing = 0.5.sp
32 | )
33 | */
34 | )
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-anydpi/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-anydpi/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidComposeDemo
3 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | alias(libs.plugins.android.application) apply false
4 | alias(libs.plugins.android.library) apply false
5 | alias(libs.plugins.compose) apply false
6 | alias(libs.plugins.kotlin.android) apply false
7 | alias(libs.plugins.kotlin.compose) apply false
8 | alias(libs.plugins.kotlin.multiplatform) apply false
9 | alias(libs.plugins.kotlin.serialization) apply false
10 | id("com.github.ben-manes.versions") version "0.52.0"
11 | }
12 |
13 | fun isNonStable(version: String): Boolean {
14 | val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase().contains(it) }
15 | val regex = "^[0-9,.v-]+(-r)?$".toRegex()
16 | val isStable = stableKeyword || regex.matches(version)
17 | return isStable.not()
18 | }
19 |
20 | tasks.withType {
21 | rejectVersionIf {
22 | isNonStable(candidate.version)
23 | }
24 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/com/d10ng/compose/demo/App.android.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo
2 |
3 | import androidx.compose.ui.text.font.FontFamily
4 |
5 | actual suspend fun loadCustomFontFamily(): FontFamily? {
6 | return null
7 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/com/d10ng/compose/demo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo
2 |
3 | import android.graphics.Color
4 | import android.os.Bundle
5 | import androidx.activity.ComponentActivity
6 | import androidx.activity.SystemBarStyle
7 | import androidx.activity.compose.setContent
8 | import androidx.activity.enableEdgeToEdge
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.tooling.preview.Preview
11 | import com.d10ng.app.view.lockScreenOrientation
12 |
13 | class MainActivity : ComponentActivity() {
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 |
17 | // 锁定屏幕方向
18 | lockScreenOrientation()
19 |
20 | setContent {
21 | enableEdgeToEdge(
22 | statusBarStyle = SystemBarStyle.light(
23 | Color.TRANSPARENT, Color.TRANSPARENT
24 | ),
25 | navigationBarStyle = SystemBarStyle.light(
26 | Color.TRANSPARENT, Color.TRANSPARENT
27 | )
28 | )
29 | App()
30 | }
31 | }
32 | }
33 |
34 | @Preview
35 | @Composable
36 | fun AppAndroidPreview() {
37 | App()
38 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/com/d10ng/compose/demo/pages/ImagePreviewScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.ExperimentalLayoutApi
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.foundation.layout.navigationBarsPadding
8 | import androidx.compose.foundation.rememberScrollState
9 | import androidx.compose.foundation.verticalScroll
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.runtime.getValue
12 | import androidx.compose.runtime.mutableStateOf
13 | import androidx.compose.runtime.remember
14 | import androidx.compose.runtime.rememberCoroutineScope
15 | import androidx.compose.runtime.setValue
16 | import androidx.compose.ui.Modifier
17 | import androidx.compose.ui.tooling.preview.Preview
18 | import com.d10ng.app.managers.PhotoManager
19 | import com.d10ng.compose.demo.Nav
20 | import com.d10ng.compose.ui.AppColor
21 | import com.d10ng.compose.ui.base.Button
22 | import com.d10ng.compose.ui.base.ButtonType
23 | import com.d10ng.compose.ui.base.CellTitle
24 | import com.d10ng.compose.ui.navigation.NavBar
25 | import com.d10ng.compose.ui.show.ImagePreview
26 | import kotlinx.coroutines.launch
27 |
28 | /**
29 | * 图片查看器
30 | * @Author d10ng
31 | * @Date 2023/11/28 16:29
32 | */
33 | @OptIn(ExperimentalLayoutApi::class)
34 | @Composable
35 | fun ImagePreviewScreen() {
36 | // 图片路径
37 | var imagePath by remember {
38 | mutableStateOf("")
39 | }
40 | Column(
41 | modifier = Modifier
42 | .fillMaxSize()
43 | .background(AppColor.Neutral.bg)
44 | .navigationBarsPadding()
45 | ) {
46 | NavBar(title = "ImagePreview", onClickBack = { Nav.instant().popBackStack() })
47 | Column(
48 | modifier = Modifier
49 | .fillMaxSize()
50 | .weight(1f)
51 | .verticalScroll(rememberScrollState())
52 | ) {
53 | CellTitle(title = "基础用法")
54 | CustomFlowRow {
55 | val scope = rememberCoroutineScope()
56 | Button(text = "选择图片", type = ButtonType.PRIMARY) {
57 | scope.launch {
58 | PhotoManager.pick()?.let {
59 | imagePath = it
60 | }
61 | }
62 | }
63 | }
64 | }
65 | }
66 | if (imagePath.isNotEmpty()) {
67 | ImagePreview(path = imagePath) {
68 | imagePath = ""
69 | }
70 | }
71 | }
72 |
73 | @Preview
74 | @Composable
75 | private fun ImagePreviewScreenPreview() {
76 | ImagePreviewScreen()
77 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/com/d10ng/compose/demo/pages/IndexBarScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.Row
7 | import androidx.compose.foundation.layout.fillMaxSize
8 | import androidx.compose.foundation.layout.fillMaxWidth
9 | import androidx.compose.foundation.layout.height
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.foundation.lazy.LazyColumn
12 | import androidx.compose.foundation.lazy.itemsIndexed
13 | import androidx.compose.foundation.lazy.rememberLazyListState
14 | import androidx.compose.material3.Text
15 | import androidx.compose.runtime.Composable
16 | import androidx.compose.runtime.remember
17 | import androidx.compose.runtime.rememberCoroutineScope
18 | import androidx.compose.ui.Alignment
19 | import androidx.compose.ui.Modifier
20 | import androidx.compose.ui.graphics.Color
21 | import androidx.compose.ui.tooling.preview.Preview
22 | import androidx.compose.ui.unit.dp
23 | import com.d10ng.compose.demo.stores.AreaStore
24 | import com.d10ng.compose.ui.AppColor
25 | import com.d10ng.compose.ui.AppText
26 | import com.d10ng.compose.ui.base.CellTitle
27 | import com.d10ng.compose.ui.navigation.IndexBar
28 | import com.d10ng.compose.ui.navigation.NavBar
29 | import kotlinx.coroutines.launch
30 |
31 | /**
32 | * IndexBar 索引栏
33 | * @Author d10ng
34 | * @Date 2023/9/18 10:50
35 | */
36 | @Composable
37 | private fun IndexBarScreen(
38 | onClickBack: () -> Unit = {},
39 | ) {
40 | val data = remember {
41 | AreaStore.list
42 | }
43 | val listState = rememberLazyListState()
44 | val scope = rememberCoroutineScope()
45 |
46 | Column(
47 | modifier = Modifier
48 | .fillMaxSize()
49 | .background(AppColor.Neutral.bg)
50 | ) {
51 | NavBar(title = "IndexBar", onClickBack = onClickBack)
52 | IndexBar(
53 | modifier = Modifier.fillMaxSize(),
54 | onSelect = { value ->
55 | val index = data.indexOfFirst { it.py[0].uppercase().contains(value, true) }
56 | if (index >= 0) {
57 | scope.launch { listState.scrollToItem(index) }
58 | }
59 | }
60 | ) {
61 | LazyColumn(
62 | modifier = Modifier.fillMaxSize(),
63 | state = listState
64 | ) {
65 | itemsIndexed(data, { i, _ -> i }) { index, item ->
66 | val isShowTag = if (index == 0) true else {
67 | val last = data[index - 1]
68 | last.py[0].uppercase() != item.py[0].uppercase()
69 | }
70 | ItemView(item, isShowTag)
71 | }
72 | }
73 | }
74 | }
75 | }
76 |
77 | @Composable
78 | private fun ItemView(
79 | value: AreaStore.Info,
80 | showTag: Boolean = false
81 | ) {
82 | Column(
83 | modifier = Modifier
84 | .fillMaxWidth()
85 | ) {
86 | if (showTag) CellTitle(title = value.py[0].uppercase())
87 | Row(
88 | modifier = Modifier
89 | .fillMaxWidth()
90 | .height(48.dp)
91 | .background(Color.White)
92 | .padding(horizontal = 16.dp),
93 | verticalAlignment = Alignment.CenterVertically
94 | ) {
95 | Text(
96 | text = value.zh,
97 | style = AppText.Normal.Title.default,
98 | modifier = Modifier.weight(1f)
99 | )
100 | Text(
101 | text = value.code.toString(),
102 | style = AppText.Normal.Body.small,
103 | modifier = Modifier
104 | .padding(end = 32.dp)
105 | .background(AppColor.Neutral.card)
106 | .padding(horizontal = 8.dp, vertical = 4.dp)
107 | )
108 | }
109 | Box(modifier = Modifier
110 | .padding(horizontal = 16.dp)
111 | .height(1.dp)
112 | .background(AppColor.Neutral.line))
113 | }
114 | }
115 |
116 | @Preview
117 | @Composable
118 | private fun IndexBarScreenPreview() {
119 | IndexBarScreen()
120 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/com/d10ng/compose/demo/stores/AreaStore.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.stores
2 |
3 | import com.d10ng.app.resource.getAssetsJSONArray
4 | import com.d10ng.common.transform.json
5 | import com.d10ng.common.transform.toPinYin
6 | import kotlinx.serialization.SerialName
7 | import kotlinx.serialization.Serializable
8 |
9 | /**
10 | * 国家或地区数据仓库
11 | * @Author d10ng
12 | * @Date 2023/9/18 10:57
13 | */
14 | object AreaStore {
15 |
16 | @Serializable
17 | data class Info(
18 | @SerialName("code")
19 | var code: Int = 0,
20 | @SerialName("en")
21 | var en: String = "",
22 | @SerialName("locale")
23 | var locale: String = "",
24 | @SerialName("tw")
25 | var tw: String = "",
26 | @SerialName("zh")
27 | var zh: String = "",
28 |
29 | // 拼音
30 | var py: String = ""
31 | )
32 |
33 | /** 国家或地区列表 */
34 | var list: List
35 |
36 | init {
37 | val jsonObj = getAssetsJSONArray("area_phone_code.json").toString()
38 | val ls: MutableList = json.decodeFromString(jsonObj)
39 | ls.forEach { item -> item.py = item.zh.toPinYin() }
40 | list = ls.sortedBy { it.py }
41 | }
42 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DLJetpackComposeUtil
3 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/apple.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/drawable/apple.webp
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/ic_avatar_40.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/ic_command_center_avatar_40.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
27 |
30 |
31 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/ic_group_avatar_40.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
27 |
30 |
33 |
34 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/round_add_circle_outline_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/round_cruelty_free_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/round_mood_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Bold.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Demibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Demibold.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_ExtraLight.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Heavy.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Heavy.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Light.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Medium.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Normal.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Normal.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Regular.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Semibold.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/MiSans_Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/composeApp/src/commonMain/composeResources/font/MiSans_Thin.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/Nav.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo
2 |
3 | import androidx.navigation.NavHostController
4 | import kotlinx.serialization.Serializable
5 |
6 | object Nav {
7 |
8 | @Serializable
9 | object HomeRoute
10 |
11 | @Serializable
12 | object ColorRoute
13 |
14 | @Serializable
15 | object TypographyRoute
16 |
17 | @Serializable
18 | object ShapeRoute
19 |
20 | @Serializable
21 | object ButtonRoute
22 |
23 | @Serializable
24 | object CellRoute
25 |
26 | @Serializable
27 | object ToastRoute
28 |
29 | @Serializable
30 | object CheckboxRoute
31 |
32 | @Serializable
33 | object FieldRoute
34 |
35 | @Serializable
36 | object SwitchRoute
37 |
38 | @Serializable
39 | object CheckButtonRoute
40 |
41 | @Serializable
42 | object StepperRoute
43 |
44 | @Serializable
45 | object SearchRoute
46 |
47 | @Serializable
48 | object DialogRoute
49 |
50 | @Serializable
51 | object SheetRoute
52 |
53 | @Serializable
54 | object NotifyRoute
55 |
56 | @Serializable
57 | object PullRefreshRoute
58 |
59 | @Serializable
60 | object TagRoute
61 |
62 | @Serializable
63 | object BadgeRoute
64 |
65 | @Serializable
66 | object AvatarRoute
67 |
68 | @Serializable
69 | object StepsRoute
70 |
71 | @Serializable
72 | object PopoverRoute
73 |
74 | @Serializable
75 | object NavBarRoute
76 |
77 | private var controller: NavHostController? = null
78 |
79 | fun init(navigator: NavHostController) {
80 | controller = navigator
81 | }
82 |
83 | fun instant(): NavHostController {
84 | while (controller == null) {
85 | // 等待初始化完成
86 | }
87 | return controller!!
88 | }
89 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/BadgeScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Arrangement
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.ExperimentalLayoutApi
8 | import androidx.compose.foundation.layout.FlowRow
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.fillMaxWidth
11 | import androidx.compose.foundation.layout.padding
12 | import androidx.compose.foundation.layout.size
13 | import androidx.compose.foundation.rememberScrollState
14 | import androidx.compose.foundation.verticalScroll
15 | import androidx.compose.runtime.Composable
16 | import androidx.compose.ui.Modifier
17 | import androidx.compose.ui.unit.dp
18 | import com.d10ng.compose.demo.Nav
19 | import com.d10ng.compose.ui.AppColor
20 | import com.d10ng.compose.ui.AppShape
21 | import com.d10ng.compose.ui.base.CellGroup
22 | import com.d10ng.compose.ui.navigation.NavBar
23 | import com.d10ng.compose.ui.show.Badge
24 | import com.d10ng.compose.ui.show.BadgeBox
25 |
26 | /**
27 | * 徽标
28 | * @Author d10ng
29 | * @Date 2023/9/12 13:36
30 | */
31 | @OptIn(ExperimentalLayoutApi::class)
32 | @Composable
33 | fun BadgeScreen() {
34 | Column(
35 | modifier = Modifier
36 | .fillMaxSize()
37 | .background(AppColor.Neutral.bg)
38 | ) {
39 | NavBar(title = "Badge", onClickBack = { Nav.instant().popBackStack() })
40 | Column(
41 | modifier = Modifier
42 | .fillMaxSize()
43 | .verticalScroll(rememberScrollState())
44 | ) {
45 | CellGroup(title = "基础用法") {
46 | FlowRow(
47 | modifier = Modifier
48 | .fillMaxWidth()
49 | .padding(horizontal = 19.dp, vertical = 12.dp),
50 | horizontalArrangement = Arrangement.Start
51 | ) {
52 | listOf("", "1", "5", "10", "HOT").forEach { item ->
53 | BadgeBox(badge = { Badge(item) }) {
54 | Box(
55 | modifier = Modifier
56 | .size(48.dp)
57 | .background(AppColor.Neutral.line, AppShape.RC.v8)
58 | )
59 | }
60 | }
61 | }
62 | }
63 | CellGroup(title = "最大值") {
64 | FlowRow(
65 | modifier = Modifier
66 | .fillMaxWidth()
67 | .padding(horizontal = 19.dp, vertical = 12.dp),
68 | horizontalArrangement = Arrangement.Start
69 | ) {
70 | listOf(10 to 9, 21 to 20, 100 to 99).forEach { item ->
71 | BadgeBox(badge = { Badge(item.first, item.second) }) {
72 | Box(
73 | modifier = Modifier
74 | .size(48.dp)
75 | .background(AppColor.Neutral.line, AppShape.RC.v8)
76 | )
77 | }
78 | }
79 | }
80 | }
81 | CellGroup(title = "自定义颜色") {
82 | FlowRow(
83 | modifier = Modifier
84 | .fillMaxWidth()
85 | .padding(horizontal = 19.dp, vertical = 12.dp),
86 | horizontalArrangement = Arrangement.Start
87 | ) {
88 | listOf("", "1", "5", "10", "HOT").forEach { item ->
89 | BadgeBox(badge = { Badge(item, AppColor.Main.primary) }) {
90 | Box(
91 | modifier = Modifier
92 | .size(48.dp)
93 | .background(AppColor.Neutral.line, AppShape.RC.v8)
94 | )
95 | }
96 | }
97 | }
98 | }
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/CellScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.layout.size
7 | import androidx.compose.foundation.rememberScrollState
8 | import androidx.compose.foundation.verticalScroll
9 | import androidx.compose.material.icons.Icons
10 | import androidx.compose.material.icons.filled.Favorite
11 | import androidx.compose.material.icons.filled.LocationOn
12 | import androidx.compose.material3.Icon
13 | import androidx.compose.runtime.Composable
14 | import androidx.compose.ui.Modifier
15 | import androidx.compose.ui.unit.dp
16 | import com.d10ng.compose.demo.Nav
17 | import com.d10ng.compose.model.UiViewModelManager
18 | import com.d10ng.compose.ui.AppColor
19 | import com.d10ng.compose.ui.base.Cell
20 | import com.d10ng.compose.ui.base.CellArrowDirection
21 | import com.d10ng.compose.ui.base.CellGroup
22 | import com.d10ng.compose.ui.navigation.NavBar
23 |
24 | /**
25 | * 单元格
26 | * @Author d10ng
27 | * @Date 2023/9/4 14:48
28 | */
29 | @Composable
30 | fun CellScreen() {
31 | Column(
32 | modifier = Modifier
33 | .fillMaxSize()
34 | .background(AppColor.Neutral.bg)
35 | ) {
36 | NavBar(title = "Cell", onClickBack = { Nav.instant().popBackStack() })
37 | Column(
38 | modifier = Modifier
39 | .fillMaxSize()
40 | .weight(1f)
41 | .verticalScroll(rememberScrollState())
42 | ) {
43 | CellGroup(
44 | title = "基础用法"
45 | ) {
46 | Cell(title = "单元格")
47 | Cell(title = "单元格", value = "内容")
48 | Cell(title = "单元格", value = "内容", label = "描述信息", border = false)
49 | }
50 | CellGroup(inset = true, title = "卡片风格") {
51 | Cell(title = "单元格", link = true)
52 | Cell(title = "单元格", value = "内容")
53 | Cell(title = "单元格", value = "内容", label = "描述信息", border = false)
54 | }
55 | CellGroup(title = "展示图标") {
56 | Cell(title = "单元格", value = "内容", icon = {
57 | Icon(
58 | Icons.Default.Favorite,
59 | contentDescription = "",
60 | modifier = Modifier.size(14.dp)
61 | )
62 | })
63 | Cell(
64 | title = "单元格",
65 | value = "内容",
66 | label = "描述信息",
67 | border = false,
68 | icon = {
69 | Icon(
70 | Icons.Default.LocationOn,
71 | contentDescription = "",
72 | modifier = Modifier.size(14.dp)
73 | )
74 | })
75 | }
76 | CellGroup(title = "展示箭头") {
77 | Cell(title = "单元格", link = true)
78 | Cell(title = "单元格", value = "内容", link = true)
79 | Cell(
80 | title = "单元格",
81 | value = "内容",
82 | link = true,
83 | arrowDirection = CellArrowDirection.DOWN
84 | )
85 | Cell(
86 | title = "单元格",
87 | value = "内容",
88 | label = "描述信息",
89 | border = false,
90 | link = true
91 | )
92 | }
93 | CellGroup(title = "点击效果") {
94 | Cell(title = "单元格", value = "内容", link = true, onClick = {
95 | UiViewModelManager.showToast("点击了单元格")
96 | })
97 | Cell(
98 | title = "单元格",
99 | value = "内容",
100 | link = true,
101 | label = "描述信息",
102 | border = false,
103 | onClick = {
104 | UiViewModelManager.showToast("点击了单元格")
105 | })
106 | }
107 | }
108 | }
109 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/CheckButtonScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.rememberScrollState
7 | import androidx.compose.foundation.verticalScroll
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.getValue
10 | import androidx.compose.runtime.mutableStateOf
11 | import androidx.compose.runtime.remember
12 | import androidx.compose.runtime.setValue
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.graphics.Color
15 | import com.d10ng.compose.demo.Nav
16 | import com.d10ng.compose.ui.AppColor
17 | import com.d10ng.compose.ui.base.CellGroup
18 | import com.d10ng.compose.ui.form.CheckButtonGroup
19 | import com.d10ng.compose.ui.form.CheckButtonMode
20 | import com.d10ng.compose.ui.navigation.NavBar
21 |
22 | /**
23 | * 选择按钮
24 | * @Author d10ng
25 | * @Date 2023/9/6 16:55
26 | */
27 | @Composable
28 | fun CheckButtonScreen() {
29 | Column(
30 | modifier = Modifier
31 | .fillMaxSize()
32 | .background(AppColor.Neutral.bg)
33 | ) {
34 | NavBar(title = "CheckButton", onClickBack = { Nav.instant().popBackStack() })
35 | Column(
36 | modifier = Modifier
37 | .fillMaxSize()
38 | .verticalScroll(rememberScrollState())
39 | ) {
40 | CellGroup(title = "基础用法", border = false) {
41 | val items = remember {
42 | setOf("滑坠", "山洪", "溺水", "车祸", "落石", "失温", "中暑", "心脏病", "高山病", "其他")
43 | }
44 | var checked by remember {
45 | mutableStateOf(items.first())
46 | }
47 | CheckButtonGroup(
48 | items = items,
49 | checked = checked,
50 | onCheckedChange = { checked = it }
51 | )
52 | }
53 | CellGroup(title = "修改颜色", border = false) {
54 | val items = remember {
55 | setOf("伤势一般", "伤势中等", "伤势严重", "无伤势")
56 | }
57 | var checked by remember {
58 | mutableStateOf(items.first())
59 | }
60 | CheckButtonGroup(
61 | items = items,
62 | checked = checked,
63 | onCheckedChange = { checked = it },
64 | activeColor = Color.Red
65 | )
66 | }
67 | CellGroup(title = "多选模式", border = false) {
68 | val items = remember {
69 | setOf("状态良好", "一切顺利", "到达终点", "到达营地", "正在攀登",
70 | "到达山腰", "到达山顶", "航行正常", "已靠岸", "飞行正常", "已落地", "安全", "到达")
71 | }
72 | var checked by remember {
73 | mutableStateOf(setOf("安全", "到达"))
74 | }
75 | CheckButtonGroup(
76 | items = items,
77 | checked = checked,
78 | onCheckedChange = { checked = it },
79 | activeColor = Color(0xFF2ABF55)
80 | )
81 | }
82 | CellGroup(title = "按钮样式", border = false) {
83 | val items = remember {
84 | setOf("1min", "5min", "10min", "30min", "60min")
85 | }
86 | var checked by remember {
87 | mutableStateOf(items.first())
88 | }
89 | CheckButtonGroup(
90 | items = items,
91 | checked = checked,
92 | onCheckedChange = { checked = it },
93 | activeColor = Color.Red,
94 | mode = CheckButtonMode.Button
95 | )
96 | }
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/CheckboxScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.foundation.rememberScrollState
8 | import androidx.compose.foundation.verticalScroll
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.runtime.getValue
11 | import androidx.compose.runtime.mutableStateOf
12 | import androidx.compose.runtime.remember
13 | import androidx.compose.runtime.setValue
14 | import androidx.compose.ui.Modifier
15 | import androidx.compose.ui.graphics.Color
16 | import androidx.compose.ui.unit.dp
17 | import com.d10ng.compose.demo.Nav
18 | import com.d10ng.compose.ui.AppColor
19 | import com.d10ng.compose.ui.base.Cell
20 | import com.d10ng.compose.ui.base.CellGroup
21 | import com.d10ng.compose.ui.base.CellTitle
22 | import com.d10ng.compose.ui.form.Checkbox
23 | import com.d10ng.compose.ui.form.CheckboxType
24 | import com.d10ng.compose.ui.navigation.NavBar
25 |
26 | /**
27 | * 复选框
28 | * @Author d10ng
29 | * @Date 2023/11/16 03:14
30 | */
31 | @Composable
32 | fun CheckboxScreen() {
33 | Column(
34 | modifier = Modifier
35 | .fillMaxSize()
36 | .background(AppColor.Neutral.bg)
37 | ) {
38 | NavBar(title = "Checkbox", onClickBack = { Nav.instant().popBackStack() })
39 | Column(
40 | modifier = Modifier
41 | .fillMaxSize()
42 | .verticalScroll(rememberScrollState())
43 | ) {
44 | val checkboxModifier = Modifier.padding(start = 19.dp)
45 | var value1 by remember { mutableStateOf(true) }
46 | CellTitle(title = "基础用法")
47 | Checkbox(checked = value1, onCheckedChange = { value1 = it }, modifier = checkboxModifier)
48 | CellTitle(title = "禁用状态")
49 | Checkbox(checked = value1, onCheckedChange = { value1 = it }, modifier = checkboxModifier, disabled = true)
50 | CellTitle(title = "圆形样式")
51 | Checkbox(checked = value1, onCheckedChange = { value1 = it }, modifier = checkboxModifier, type = CheckboxType.CIRCLE)
52 | CellTitle(title = "自定义大小")
53 | Checkbox(checked = value1, onCheckedChange = { value1 = it }, modifier = checkboxModifier, size = 50.dp)
54 | CellTitle(title = "自定义颜色")
55 | Checkbox(checked = value1, onCheckedChange = { value1 = it }, modifier = checkboxModifier, activeColor = Color.Red)
56 | CellGroup(title = "搭配单元格使用", border = false) {
57 | Cell(title = "标题", border = false) {
58 | Checkbox(checked = value1, onCheckedChange = { value1 = it }, modifier = checkboxModifier)
59 | }
60 | }
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/NotifyScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.rememberScrollState
7 | import androidx.compose.foundation.verticalScroll
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import com.d10ng.compose.demo.Nav
11 | import com.d10ng.compose.model.UiViewModelManager
12 | import com.d10ng.compose.ui.AppColor
13 | import com.d10ng.compose.ui.base.Cell
14 | import com.d10ng.compose.ui.base.CellGroup
15 | import com.d10ng.compose.ui.feedback.NotifyType
16 | import com.d10ng.compose.ui.navigation.NavBar
17 |
18 | /**
19 | * 消息通知
20 | * @Author d10ng
21 | * @Date 2023/9/12 18:26
22 | */
23 | @Composable
24 | fun NotifyScreen() {
25 | Column(
26 | modifier = Modifier
27 | .fillMaxSize()
28 | .background(AppColor.Neutral.bg)
29 | ) {
30 | NavBar(title = "Notify", onClickBack = { Nav.instant().popBackStack() })
31 | Column(
32 | modifier = Modifier
33 | .fillMaxSize()
34 | .verticalScroll(rememberScrollState())
35 | ) {
36 | CellGroup(title = "基础用法", inset = true) {
37 | Cell(title = "主要通知", link = true, onClick = {
38 | UiViewModelManager.showNotify(NotifyType.Primary, "这是一条通知消息")
39 | })
40 | Cell(title = "成功通知", link = true, onClick = {
41 | UiViewModelManager.showNotify(NotifyType.Success, "这是一条通知消息")
42 | })
43 | Cell(title = "危险通知", link = true, onClick = {
44 | UiViewModelManager.showNotify(NotifyType.Error, "这是一条通知消息")
45 | })
46 | Cell(title = "警告通知", link = true, onClick = {
47 | UiViewModelManager.showNotify(NotifyType.Warning, "这是一条通知消息")
48 | })
49 | }
50 | CellGroup(title = "其他样式", inset = true) {
51 | Cell(title = "长文本通知", link = true, onClick = {
52 | UiViewModelManager.showNotify(
53 | NotifyType.Primary,
54 | "生命远不止连轴转和忙到极限,人类的体验远比这辽阔、丰富得多。代码是写出来给人看的,附带能在机器上运行。如果解决方法是丑陋的,那就肯定还有更好的解决方法,只是还没有发现而已。"
55 | )
56 | })
57 | }
58 | CellGroup(title = "自定义配置", inset = true) {
59 | Cell(title = "自定义时长", link = true, onClick = {
60 | UiViewModelManager.showNotify(NotifyType.Primary, "通知3秒", 3000)
61 | })
62 | }
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/PopoverScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Arrangement
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.ExperimentalLayoutApi
8 | import androidx.compose.foundation.layout.FlowRow
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.fillMaxWidth
11 | import androidx.compose.foundation.layout.padding
12 | import androidx.compose.foundation.rememberScrollState
13 | import androidx.compose.foundation.verticalScroll
14 | import androidx.compose.runtime.Composable
15 | import androidx.compose.runtime.getValue
16 | import androidx.compose.runtime.mutableStateOf
17 | import androidx.compose.runtime.remember
18 | import androidx.compose.runtime.setValue
19 | import androidx.compose.ui.Modifier
20 | import androidx.compose.ui.unit.dp
21 | import com.d10ng.compose.demo.Nav
22 | import com.d10ng.compose.model.UiViewModelManager
23 | import com.d10ng.compose.ui.AppColor
24 | import com.d10ng.compose.ui.base.Button
25 | import com.d10ng.compose.ui.base.ButtonType
26 | import com.d10ng.compose.ui.base.CellTitle
27 | import com.d10ng.compose.ui.navigation.NavBar
28 | import com.d10ng.compose.ui.show.Popover
29 | import com.d10ng.compose.ui.show.PopoverColumnItems
30 |
31 | /**
32 | * Popover 气泡弹出框
33 | * @Author d10ng
34 | * @Date 2023/9/18 14:28
35 | */
36 |
37 | @OptIn(ExperimentalLayoutApi::class)
38 | @Composable
39 | fun PopoverScreen() {
40 | Column(
41 | modifier = Modifier
42 | .fillMaxSize()
43 | .background(AppColor.Neutral.bg)
44 | ) {
45 | NavBar(title = "Popover", onClickBack = { Nav.instant().popBackStack() })
46 | Column(
47 | modifier = Modifier
48 | .fillMaxSize()
49 | .verticalScroll(rememberScrollState())
50 | ) {
51 | CellTitle(title = "基础用法")
52 | FlowRow(
53 | modifier = Modifier.fillMaxWidth().padding(start = 19.dp),
54 | horizontalArrangement = Arrangement.spacedBy(19.dp)
55 | ) {
56 | Box {
57 | var expanded by remember { mutableStateOf(false) }
58 | Button(
59 | text = "浅色风格",
60 | onClick = { expanded = true },
61 | type = ButtonType.PRIMARY
62 | )
63 | Popover(
64 | expanded = expanded,
65 | onDismissRequest = { expanded = false }
66 | ) {
67 | PopoverColumnItems(
68 | value = setOf("选项一", "选项二", "选项三"),
69 | onClick = {
70 | UiViewModelManager.showToast(it)
71 | expanded = false
72 | }
73 | )
74 | }
75 | }
76 | Box {
77 | var expanded by remember { mutableStateOf(false) }
78 | Button(
79 | text = "深色风格",
80 | onClick = { expanded = true },
81 | type = ButtonType.PRIMARY
82 | )
83 | Popover(
84 | expanded = expanded,
85 | onDismissRequest = { expanded = false },
86 | dark = true
87 | ) {
88 | PopoverColumnItems(
89 | value = setOf("选项一", "选项二", "选项三"),
90 | dark = true,
91 | onClick = {
92 | UiViewModelManager.showToast(it)
93 | expanded = false
94 | }
95 | )
96 | }
97 | }
98 | }
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/PullRefreshScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Arrangement
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.fillMaxSize
8 | import androidx.compose.foundation.lazy.LazyColumn
9 | import androidx.compose.foundation.lazy.items
10 | import androidx.compose.material3.ExperimentalMaterial3Api
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.getValue
13 | import androidx.compose.runtime.mutableStateOf
14 | import androidx.compose.runtime.remember
15 | import androidx.compose.runtime.setValue
16 | import androidx.compose.ui.Alignment
17 | import androidx.compose.ui.Modifier
18 | import androidx.compose.ui.unit.dp
19 | import com.d10ng.compose.demo.Nav
20 | import com.d10ng.compose.ui.AppColor
21 | import com.d10ng.compose.ui.base.Cell
22 | import com.d10ng.compose.ui.base.CellGroup
23 | import com.d10ng.compose.ui.feedback.PullRefreshIndicator
24 | import com.d10ng.compose.ui.feedback.pullRefresh
25 | import com.d10ng.compose.ui.feedback.rememberPullRefreshState
26 | import com.d10ng.compose.ui.navigation.NavBar
27 | import kotlinx.coroutines.CoroutineScope
28 | import kotlinx.coroutines.Dispatchers
29 | import kotlinx.coroutines.delay
30 | import kotlinx.coroutines.launch
31 |
32 | /**
33 | * 下拉刷新
34 | * @Author d10ng
35 | * @Date 2023/11/8 18:29
36 | */
37 | @OptIn(ExperimentalMaterial3Api::class)
38 | @Composable
39 | fun PullRefreshScreen() {
40 | var isRefreshing by remember {
41 | mutableStateOf(false)
42 | }
43 | val state = rememberPullRefreshState(refreshing = isRefreshing, onRefresh = {
44 | isRefreshing = true
45 | CoroutineScope(Dispatchers.Default).launch {
46 | delay(1000)
47 | isRefreshing = false
48 | }
49 | })
50 |
51 | Column(
52 | modifier = Modifier
53 | .fillMaxSize()
54 | .background(AppColor.Neutral.bg)
55 | ) {
56 | NavBar(title = "PullRefreshScreen", onClickBack = { Nav.instant().popBackStack() })
57 | Box(modifier = Modifier.fillMaxSize()) {
58 | LazyColumn(
59 | modifier = Modifier.pullRefresh(state),
60 | verticalArrangement = Arrangement.spacedBy(19.dp)
61 | ) {
62 | items(listOf("test 1", "test 2")) {
63 | CellGroup(
64 | title = "基础用法"
65 | ) {
66 | Cell(title = it)
67 | }
68 | }
69 | }
70 | PullRefreshIndicator(refreshing = isRefreshing, state = state,
71 | modifier = Modifier
72 | .align(Alignment.TopCenter)
73 | )
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/ShapeScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.border
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.ExperimentalLayoutApi
8 | import androidx.compose.foundation.layout.Row
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.fillMaxWidth
11 | import androidx.compose.foundation.layout.height
12 | import androidx.compose.foundation.layout.padding
13 | import androidx.compose.foundation.rememberScrollState
14 | import androidx.compose.foundation.verticalScroll
15 | import androidx.compose.material3.MaterialTheme
16 | import androidx.compose.material3.Text
17 | import androidx.compose.runtime.Composable
18 | import androidx.compose.ui.Alignment
19 | import androidx.compose.ui.Modifier
20 | import androidx.compose.ui.graphics.Color
21 | import androidx.compose.ui.graphics.Shape
22 | import androidx.compose.ui.unit.dp
23 | import com.d10ng.compose.demo.Nav
24 | import com.d10ng.compose.ui.AppColor
25 | import com.d10ng.compose.ui.navigation.NavBar
26 |
27 | /**
28 | * 容器形状
29 | * @Author d10ng
30 | * @Date 2025/3/24 11:59
31 | */
32 | @OptIn(ExperimentalLayoutApi::class)
33 | @Composable
34 | fun ShapeScreen() {
35 | Column(
36 | modifier = Modifier
37 | .fillMaxSize()
38 | .background(AppColor.Neutral.bg)
39 | ) {
40 | NavBar(title = "Shape", onClickBack = { Nav.instant().popBackStack() })
41 | Column(
42 | modifier = Modifier
43 | .fillMaxSize()
44 | .verticalScroll(rememberScrollState())
45 | ) {
46 | MaterialTheme.shapes.apply {
47 | ShapeBox(extraSmall, "extraSmall")
48 | ShapeBox(small, "small")
49 | ShapeBox(medium, "medium")
50 | ShapeBox(large, "large")
51 | ShapeBox(extraLarge, "extraLarge")
52 | }
53 | }
54 | }
55 | }
56 |
57 | @Composable
58 | private fun ShapeBox(
59 | shape: Shape,
60 | name: String
61 | ) {
62 | Row(
63 | modifier = Modifier
64 | .fillMaxWidth()
65 | .padding(top = 16.dp)
66 | .padding(horizontal = 16.dp),
67 | verticalAlignment = Alignment.CenterVertically
68 | ) {
69 | Box(
70 | modifier = Modifier
71 | .weight(1f)
72 | .height(60.dp)
73 | .background(Color.Blue, shape)
74 | .border(1.dp, Color.Gray)
75 | )
76 | Text(
77 | text = name,
78 | modifier = Modifier
79 | .weight(1f)
80 | .padding(start = 8.dp)
81 | )
82 | }
83 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/StepperScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.rememberScrollState
7 | import androidx.compose.foundation.verticalScroll
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.getValue
10 | import androidx.compose.runtime.mutableIntStateOf
11 | import androidx.compose.runtime.remember
12 | import androidx.compose.runtime.setValue
13 | import androidx.compose.ui.Modifier
14 | import com.d10ng.compose.demo.Nav
15 | import com.d10ng.compose.ui.AppColor
16 | import com.d10ng.compose.ui.base.Cell
17 | import com.d10ng.compose.ui.base.CellGroup
18 | import com.d10ng.compose.ui.form.Stepper
19 | import com.d10ng.compose.ui.form.StepperStyle
20 | import com.d10ng.compose.ui.navigation.NavBar
21 |
22 | /**
23 | * 步进器
24 | * @Author d10ng
25 | * @Date 2023/9/6 17:47
26 | */
27 | @Composable
28 | fun StepperScreen() {
29 | Column(
30 | modifier = Modifier
31 | .fillMaxSize()
32 | .background(AppColor.Neutral.bg)
33 | ) {
34 | NavBar(title = "Stepper", onClickBack = { Nav.instant().popBackStack() })
35 | Column(
36 | modifier = Modifier
37 | .fillMaxSize()
38 | .verticalScroll(rememberScrollState())
39 | ) {
40 | CellGroup(title = "使用方式", inset = true) {
41 | Cell(title = "基础用法") {
42 | var value1 by remember { mutableIntStateOf(1) }
43 | Stepper(value = value1, onValueChange = { value1 = it })
44 | }
45 | Cell(title = "步长设置") {
46 | var value1 by remember { mutableIntStateOf(0) }
47 | Stepper(value = value1, onValueChange = { value1 = it }, step = 2)
48 | }
49 | Cell(title = "限制输入范围") {
50 | var value1 by remember { mutableIntStateOf(10) }
51 | Stepper(value = value1, onValueChange = { value1 = it }, max = 10)
52 | }
53 | Cell(title = "禁用状态") {
54 | var value1 by remember { mutableIntStateOf(0) }
55 | Stepper(value = value1, onValueChange = { value1 = it }, disabled = true)
56 | }
57 | Cell(title = "禁用输入框") {
58 | var value1 by remember { mutableIntStateOf(0) }
59 | Stepper(value = value1, onValueChange = { value1 = it }, canInput = false)
60 | }
61 | Cell(title = "圆角风格") {
62 | var value1 by remember { mutableIntStateOf(0) }
63 | Stepper(value = value1, onValueChange = { value1 = it }, style = StepperStyle.Round)
64 | }
65 | }
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/StepsScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.rememberScrollState
10 | import androidx.compose.foundation.verticalScroll
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.getValue
13 | import androidx.compose.runtime.mutableIntStateOf
14 | import androidx.compose.runtime.remember
15 | import androidx.compose.runtime.setValue
16 | import androidx.compose.ui.Modifier
17 | import androidx.compose.ui.graphics.Color
18 | import androidx.compose.ui.unit.dp
19 | import com.d10ng.compose.demo.Nav
20 | import com.d10ng.compose.ui.AppColor
21 | import com.d10ng.compose.ui.base.Button
22 | import com.d10ng.compose.ui.base.CellGroup
23 | import com.d10ng.compose.ui.navigation.NavBar
24 | import com.d10ng.compose.ui.show.Steps
25 |
26 | /**
27 | * 步骤条
28 | * @Author d10ng
29 | * @Date 2023/9/13 13:58
30 | */
31 |
32 | @Composable
33 | fun StepsScreen() {
34 | Column(
35 | modifier = Modifier
36 | .fillMaxSize()
37 | .background(AppColor.Neutral.bg)
38 | ) {
39 | NavBar(title = "Steps", onClickBack = { Nav.instant().popBackStack() })
40 | Column(
41 | modifier = Modifier
42 | .fillMaxSize()
43 | .verticalScroll(rememberScrollState())
44 | ) {
45 | var index by remember {
46 | mutableIntStateOf(0)
47 | }
48 | CellGroup(title = "基础用法", border = false) {
49 | Box(
50 | modifier = Modifier
51 | .fillMaxWidth()
52 | .padding(vertical = 19.dp)
53 | ) {
54 | Steps(
55 | items = setOf("步骤一", "步骤二", "步骤三", "步骤四"),
56 | runningIndex = index
57 | )
58 | }
59 | Box(
60 | modifier = Modifier
61 | .fillMaxWidth()
62 | .padding(vertical = 19.dp)
63 | ) {
64 | Steps(
65 | items = setOf("步骤一", "步骤二", "步骤三", "步骤四"),
66 | runningIndex = index,
67 | runningColor = Color.Red
68 | )
69 | }
70 | }
71 | Button(text = "下一步") {
72 | index++
73 | if (index > 3) index = 0
74 | }
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/SwitchScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.foundation.rememberScrollState
8 | import androidx.compose.foundation.verticalScroll
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.runtime.getValue
11 | import androidx.compose.runtime.mutableStateOf
12 | import androidx.compose.runtime.remember
13 | import androidx.compose.runtime.setValue
14 | import androidx.compose.ui.Modifier
15 | import androidx.compose.ui.graphics.Color
16 | import androidx.compose.ui.unit.dp
17 | import com.d10ng.compose.demo.Nav
18 | import com.d10ng.compose.ui.AppColor
19 | import com.d10ng.compose.ui.base.Cell
20 | import com.d10ng.compose.ui.base.CellGroup
21 | import com.d10ng.compose.ui.base.CellTitle
22 | import com.d10ng.compose.ui.form.Switch
23 | import com.d10ng.compose.ui.navigation.NavBar
24 | import dljetpackcomposeutil_project.composeapp.generated.resources.Res
25 | import dljetpackcomposeutil_project.composeapp.generated.resources.round_add_circle_outline_24
26 |
27 | /**
28 | * Switch 开关
29 | * @Author d10ng
30 | * @Date 2023/9/6 14:29
31 | */
32 | @Composable
33 | fun SwitchScreen() {
34 | Column(
35 | modifier = Modifier
36 | .fillMaxSize()
37 | .background(AppColor.Neutral.bg)
38 | ) {
39 | NavBar(title = "Switch", onClickBack = { Nav.instant().popBackStack() })
40 | Column(
41 | modifier = Modifier
42 | .fillMaxSize()
43 | .verticalScroll(rememberScrollState())
44 | ) {
45 | val switchModifier = Modifier.padding(start = 19.dp)
46 | var value1 by remember { mutableStateOf(true) }
47 | CellTitle(title = "基础用法")
48 | Switch(checked = value1, onCheckedChange = { value1 = it }, modifier = switchModifier)
49 | CellTitle(title = "禁用状态")
50 | Switch(
51 | checked = value1,
52 | onCheckedChange = { value1 = it },
53 | modifier = switchModifier,
54 | disabled = true
55 | )
56 | CellTitle(title = "加载状态")
57 | Switch(
58 | checked = value1,
59 | onCheckedChange = { value1 = it },
60 | modifier = switchModifier,
61 | loading = true
62 | )
63 | CellTitle(title = "自定义大小")
64 | Switch(
65 | checked = value1,
66 | onCheckedChange = { value1 = it },
67 | modifier = switchModifier,
68 | size = 25.dp
69 | )
70 | CellTitle(title = "自定义颜色")
71 | Switch(
72 | checked = value1,
73 | onCheckedChange = { value1 = it },
74 | modifier = switchModifier,
75 | activeColor = Color.Red
76 | )
77 | CellTitle(title = "自定义按钮")
78 | Switch(
79 | checked = value1,
80 | onCheckedChange = { value1 = it },
81 | modifier = switchModifier,
82 | iconResource = Res.drawable.round_add_circle_outline_24
83 | )
84 | CellGroup(title = "搭配单元格使用", border = false) {
85 | Cell(title = "标题", border = false) {
86 | Switch(
87 | checked = value1,
88 | onCheckedChange = { value1 = it },
89 | modifier = switchModifier,
90 | size = 25.dp
91 | )
92 | }
93 | }
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/TagScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.layout.navigationBarsPadding
7 | import androidx.compose.foundation.rememberScrollState
8 | import androidx.compose.foundation.verticalScroll
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.graphics.Color
12 | import com.d10ng.compose.demo.Nav
13 | import com.d10ng.compose.ui.AppColor
14 | import com.d10ng.compose.ui.base.Cell
15 | import com.d10ng.compose.ui.base.CellGroup
16 | import com.d10ng.compose.ui.navigation.NavBar
17 | import com.d10ng.compose.ui.show.Tag
18 | import com.d10ng.compose.ui.show.TagStyle
19 | import com.d10ng.compose.ui.show.TagType
20 |
21 | /**
22 | * 标签
23 | * @Author d10ng
24 | * @Date 2023/9/7 10:52
25 | */
26 | @Composable
27 | fun TagScreen() {
28 | Column(
29 | modifier = Modifier
30 | .fillMaxSize()
31 | .background(AppColor.Neutral.bg)
32 | .navigationBarsPadding()
33 | ) {
34 | NavBar(title = "Tag", onClickBack = { Nav.instant().popBackStack() })
35 | Column(
36 | modifier = Modifier
37 | .fillMaxSize()
38 | .verticalScroll(rememberScrollState())
39 | ) {
40 | CellGroup(title = "基础用法", inset = true) {
41 | Cell(title = "primary 类型") {
42 | Tag(text = "标签")
43 | }
44 | Cell(title = "success 类型") {
45 | Tag(text = "标签", type = TagType.Success)
46 | }
47 | Cell(title = "warning 类型") {
48 | Tag(text = "标签", type = TagType.Warning)
49 | }
50 | Cell(title = "danger 类型", border = false) {
51 | Tag(text = "标签", type = TagType.Danger)
52 | }
53 | }
54 | CellGroup(title = "样式风格", inset = true) {
55 | Cell(title = "填充样式") {
56 | Tag(text = "标签", style = TagStyle.Fill)
57 | }
58 | Cell(title = "圆角样式") {
59 | Tag(text = "标签", style = TagStyle.Round)
60 | }
61 | Cell(title = "标记样式") {
62 | Tag(text = "标签", style = TagStyle.Mark)
63 | }
64 | Cell(title = "边框样式", border = false) {
65 | Tag(text = "标签", style = TagStyle.Outline)
66 | }
67 | }
68 | CellGroup(title = "自定义颜色", inset = true) {
69 | Cell(title = "背景颜色") {
70 | Tag(text = "标签", color = Color.Gray)
71 | }
72 | Cell(title = "文字颜色") {
73 | Tag(text = "标签", color = Color(0xFFffe1e1), contentColor = Color(0xFFc14036))
74 | }
75 | Cell(title = "空心颜色", border = false) {
76 | Tag(text = "标签", color = Color.Magenta, style = TagStyle.Outline)
77 | }
78 | }
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/ToastScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.rememberScrollState
7 | import androidx.compose.foundation.verticalScroll
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import com.d10ng.compose.demo.Nav
11 | import com.d10ng.compose.model.UiViewModelManager
12 | import com.d10ng.compose.ui.AppColor
13 | import com.d10ng.compose.ui.base.Cell
14 | import com.d10ng.compose.ui.base.CellGroup
15 | import com.d10ng.compose.ui.base.ToastPosition
16 | import com.d10ng.compose.ui.navigation.NavBar
17 | import kotlinx.coroutines.CoroutineScope
18 | import kotlinx.coroutines.Dispatchers
19 | import kotlinx.coroutines.delay
20 | import kotlinx.coroutines.launch
21 |
22 | /**
23 | * 轻提示
24 | * @Author d10ng
25 | * @Date 2023/9/4 15:14
26 | */
27 | @Composable
28 | fun ToastScreen() {
29 | Column(
30 | modifier = Modifier
31 | .fillMaxSize()
32 | .background(AppColor.Neutral.bg)
33 | ) {
34 | NavBar(title = "Toast", onClickBack = { Nav.instant().popBackStack() })
35 | Column(
36 | modifier = Modifier
37 | .fillMaxSize()
38 | .verticalScroll(rememberScrollState())
39 | ) {
40 | CellGroup(title = "基础用法", inset = true) {
41 | Cell(
42 | title = "文字提示",
43 | link = true,
44 | onClick = { UiViewModelManager.showToast("提示内容") })
45 | Cell(title = "加载提示", link = true, onClick = {
46 | UiViewModelManager.showLoading("加载中...")
47 | CoroutineScope(Dispatchers.Default).launch {
48 | delay(1500)
49 | UiViewModelManager.hideLoading()
50 | }
51 | })
52 | Cell(title = "无文本加载提示", link = true, onClick = {
53 | UiViewModelManager.showLoading()
54 | CoroutineScope(Dispatchers.Default).launch {
55 | delay(1500)
56 | UiViewModelManager.hideLoading()
57 | }
58 | })
59 | Cell(
60 | title = "成功提示",
61 | link = true,
62 | onClick = { UiViewModelManager.showSuccessToast("成功文案") })
63 | Cell(
64 | title = "失败提示",
65 | label = "提示文案不建议8个字符",
66 | link = true,
67 | onClick = { UiViewModelManager.showFailToast("失败文案失败文案") })
68 | }
69 | CellGroup(title = "自定义位置", inset = true) {
70 | Cell(
71 | title = "顶部展示",
72 | link = true,
73 | onClick = {
74 | UiViewModelManager.showToast(
75 | "提示内容",
76 | position = ToastPosition.Top
77 | )
78 | })
79 | Cell(
80 | title = "底部展示",
81 | link = true,
82 | onClick = {
83 | UiViewModelManager.showToast(
84 | "提示内容",
85 | position = ToastPosition.Bottom
86 | )
87 | })
88 | }
89 | CellGroup(title = "动态更新提示", inset = true) {
90 | Cell(title = "动态更新提示", link = true, onClick = {
91 | var wait = 3
92 | UiViewModelManager.showLoading("等待${wait}秒...")
93 | CoroutineScope(Dispatchers.Default).launch {
94 | while (wait > 0) {
95 | delay(1000)
96 | wait--
97 | UiViewModelManager.showLoading("等待${wait}秒...")
98 | }
99 | UiViewModelManager.hideLoading()
100 | }
101 | })
102 | }
103 | }
104 | }
105 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/com/d10ng/compose/demo/pages/TypographyScreen.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo.pages
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.ExperimentalLayoutApi
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.rememberScrollState
10 | import androidx.compose.foundation.verticalScroll
11 | import androidx.compose.material3.HorizontalDivider
12 | import androidx.compose.material3.MaterialTheme
13 | import androidx.compose.material3.Text
14 | import androidx.compose.runtime.Composable
15 | import androidx.compose.ui.Modifier
16 | import androidx.compose.ui.text.TextStyle
17 | import androidx.compose.ui.unit.dp
18 | import androidx.compose.ui.unit.sp
19 | import com.d10ng.compose.demo.Nav
20 | import com.d10ng.compose.ui.navigation.NavBar
21 |
22 | /**
23 | * 字体排版
24 | * @Author d10ng
25 | * @Date 2025/3/24 11:55
26 | */
27 | @OptIn(ExperimentalLayoutApi::class)
28 | @Composable
29 | fun TypographyScreen() {
30 | Column(
31 | modifier = Modifier
32 | .fillMaxSize()
33 | .background(MaterialTheme.colorScheme.background)
34 | ) {
35 | NavBar(title = "Typography", onClickBack = { Nav.instant().popBackStack() })
36 | Column(
37 | modifier = Modifier
38 | .fillMaxSize()
39 | .verticalScroll(rememberScrollState())
40 | .padding(16.dp)
41 | ) {
42 | MaterialTheme.typography.apply {
43 | TextView("displayLarge", style = displayLarge)
44 | TextView("displayMedium", style = displayMedium)
45 | TextView("displaySmall", style = displaySmall)
46 | TextView("headlineLarge", style = headlineLarge)
47 | TextView("headlineMedium", style = headlineMedium)
48 | TextView("headlineSmall", style = headlineSmall)
49 | TextView("titleLarge", style = titleLarge)
50 | TextView("titleMedium", style = titleMedium)
51 | TextView("titleSmall", style = titleSmall)
52 | TextView("bodyLarge", style = bodyLarge)
53 | TextView("bodyMedium", style = bodyMedium)
54 | TextView("bodySmall", style = bodySmall)
55 | TextView("labelLarge", style = labelLarge)
56 | TextView("labelMedium", style = labelMedium)
57 | TextView("labelSmall", style = labelSmall)
58 | }
59 | }
60 | }
61 | }
62 |
63 | @Composable
64 | private fun TextView(
65 | name: String,
66 | style: TextStyle
67 | ) {
68 | style.apply {
69 | Column(
70 | modifier = Modifier
71 | .fillMaxWidth()
72 | ) {
73 | Text(
74 | text = name,
75 | style = this@apply
76 | )
77 | Text(
78 | text = "${fontWeight}, ${fontSize}, $lineHeight",
79 | fontSize = 12.sp
80 | )
81 | HorizontalDivider(modifier = Modifier.padding(top = 8.dp))
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/com/d10ng/compose/demo/App.ios.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo
2 |
3 | import androidx.compose.ui.text.font.FontFamily
4 |
5 | actual suspend fun loadCustomFontFamily(): FontFamily? {
6 | return null
7 | }
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/com/d10ng/compose/demo/MainViewController.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo
2 |
3 | import androidx.compose.ui.window.ComposeUIViewController
4 |
5 | fun MainViewController() = ComposeUIViewController { App() }
--------------------------------------------------------------------------------
/composeApp/src/wasmJsMain/kotlin/com/d10ng/compose/demo/App.wasmJs.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.demo
2 |
3 | import androidx.compose.ui.text.font.FontFamily
4 | import androidx.compose.ui.text.font.FontStyle
5 | import androidx.compose.ui.text.font.FontWeight
6 | import androidx.compose.ui.text.platform.Font
7 | import dljetpackcomposeutil_project.composeapp.generated.resources.Res
8 | import org.jetbrains.compose.resources.ExperimentalResourceApi
9 |
10 |
11 | @OptIn(ExperimentalResourceApi::class)
12 | actual suspend fun loadCustomFontFamily(): FontFamily? {
13 | val normal = Res.readBytes("font/MiSans_Normal.ttf")
14 | return FontFamily(
15 | Font("MiSans_Normal", normal, FontWeight.Normal, FontStyle.Normal)
16 | )
17 | }
--------------------------------------------------------------------------------
/composeApp/src/wasmJsMain/kotlin/com/d10ng/compose/multiplatform/demo/main.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.multiplatform.demo
2 |
3 | import androidx.compose.ui.ExperimentalComposeUiApi
4 | import androidx.compose.ui.window.ComposeViewport
5 | import com.d10ng.compose.demo.App
6 | import kotlinx.browser.document
7 |
8 | @OptIn(ExperimentalComposeUiApi::class)
9 | fun main() {
10 | ComposeViewport(document.body!!) {
11 | App()
12 | }
13 | }
--------------------------------------------------------------------------------
/composeApp/src/wasmJsMain/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | DLJetpackComposeUtil
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/composeApp/src/wasmJsMain/resources/styles.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | width: 100%;
3 | height: 100%;
4 | margin: 0;
5 | padding: 0;
6 | overflow: hidden;
7 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 |
3 | #Gradle
4 | org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
5 |
6 | #Android
7 | android.nonTransitiveRClass=true
8 | android.useAndroidX=true
9 |
10 | #Kotlin Multiplatform
11 | kotlin.mpp.enableCInteropCommonization=true
12 |
13 | # fix https://github.com/ben-manes/gradle-versions-plugin/issues/859
14 | systemProp.javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
15 | systemProp.javax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
16 | systemProp.javax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
17 |
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.11.1"
3 | android-compileSdk = "35"
4 | android-minSdk = "26"
5 | android-targetSdk = "34"
6 | androidx-activity-compose = "1.10.1"
7 | androidx-compose-bom = "2025.07.00"
8 | androidx-core = "1.16.0"
9 | androidx-lifecycle = "2.9.2"
10 | androidx-navigation-compose = "2.9.0-beta03"
11 | androidx-test-junit = "1.3.0"
12 | androidx-test-espresso = "3.7.0"
13 | compose = "1.8.2"
14 | kotlin = "2.2.0"
15 | kotlinx-datetime = "0.7.1"
16 | kotlinx-serialization-json = "1.9.0"
17 | jetbrains-androidx-lifecycle = "2.9.1"
18 | junit = "4.13.2"
19 | constraintlayout-compose-multiplatform = "0.6.0-shaded"
20 | dlcommon = "0.7.0"
21 | dlapp = "2.6.0"
22 |
23 | [libraries]
24 | androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" }
25 | androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidx-compose-bom" }
26 | androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
27 | androidx-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "jetbrains-androidx-lifecycle" }
28 | androidx-lifecycle-viewmodel-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "jetbrains-androidx-lifecycle" }
29 | androidx-lifecycle-runtime-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "jetbrains-androidx-lifecycle" }
30 | androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }
31 | androidx-navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "androidx-navigation-compose" }
32 | androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-junit" }
33 | androidx-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espresso" }
34 | androidx-ui = { group = "androidx.compose.ui", name = "ui" }
35 | androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
36 | androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
37 | androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
38 | androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
39 | androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
40 | androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
41 | junit = { module = "junit:junit", version.ref = "junit" }
42 | kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
43 | kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
44 | constraintlayout-compose-multiplatform = { module = "tech.annexflow.compose:constraintlayout-compose-multiplatform", version.ref = "constraintlayout-compose-multiplatform" }
45 | dl-common = { module = "com.github.D10NGYANG:DLCommonUtil", version.ref = "dlcommon" }
46 | dl-app = { module = "com.github.D10NGYANG:DLAppUtil", version.ref = "dlapp" }
47 |
48 | [plugins]
49 | android-application = { id = "com.android.application", version.ref = "agp" }
50 | android-library = { id = "com.android.library", version.ref = "agp" }
51 | compose = { id = "org.jetbrains.compose", version.ref = "compose" }
52 | kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
53 | kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
54 | kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
55 | kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.14.3-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/iosApp/Configuration/Config.xcconfig:
--------------------------------------------------------------------------------
1 | TEAM_ID=
2 | BUNDLE_ID=com.d10ng.compose.demo.DLJetpackComposeUtil
3 | APP_NAME=DLJetpackComposeUtil
--------------------------------------------------------------------------------
/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "app-icon-1024.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D10NGYANG/DLJetpackComposeUtil/a999d21d0af1678fdb8e6614d0db8521bdf77691/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/ContentView.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import SwiftUI
3 | import ComposeApp
4 |
5 | struct ComposeView: UIViewControllerRepresentable {
6 | func makeUIViewController(context: Context) -> UIViewController {
7 | MainViewControllerKt.MainViewController()
8 | }
9 |
10 | func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
11 | }
12 |
13 | struct ContentView: View {
14 | var body: some View {
15 | ComposeView()
16 | .ignoresSafeArea(edges: .all)
17 | .ignoresSafeArea(.keyboard) // Compose has own keyboard handler
18 | }
19 | }
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | CADisableMinimumFrameDurationOnPhone
24 |
25 | UIApplicationSceneManifest
26 |
27 | UIApplicationSupportsMultipleScenes
28 |
29 |
30 | UILaunchScreen
31 |
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/iOSApp.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @main
4 | struct iOSApp: App {
5 | var body: some Scene {
6 | WindowGroup {
7 | ContentView()
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/library/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
2 | import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
3 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
4 |
5 | plugins {
6 | alias(libs.plugins.kotlin.multiplatform)
7 | alias(libs.plugins.android.library)
8 | alias(libs.plugins.compose)
9 | alias(libs.plugins.kotlin.compose)
10 | id("maven-publish")
11 | }
12 |
13 | group = "com.github.D10NGYANG"
14 | version = "3.1.4"
15 |
16 | kotlin {
17 | androidTarget {
18 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
19 | compilerOptions {
20 | jvmTarget.set(JvmTarget.JVM_11)
21 | }
22 | publishLibraryVariants("release")
23 | }
24 |
25 | iosArm64()
26 | iosSimulatorArm64()
27 | iosX64()
28 |
29 | @OptIn(ExperimentalWasmDsl::class)
30 | wasmJs {
31 | browser()
32 | binaries.library()
33 | }
34 |
35 | sourceSets {
36 | androidMain.dependencies {
37 | implementation(compose.preview)
38 | implementation(libs.androidx.activity.compose)
39 | }
40 | commonMain.dependencies {
41 | implementation(compose.runtime)
42 | implementation(compose.foundation)
43 | implementation(compose.material3)
44 | implementation(compose.ui)
45 | implementation(compose.components.resources)
46 | implementation(compose.components.uiToolingPreview)
47 | implementation(libs.constraintlayout.compose.multiplatform)
48 | // Lifecycle
49 | implementation(libs.androidx.lifecycle.viewmodel)
50 | implementation(libs.androidx.lifecycle.viewmodel.compose)
51 | implementation(libs.androidx.lifecycle.runtime.compose)
52 | // 时间工具
53 | implementation(libs.kotlinx.datetime)
54 | }
55 | }
56 | }
57 |
58 | compose.resources {
59 | packageOfResClass = "com.d10ng.compose.resources"
60 | }
61 |
62 | android {
63 | namespace = "com.d10ng.compose"
64 | compileSdk = libs.versions.android.compileSdk.get().toInt()
65 |
66 | defaultConfig {
67 | minSdk = libs.versions.android.minSdk.get().toInt()
68 | }
69 | compileOptions {
70 | sourceCompatibility = JavaVersion.VERSION_11
71 | targetCompatibility = JavaVersion.VERSION_11
72 | }
73 | buildFeatures {
74 | compose = true
75 | }
76 | dependencies {
77 | debugImplementation(compose.uiTooling)
78 | }
79 | }
80 |
81 | val bds100MavenUsername: String by project
82 | val bds100MavenPassword: String by project
83 |
84 | val javadocJar: TaskProvider by tasks.registering(Jar::class) {
85 | archiveClassifier.set("javadoc")
86 | }
87 |
88 | afterEvaluate {
89 | publishing {
90 | publications {
91 | withType(MavenPublication::class) {
92 | //artifactId = artifactId.replace(project.name, rootProject.name)
93 | artifact(tasks["javadocJar"])
94 | }
95 | }
96 | repositories {
97 | maven {
98 | url = uri("/Users/d10ng/project/kotlin/maven-repo/repository")
99 | }
100 | maven {
101 | credentials {
102 | username = bds100MavenUsername
103 | password = bds100MavenPassword
104 | }
105 | setUrl("https://nexus.bds100.com/repository/maven-releases/")
106 | }
107 | }
108 | }
109 | }
110 |
111 |
--------------------------------------------------------------------------------
/library/src/androidMain/kotlin/com/d10ng/compose/ui/show/ImagePreview.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.show
2 |
3 | import android.graphics.BitmapFactory
4 | import androidx.compose.foundation.Image
5 | import androidx.compose.foundation.gestures.detectTapGestures
6 | import androidx.compose.foundation.gestures.rememberTransformableState
7 | import androidx.compose.foundation.gestures.transformable
8 | import androidx.compose.foundation.layout.fillMaxSize
9 | import androidx.compose.material3.Surface
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.runtime.getValue
12 | import androidx.compose.runtime.mutableFloatStateOf
13 | import androidx.compose.runtime.mutableStateOf
14 | import androidx.compose.runtime.remember
15 | import androidx.compose.runtime.setValue
16 | import androidx.compose.ui.Modifier
17 | import androidx.compose.ui.geometry.Offset
18 | import androidx.compose.ui.graphics.Color
19 | import androidx.compose.ui.graphics.asImageBitmap
20 | import androidx.compose.ui.graphics.graphicsLayer
21 | import androidx.compose.ui.input.pointer.pointerInput
22 | import java.io.File
23 |
24 | /**
25 | * 图片查看器
26 | * @Author d10ng
27 | * @Date 2023/11/28 16:02
28 | */
29 |
30 | /**
31 | * 图片查看器
32 | * @param path String 图片路径
33 | * @param onDismiss Function0
34 | */
35 | @Composable
36 | fun ImagePreview(
37 | path: String,
38 | onDismiss: () -> Unit
39 | ) {
40 | var scale by remember { mutableFloatStateOf(1f) }
41 | var offset by remember { mutableStateOf(Offset.Zero) }
42 | val state = rememberTransformableState { zoomChange, offsetChange, _ ->
43 | scale = (zoomChange * scale).coerceAtLeast(1f)
44 | offset += offsetChange
45 | }
46 |
47 | val bitmap = remember(path) {
48 | File(path).let {
49 | if (it.exists()) {
50 | runCatching { BitmapFactory.decodeFile(it.absolutePath) }.getOrNull()
51 | } else null
52 | }?.asImageBitmap()
53 | }
54 |
55 | Surface(
56 | color = Color.DarkGray,
57 | modifier = Modifier
58 | .fillMaxSize()
59 | .pointerInput(Unit) {
60 | detectTapGestures(
61 | onDoubleTap = {
62 | scale = 1f
63 | offset = Offset.Zero
64 | },
65 | onTap = {
66 | onDismiss()
67 | }
68 | )
69 | }
70 | ) {
71 | if (bitmap != null) {
72 | Image(
73 | bitmap = bitmap,
74 | contentDescription = null,
75 | modifier = Modifier
76 | .fillMaxSize()
77 | .transformable(state = state)
78 | .graphicsLayer(
79 | scaleX = scale,
80 | scaleY = scale,
81 | translationX = offset.x,
82 | translationY = offset.y
83 | )
84 | )
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/library/src/androidMain/kotlin/com/d10ng/compose/utils/BackHandlerUtils.android.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.utils
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 | /**
6 | * 返回键处理
7 | * @Author d10ng
8 | * @Date 2024/9/12 11:26
9 | */
10 | @Composable
11 | actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {
12 | androidx.activity.compose.BackHandler(enabled = enabled, onBack = onBack)
13 | }
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_baseline_arrow_drop_down_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_baseline_arrow_drop_up_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_baseline_keyboard_arrow_right_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_baseline_visibility_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_baseline_visibility_off_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_false_102.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_add_circle_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_back_22.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_cancel_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_check_24.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_error_160.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_forward_16.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_remove_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_remove_circle_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_search_22.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_steps_active_20.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_round_success_160.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
16 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/commonMain/composeResources/drawable/ic_success_102.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/model/IUiViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.model
2 |
3 | import com.d10ng.compose.ui.base.ToastPosition
4 | import com.d10ng.compose.ui.feedback.NotifyType
5 | import com.d10ng.compose.ui.sheet.builder.SheetBuilder
6 |
7 | /**
8 | *
9 | * @Author d10ng
10 | * @Date 2023/9/4 15:19
11 | */
12 | interface IUiViewModel {
13 |
14 | /**
15 | * 显示toast
16 | * @param msg String 消息
17 | * @param duration Long 显示时长, 默认1500毫秒
18 | * @param position ToastPosition 显示位置, 默认居中
19 | */
20 | fun showToast(
21 | msg: String,
22 | duration: Long = 1500,
23 | position: ToastPosition = ToastPosition.Center
24 | )
25 |
26 | /**
27 | * 显示成功的toast
28 | * @param msg String 消息
29 | * @param duration Long 显示时长, 默认1500毫秒
30 | */
31 | fun showSuccessToast(msg: String, duration: Long = 1500)
32 |
33 | /**
34 | * 显示失败的toast
35 | * @param msg String 消息
36 | * @param duration Long 显示时长, 默认1500毫秒
37 | */
38 | fun showFailToast(msg: String, duration: Long = 1500)
39 |
40 | /**
41 | * 显示loading
42 | * @param text String
43 | */
44 | fun showLoading(text: String = "")
45 |
46 | /**
47 | * 隐藏loading
48 | */
49 | fun hideLoading()
50 |
51 | /**
52 | * 显示提示
53 | * @param type NotifyType
54 | * @param text String
55 | * @param duration Long
56 | */
57 | fun showNotify(type: NotifyType, text: String, duration: Long = 1500)
58 |
59 | /**
60 | * 显示错误提示
61 | * @param text String
62 | * @param duration Long
63 | */
64 | fun showErrorNotify(text: String, duration: Long = 1500)
65 |
66 | /**
67 | * 显示底部弹窗
68 | * @param builder SheetBuilder
69 | */
70 | fun showSheet(builder: SheetBuilder)
71 |
72 | /**
73 | * 隐藏底部弹窗
74 | */
75 | fun hideSheet(builder: SheetBuilder)
76 |
77 | /**
78 | * 隐藏全部底部弹窗
79 | */
80 | fun hideAllSheet()
81 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/model/UiViewModelManager.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.model
2 |
3 | import androidx.compose.foundation.layout.Box
4 | import androidx.compose.foundation.layout.fillMaxSize
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.runtime.DisposableEffect
7 | import androidx.compose.runtime.LaunchedEffect
8 | import androidx.compose.ui.Modifier
9 | import androidx.lifecycle.viewmodel.compose.viewModel
10 | import com.d10ng.compose.ui.base.ToastPosition
11 | import com.d10ng.compose.ui.dialog.builder.DialogBuilder
12 | import com.d10ng.compose.ui.feedback.NotifyType
13 | import com.d10ng.compose.ui.sheet.builder.SheetBuilder
14 | import kotlin.uuid.ExperimentalUuidApi
15 | import kotlin.uuid.Uuid
16 |
17 | /**
18 | * UI ViewModel 管理器
19 | * @Author d10ng
20 | * @Date 2023/9/4 10:24
21 | */
22 | object UiViewModelManager : IUiViewModel {
23 |
24 | private val models = mutableListOf()
25 |
26 | @Composable
27 | fun Init(uiViewModel: UiViewModel = viewModel { UiViewModel() }) {
28 | LaunchedEffect(uiViewModel) {
29 | models.add(uiViewModel)
30 | }
31 | DisposableEffect(uiViewModel) {
32 | onDispose {
33 | models.remove(uiViewModel)
34 | }
35 | }
36 | Box(
37 | modifier = Modifier.fillMaxSize()
38 | ) {
39 | uiViewModel.Init()
40 | }
41 | }
42 |
43 | override fun showToast(msg: String, duration: Long, position: ToastPosition) {
44 | models.forEach { it.showToast(msg, duration, position) }
45 | }
46 |
47 | override fun showSuccessToast(msg: String, duration: Long) {
48 | models.forEach { it.showSuccessToast(msg, duration) }
49 | }
50 |
51 | override fun showFailToast(msg: String, duration: Long) {
52 | models.forEach { it.showFailToast(msg, duration) }
53 | }
54 |
55 | override fun showLoading(text: String) {
56 | models.forEach { it.showLoading(text) }
57 | }
58 |
59 | override fun hideLoading() {
60 | models.forEach { it.hideLoading() }
61 | }
62 |
63 | override fun showNotify(type: NotifyType, text: String, duration: Long) {
64 | models.forEach { it.showNotify(type, text, duration) }
65 | }
66 |
67 | override fun showErrorNotify(text: String, duration: Long) {
68 | models.forEach { it.showErrorNotify(text, duration) }
69 | }
70 |
71 | override fun showSheet(builder: SheetBuilder) {
72 | models.forEach { it.showSheet(builder) }
73 | }
74 |
75 | override fun hideSheet(builder: SheetBuilder) {
76 | models.forEach { it.hideSheet(builder) }
77 | }
78 |
79 | override fun hideAllSheet() {
80 | models.forEach { it.hideAllSheet() }
81 | }
82 |
83 | @OptIn(ExperimentalUuidApi::class)
84 | fun showDialog(builder: DialogBuilder): String {
85 | val id = Uuid.random().toHexString()
86 | models.forEach { it.showDialog(id, builder) }
87 | return id
88 | }
89 |
90 | fun updateDialog(id: String, builder: DialogBuilder) {
91 | models.forEach { it.updateDialog(id, builder) }
92 | }
93 |
94 | fun hideDialog(id: String) {
95 | models.forEach { it.hideDialog(id) }
96 | }
97 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/Modifier.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui
2 |
3 | import androidx.compose.foundation.clickable
4 | import androidx.compose.runtime.mutableStateOf
5 | import androidx.compose.runtime.remember
6 | import androidx.compose.runtime.rememberCoroutineScope
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.composed
9 | import androidx.compose.ui.draw.drawBehind
10 | import androidx.compose.ui.graphics.Color
11 | import androidx.compose.ui.graphics.Paint
12 | import androidx.compose.ui.graphics.PaintingStyle
13 | import androidx.compose.ui.graphics.PathEffect
14 | import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
15 | import androidx.compose.ui.unit.Dp
16 | import androidx.compose.ui.unit.dp
17 | import kotlinx.coroutines.delay
18 | import kotlinx.coroutines.launch
19 |
20 | /**
21 | * 虚线边框
22 | * @Author d10ng
23 | * @Date 2023/9/6 16:09
24 | */
25 |
26 | /**
27 | * 虚线边框
28 | * @receiver Modifier
29 | * @param color Color 边框颜色
30 | * @param width Dp 边框宽度
31 | * @param dashLength Dp 虚线长度
32 | * @param cornerRadiusDp Dp 圆角
33 | * @return Modifier
34 | */
35 | fun Modifier.dashBorder(
36 | color: Color = Color.Black,
37 | width: Dp = 1.dp,
38 | dashLength:Dp = 5.dp,
39 | cornerRadiusDp: Dp = 0.dp
40 | ) = drawBehind {
41 | drawIntoCanvas {
42 | val paint = Paint()
43 | .apply {
44 | strokeWidth = width.toPx()
45 | this.color = color
46 | style = PaintingStyle.Stroke
47 | pathEffect = PathEffect.dashPathEffect(floatArrayOf(dashLength.toPx(), dashLength.toPx()), 0f)
48 | }
49 | it.drawRoundRect(
50 | width.toPx(),
51 | width.toPx(),
52 | size.width - width.toPx(),
53 | size.height - width.toPx(),
54 | cornerRadiusDp.toPx(),
55 | cornerRadiusDp.toPx(),
56 | paint
57 | )
58 | }
59 | }
60 |
61 | /**
62 | * 防抖点击
63 | * @receiver Modifier
64 | * @param onClick Function0
65 | * @param delayMillis Long
66 | * @return Modifier
67 | */
68 | fun Modifier.debounceClick(
69 | onClick: () -> Unit,
70 | delayMillis: Long = 1000L
71 | ): Modifier = composed {
72 | val scope = rememberCoroutineScope()
73 | val clickEnabled = remember { mutableStateOf(true) }
74 |
75 | clickable {
76 | if (clickEnabled.value) {
77 | clickEnabled.value = false
78 | onClick()
79 | scope.launch {
80 | delay(delayMillis)
81 | clickEnabled.value = true
82 | }
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/Shape.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui
2 |
3 | import androidx.compose.foundation.shape.RoundedCornerShape
4 | import androidx.compose.ui.unit.dp
5 |
6 | object AppShape {
7 | object RC {
8 | val Cycle by lazy { RoundedCornerShape(100) }
9 | val v0 by lazy { RoundedCornerShape(0.dp) }
10 | val v1 by lazy { RoundedCornerShape(1.dp) }
11 | val v2 by lazy { RoundedCornerShape(2.dp) }
12 | val v3 by lazy { RoundedCornerShape(3.dp) }
13 | val v4 by lazy { RoundedCornerShape(4.dp) }
14 | val v5 by lazy { RoundedCornerShape(5.dp) }
15 | val v6 by lazy { RoundedCornerShape(6.dp) }
16 | val v7 by lazy { RoundedCornerShape(7.dp) }
17 | val v8 by lazy { RoundedCornerShape(8.dp) }
18 | val v9 by lazy { RoundedCornerShape(9.dp) }
19 | val v10 by lazy { RoundedCornerShape(10.dp) }
20 | val v11 by lazy { RoundedCornerShape(11.dp) }
21 | val v12 by lazy { RoundedCornerShape(12.dp) }
22 | val v13 by lazy { RoundedCornerShape(13.dp) }
23 | val v14 by lazy { RoundedCornerShape(14.dp) }
24 | val v15 by lazy { RoundedCornerShape(15.dp) }
25 | val v16 by lazy { RoundedCornerShape(16.dp) }
26 | val v17 by lazy { RoundedCornerShape(17.dp) }
27 | val v18 by lazy { RoundedCornerShape(18.dp) }
28 | val v19 by lazy { RoundedCornerShape(19.dp) }
29 | val v20 by lazy { RoundedCornerShape(20.dp) }
30 | val v21 by lazy { RoundedCornerShape(21.dp) }
31 | val v22 by lazy { RoundedCornerShape(22.dp) }
32 | val v23 by lazy { RoundedCornerShape(23.dp) }
33 | val v24 by lazy { RoundedCornerShape(24.dp) }
34 | val v25 by lazy { RoundedCornerShape(25.dp) }
35 | val v26 by lazy { RoundedCornerShape(26.dp) }
36 | val v27 by lazy { RoundedCornerShape(27.dp) }
37 | val v28 by lazy { RoundedCornerShape(28.dp) }
38 | val v29 by lazy { RoundedCornerShape(29.dp) }
39 | val v30 by lazy { RoundedCornerShape(30.dp) }
40 | val v31 by lazy { RoundedCornerShape(31.dp) }
41 | val v32 by lazy { RoundedCornerShape(32.dp) }
42 | val v33 by lazy { RoundedCornerShape(33.dp) }
43 | val v34 by lazy { RoundedCornerShape(34.dp) }
44 | val v35 by lazy { RoundedCornerShape(35.dp) }
45 | val v36 by lazy { RoundedCornerShape(36.dp) }
46 | val v37 by lazy { RoundedCornerShape(37.dp) }
47 | val v38 by lazy { RoundedCornerShape(38.dp) }
48 | val v39 by lazy { RoundedCornerShape(39.dp) }
49 | val v40 by lazy { RoundedCornerShape(40.dp) }
50 | val v41 by lazy { RoundedCornerShape(41.dp) }
51 | val v42 by lazy { RoundedCornerShape(42.dp) }
52 | val v43 by lazy { RoundedCornerShape(43.dp) }
53 | val v44 by lazy { RoundedCornerShape(44.dp) }
54 | val v45 by lazy { RoundedCornerShape(45.dp) }
55 | val v46 by lazy { RoundedCornerShape(46.dp) }
56 | val v47 by lazy { RoundedCornerShape(47.dp) }
57 | val v48 by lazy { RoundedCornerShape(48.dp) }
58 | val v49 by lazy { RoundedCornerShape(49.dp) }
59 | val v50 by lazy { RoundedCornerShape(50.dp) }
60 | }
61 | }
62 |
63 | val defaultPaddingSize by lazy { 16.dp }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/dialog/Dialog.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.dialog
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.ColumnScope
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.shape.RoundedCornerShape
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.unit.Dp
15 | import androidx.compose.ui.unit.dp
16 | import com.d10ng.compose.ui.dialog.builder.DialogBuilder
17 | import com.d10ng.compose.ui.feedback.Overlay
18 |
19 | /**
20 | * 弹窗
21 | * @Author d10ng
22 | * @Date 2023/9/7 11:33
23 | */
24 |
25 | @Composable
26 | fun Dialog(
27 | builder: DialogBuilder,
28 | id: String
29 | ) {
30 | Overlay(
31 | onDismiss = {
32 | if (builder.clickOutsideDismiss) DialogBuilder.dismiss(id)
33 | },
34 | contentAlignment = builder.contentAlignment
35 | ) {
36 | builder.Build(id)
37 | }
38 | }
39 |
40 | @Composable
41 | fun DialogBox(
42 | color: Color = Color.White,
43 | shape: RoundedCornerShape = RoundedCornerShape(12.dp),
44 | margin: Dp = 22.dp,
45 | padding: Dp = 25.dp,
46 | content: @Composable () -> Unit
47 | ) {
48 | Box(
49 | modifier = Modifier
50 | .fillMaxWidth()
51 | .padding(margin)
52 | .background(color, shape)
53 | .padding(padding)
54 | ) {
55 | content()
56 | }
57 | }
58 |
59 | @Composable
60 | fun DialogColumn(
61 | color: Color = Color.White,
62 | shape: RoundedCornerShape = RoundedCornerShape(12.dp),
63 | margin: Dp = 22.dp,
64 | padding: Dp = 25.dp,
65 | content: @Composable ColumnScope.() -> Unit
66 | ) {
67 | DialogBox(
68 | color = color,
69 | shape = shape,
70 | margin = margin,
71 | padding = padding
72 | ) {
73 | Column(
74 | modifier = Modifier
75 | .fillMaxWidth(),
76 | horizontalAlignment = Alignment.CenterHorizontally
77 | ) {
78 | content()
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/dialog/builder/DialogBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.dialog.builder
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.Alignment
5 | import com.d10ng.compose.model.UiViewModelManager
6 |
7 | /**
8 | * 弹窗构建器
9 | * @Author d10ng
10 | * @Date 2023/9/7 11:53
11 | */
12 | abstract class DialogBuilder(
13 | // 是否允许点击外部隐藏弹窗
14 | var clickOutsideDismiss: Boolean = false,
15 | // 弹窗内容所在位置
16 | var contentAlignment: Alignment = Alignment.Center
17 | ) {
18 |
19 | companion object {
20 | /**
21 | * 隐藏弹窗
22 | * @param id String 弹窗唯一标识
23 | */
24 | fun dismiss(id: String) {
25 | UiViewModelManager.hideDialog(id)
26 | }
27 | }
28 |
29 | /**
30 | * 构建弹窗内容
31 | * @param id String 弹窗唯一标识
32 | */
33 | @Composable
34 | abstract fun Build(id: String)
35 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/dialog/builder/ProgressDialogBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.dialog.builder
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.foundation.layout.height
5 | import androidx.compose.foundation.layout.padding
6 | import androidx.compose.material3.LinearProgressIndicator
7 | import androidx.compose.material3.Text
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.remember
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.graphics.StrokeCap
12 | import androidx.compose.ui.unit.dp
13 | import com.d10ng.compose.ui.AppColor
14 | import com.d10ng.compose.ui.AppText
15 | import com.d10ng.compose.ui.dialog.DialogColumn
16 |
17 | /**
18 | * 进度加载对话框构建器
19 | * @Author d10ng
20 | * @Date 2023/9/12 09:49
21 | */
22 | data class ProgressDialogBuilder(
23 | // 标题
24 | private val title: String = "请稍候...",
25 | // 进度
26 | private val progress: Long = 0,
27 | // 最大值
28 | private val max: Long = 100,
29 | // 类型
30 | private val type: Type = Type.PERCENTAGE,
31 | ) : DialogBuilder(clickOutsideDismiss = false) {
32 |
33 | enum class Type {
34 | // 显示百分比
35 | PERCENTAGE,
36 |
37 | // 显示进度和最大值
38 | PROGRESS_AND_MAX,
39 |
40 | // 什么都不显示
41 | NONE
42 | }
43 |
44 | @Composable
45 | override fun Build(id: String) {
46 | // 根据类型换算文本内容
47 | val content = remember(type, progress, max) {
48 | when (type) {
49 | Type.PERCENTAGE -> "${((progress * 100.0) / max).toInt()}%"
50 | Type.PROGRESS_AND_MAX -> "${progress}/${max}"
51 | Type.NONE -> ""
52 | }
53 | }
54 | DialogColumn {
55 | // 标题
56 | if (title.isNotEmpty()) {
57 | TipsDialogBuilder.TitleText(text = title)
58 | }
59 | // 内容
60 | if (content.isNotEmpty()) {
61 | Text(text = content, style = AppText.Normal.Body.big)
62 | }
63 | // 进度
64 | LinearProgressIndicator(
65 | progress = { (progress * 1.0f) / max },
66 | modifier = Modifier
67 | .padding(top = 16.dp)
68 | .fillMaxWidth()
69 | .height(12.dp),
70 | color = AppColor.Main.primary,
71 | trackColor = AppColor.Neutral.line,
72 | strokeCap = StrokeCap.Round,
73 | )
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/dialog/builder/ResultDialogBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.dialog.builder
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.fillMaxWidth
5 | import androidx.compose.foundation.layout.padding
6 | import androidx.compose.foundation.layout.size
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.runtime.rememberCoroutineScope
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.layout.ContentScale
11 | import androidx.compose.ui.unit.dp
12 | import com.d10ng.compose.resources.Res
13 | import com.d10ng.compose.resources.ic_round_error_160
14 | import com.d10ng.compose.resources.ic_round_success_160
15 | import com.d10ng.compose.ui.AppShape
16 | import com.d10ng.compose.ui.base.Button
17 | import com.d10ng.compose.ui.base.ButtonType
18 | import com.d10ng.compose.ui.dialog.DialogColumn
19 | import kotlinx.coroutines.CoroutineScope
20 | import kotlinx.coroutines.launch
21 | import org.jetbrains.compose.resources.DrawableResource
22 | import org.jetbrains.compose.resources.painterResource
23 |
24 | /**
25 | * 结果弹窗构建器
26 | * @Author d10ng
27 | * @Date 2023/11/21 14:10
28 | */
29 | class ResultDialogBuilder(
30 | // 标题
31 | private val title: String = "提示",
32 | // 内容
33 | private val content: String,
34 | // 状态
35 | private val status: Status = Status.SUCCESS,
36 | // 确定按钮文字
37 | private val confirmText: String = "确定",
38 | // 取消按钮文字
39 | private val cancelText: String = "取消",
40 | // 是否显示取消按钮
41 | private val showCancel: Boolean = true,
42 | // 确定按钮点击事件,返回true则隐藏弹窗
43 | private val onConfirmClick: suspend CoroutineScope.() -> Boolean = { true },
44 | // 取消按钮点击事件,返回true则隐藏弹窗
45 | private val onCancelClick: suspend CoroutineScope.() -> Boolean = { true }
46 | ): DialogBuilder() {
47 |
48 | enum class Status(val iconResource: DrawableResource) {
49 | SUCCESS(Res.drawable.ic_round_success_160),
50 | ERROR(Res.drawable.ic_round_error_160),
51 | }
52 |
53 | @Composable
54 | override fun Build(id: String) {
55 | DialogColumn {
56 | // 标题
57 | TipsDialogBuilder.TitleText(text = title)
58 | // 图标
59 | Image(
60 | painter = painterResource(resource = status.iconResource),
61 | contentDescription = null,
62 | modifier = Modifier.padding(bottom = 12.dp).size(100.dp),
63 | contentScale = ContentScale.FillBounds
64 | )
65 | // 内容
66 | TipsDialogBuilder.ContentText(text = content)
67 | if (showCancel) {
68 | ConfirmDialogBuilder.ButtonRow(
69 | id = id,
70 | cancelText = cancelText,
71 | confirmText = confirmText,
72 | onCancelClick = onCancelClick,
73 | onConfirmClick = onConfirmClick
74 | )
75 | } else {
76 | val scope = rememberCoroutineScope()
77 | Button(
78 | text = confirmText,
79 | modifier = Modifier
80 | .fillMaxWidth(),
81 | shape = AppShape.RC.Cycle,
82 | type = ButtonType.PRIMARY
83 | ) {
84 | scope.launch {
85 | if (onConfirmClick(this)) dismiss(id)
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/dialog/builder/TipsDialogBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.dialog.builder
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.foundation.layout.padding
5 | import androidx.compose.material3.Text
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.runtime.rememberCoroutineScope
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.text.TextStyle
10 | import androidx.compose.ui.text.style.TextAlign
11 | import androidx.compose.ui.unit.dp
12 | import com.d10ng.compose.ui.AppShape
13 | import com.d10ng.compose.ui.AppText
14 | import com.d10ng.compose.ui.base.Button
15 | import com.d10ng.compose.ui.base.ButtonType
16 | import com.d10ng.compose.ui.dialog.DialogColumn
17 | import kotlinx.coroutines.CoroutineScope
18 | import kotlinx.coroutines.launch
19 |
20 | /**
21 | * 提示弹窗构建器
22 | * @Author d10ng
23 | * @Date 2023/9/7 13:38
24 | */
25 | open class TipsDialogBuilder(
26 | // 标题
27 | private val title: String = "提示",
28 | // 标题Align
29 | private val titleAlign: TextAlign = TextAlign.Center,
30 | // 内容
31 | private val content: String,
32 | // 内容Align
33 | private val contentAlign: TextAlign = TextAlign.Center,
34 | // 内容插槽
35 | private val contentSlot: @Composable () -> Unit = {},
36 | // 按钮文字
37 | private val buttonText: String = "确定",
38 | // 弹窗类型
39 | private val type: Type = Type.Default,
40 | // 按钮点击事件,返回true则隐藏弹窗
41 | private val onButtonClick: suspend CoroutineScope.() -> Boolean = { true }
42 | ): DialogBuilder() {
43 |
44 | enum class Type(val titleStyle: TextStyle, val contentStyle: TextStyle, val buttonType: ButtonType) {
45 | Default(AppText.Bold.Title.large, AppText.Normal.Body.default, ButtonType.PRIMARY),
46 | Success(AppText.Bold.Success.large, AppText.Normal.Body.default, ButtonType.SUCCESS),
47 | Warning(AppText.Bold.Assist.large, AppText.Normal.Body.default, ButtonType.WARNING),
48 | Danger(AppText.Bold.Error.large, AppText.Normal.Body.default, ButtonType.DANGER),
49 | }
50 |
51 | @Composable
52 | override fun Build(id: String) {
53 | val scope = rememberCoroutineScope()
54 | DialogColumn {
55 | // 标题
56 | if (title.isNotEmpty()) {
57 | TitleText(title, type.titleStyle, titleAlign)
58 | }
59 | // 内容
60 | contentSlot()
61 | if (content.isNotEmpty()) {
62 | ContentText(content, type.contentStyle, contentAlign)
63 | }
64 | // 按钮
65 | Button(
66 | text = buttonText,
67 | modifier = Modifier
68 | .fillMaxWidth(),
69 | shape = AppShape.RC.Cycle,
70 | type = type.buttonType
71 | ) {
72 | scope.launch {
73 | if (onButtonClick(this)) dismiss(id)
74 | }
75 | }
76 | }
77 | }
78 |
79 | companion object {
80 | @Composable
81 | fun TitleText(
82 | text: String,
83 | style: TextStyle = AppText.Bold.Title.large,
84 | textAlign: TextAlign = TextAlign.Center
85 | ) {
86 | BasicText(text, style, textAlign)
87 | }
88 |
89 | @Composable
90 | fun ContentText(
91 | text: String,
92 | style: TextStyle = AppText.Normal.Body.default,
93 | textAlign: TextAlign = TextAlign.Center
94 | ) {
95 | BasicText(text, style, textAlign)
96 | }
97 |
98 | @Composable
99 | private fun BasicText(
100 | text: String,
101 | style: TextStyle,
102 | textAlign: TextAlign = TextAlign.Center
103 | ) {
104 | Text(
105 | text = text,
106 | style = style,
107 | modifier = Modifier
108 | .fillMaxWidth()
109 | .padding(bottom = 30.dp),
110 | textAlign = textAlign
111 | )
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/feedback/Notify.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.feedback
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.foundation.layout.statusBarsPadding
8 | import androidx.compose.material3.Text
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.graphics.Color
13 | import androidx.compose.ui.text.style.TextOverflow
14 | import androidx.compose.ui.unit.dp
15 | import com.d10ng.compose.ui.AppColor
16 | import com.d10ng.compose.ui.AppShape
17 | import com.d10ng.compose.ui.AppText
18 | import com.d10ng.compose.ui.defaultPaddingSize
19 |
20 | /**
21 | * 消息提示
22 | * @Author d10ng
23 | * @Date 2023/9/12 18:11
24 | */
25 |
26 | enum class NotifyType(val color: Color) {
27 | Primary(AppColor.Main.primary),
28 | Success(AppColor.Func.success),
29 | Warning(AppColor.Func.assist),
30 | Error(AppColor.Func.error),
31 | }
32 |
33 | /**
34 | * 消息提示
35 | * @param type NotifyType 消息类型
36 | * @param text String 消息内容
37 | */
38 | @Composable
39 | fun Notify(
40 | type: NotifyType = NotifyType.Primary,
41 | text: String
42 | ) {
43 | Box(
44 | modifier = Modifier
45 | .fillMaxWidth()
46 | .padding(horizontal = defaultPaddingSize, vertical = 8.dp)
47 | .statusBarsPadding()
48 | .background(type.color, AppShape.RC.v8)
49 | .padding(horizontal = defaultPaddingSize, vertical = 8.dp),
50 | contentAlignment = Alignment.Center
51 | ) {
52 | Text(
53 | text = text,
54 | style = AppText.Normal.Surface.default,
55 | maxLines = 3,
56 | overflow = TextOverflow.Ellipsis
57 | )
58 | }
59 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/feedback/Overlay.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.feedback
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.gestures.detectTapGestures
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.BoxScope
7 | import androidx.compose.foundation.layout.fillMaxSize
8 | import androidx.compose.foundation.layout.imePadding
9 | import androidx.compose.foundation.layout.statusBarsPadding
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.input.pointer.pointerInput
15 | import com.d10ng.compose.utils.BackHandler
16 |
17 | /**
18 | * 遮罩层
19 | * @Author d10ng
20 | * @Date 2023/9/7 11:36
21 | */
22 |
23 | @Composable
24 | fun Overlay(
25 | onDismiss: () -> Unit = {},
26 | contentAlignment: Alignment = Alignment.Center,
27 | content: @Composable BoxScope.() -> Unit = {}
28 | ) {
29 | Box(
30 | modifier = Modifier
31 | .fillMaxSize()
32 | .background(Color.Black.copy(alpha = 0.5f))
33 | .pointerInput(Unit) {
34 | // 拦截外部的点击
35 | detectTapGestures { onDismiss.invoke() }
36 | }
37 | .statusBarsPadding()
38 | .imePadding(),
39 | content = content,
40 | contentAlignment = contentAlignment
41 | )
42 | BackHandler {
43 | onDismiss.invoke()
44 | }
45 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/form/Checkbox.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.form
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.border
5 | import androidx.compose.foundation.clickable
6 | import androidx.compose.foundation.layout.Box
7 | import androidx.compose.foundation.layout.fillMaxSize
8 | import androidx.compose.foundation.layout.size
9 | import androidx.compose.material3.Icon
10 | import androidx.compose.material3.MaterialTheme
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.remember
13 | import androidx.compose.ui.Alignment
14 | import androidx.compose.ui.Modifier
15 | import androidx.compose.ui.draw.clip
16 | import androidx.compose.ui.graphics.Color
17 | import androidx.compose.ui.graphics.Shape
18 | import androidx.compose.ui.unit.Dp
19 | import androidx.compose.ui.unit.dp
20 | import com.d10ng.compose.resources.Res
21 | import com.d10ng.compose.resources.ic_round_check_24
22 | import com.d10ng.compose.ui.AppColor
23 | import com.d10ng.compose.ui.AppShape
24 | import com.d10ng.compose.utils.next
25 | import org.jetbrains.compose.resources.painterResource
26 |
27 | /**
28 | * Checkbox 复选框
29 | * @Author d10ng
30 | * @Date 2023/11/16 02:34
31 | */
32 |
33 | enum class CheckboxType(val shape: Shape) {
34 | // 方形
35 | SQUARE(AppShape.RC.v4),
36 | // 圆形
37 | CIRCLE(AppShape.RC.Cycle)
38 | }
39 |
40 | /**
41 | * 复选框
42 | * @param modifier Modifier 外部传入的修饰符
43 | * @param checked Boolean 是否选中
44 | * @param onCheckedChange Function1 选中状态切换
45 | * @param disabled Boolean 是否禁用
46 | * @param size Dp 大小
47 | * @param type CheckboxType 复选框类型
48 | * @param activeColor Color 选中颜色
49 | * @param inactiveColor Color 未选中颜色
50 | * @param disabledColor Color 禁用颜色
51 | */
52 | @Composable
53 | fun Checkbox(
54 | modifier: Modifier = Modifier,
55 | checked: Boolean,
56 | onCheckedChange: (Boolean) -> Unit = {},
57 | disabled: Boolean = false,
58 | size: Dp = 22.dp,
59 | type: CheckboxType = CheckboxType.SQUARE,
60 | activeColor: Color = MaterialTheme.colorScheme.primary,
61 | inactiveColor: Color = AppColor.Neutral.tips,
62 | disabledColor: Color = AppColor.Neutral.hint,
63 | ) {
64 | val bgColor = remember(disabled, disabledColor, checked, activeColor, inactiveColor) {
65 | when {
66 | disabled && checked -> disabledColor
67 | disabled -> disabledColor.next(0.5)
68 | checked -> activeColor
69 | else -> Color.Transparent
70 | }
71 | }
72 | Box(modifier = modifier.size(size)) {
73 | Box(
74 | modifier = Modifier
75 | .fillMaxSize()
76 | .background(bgColor, type.shape)
77 | .clip(type.shape)
78 | .then(
79 | if (checked.not()) Modifier
80 | .border(1.dp, if (disabled) disabledColor else inactiveColor, type.shape)
81 | else Modifier
82 | )
83 | .clickable(disabled.not()) { onCheckedChange(checked.not()) },
84 | contentAlignment = Alignment.Center
85 | ) {
86 | if (checked) {
87 | val tintColor = remember {
88 | if (disabled) disabledColor.next(0.5) else Color.White
89 | }
90 | Icon(
91 | painter = painterResource(resource = Res.drawable.ic_round_check_24),
92 | contentDescription = null,
93 | modifier = Modifier.fillMaxSize(),
94 | tint = tintColor,
95 | )
96 | }
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/form/Radio.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.form
2 |
3 | import androidx.compose.foundation.clickable
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.Row
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.layout.size
10 | import androidx.compose.material3.RadioButton
11 | import androidx.compose.material3.RadioButtonDefaults
12 | import androidx.compose.material3.Text
13 | import androidx.compose.runtime.Composable
14 | import androidx.compose.ui.Alignment
15 | import androidx.compose.ui.Modifier
16 | import androidx.compose.ui.unit.dp
17 | import com.d10ng.compose.ui.AppColor
18 | import com.d10ng.compose.ui.AppText
19 | import com.d10ng.compose.ui.defaultPaddingSize
20 | import com.d10ng.compose.ui.show.HorizontalDivider
21 | import com.d10ng.compose.utils.next
22 |
23 | /**
24 | * 单选按钮
25 | * @Author d10ng
26 | * @Date 2023/9/8 17:03
27 | */
28 |
29 | /**
30 | * 单选单元格
31 | * @param modifier Modifier 修饰符
32 | * @param label String 标题
33 | * @param selected Boolean 是否选中
34 | * @param disabled Boolean 是否禁用
35 | * @param border Boolean 是否显示边框
36 | * @param onClick Function0
37 | */
38 | @Composable
39 | fun RadioCell(
40 | modifier: Modifier = Modifier,
41 | label: String,
42 | selected: Boolean,
43 | disabled: Boolean = false,
44 | border: Boolean = true,
45 | onClick: () -> Unit = {}
46 | ) {
47 | Column(
48 | modifier = modifier
49 | .clickable { onClick() }
50 | .padding(horizontal = defaultPaddingSize)
51 | ) {
52 | Row(
53 | modifier = Modifier
54 | .fillMaxWidth()
55 | .padding(vertical = defaultPaddingSize),
56 | verticalAlignment = Alignment.CenterVertically
57 | ) {
58 | // 标题
59 | Text(
60 | text = label,
61 | style = AppText.Normal.Title.default,
62 | color = AppColor.Neutral.title.next(if (disabled) 0.5 else 0.0)
63 | )
64 | // 间隔
65 | Box(modifier = Modifier.weight(1f))
66 | // 单选按钮
67 | RadioButton(
68 | selected = selected,
69 | onClick = onClick,
70 | colors = RadioButtonDefaults.colors(
71 | selectedColor = AppColor.Main.primary,
72 | unselectedColor = AppColor.Neutral.tips,
73 | disabledSelectedColor = AppColor.Main.primary.next(0.5),
74 | disabledUnselectedColor = AppColor.Neutral.tips.next(0.5),
75 | ),
76 | enabled = !disabled,
77 | modifier = Modifier.size(18.dp)
78 | )
79 | }
80 | if (border) HorizontalDivider()
81 | }
82 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/form/Switch.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.form
2 |
3 | import androidx.compose.foundation.layout.height
4 | import androidx.compose.foundation.layout.padding
5 | import androidx.compose.material3.CircularProgressIndicator
6 | import androidx.compose.material3.Icon
7 | import androidx.compose.material3.SwitchDefaults
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.remember
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.draw.scale
12 | import androidx.compose.ui.graphics.Color
13 | import androidx.compose.ui.graphics.StrokeCap
14 | import androidx.compose.ui.unit.Dp
15 | import androidx.compose.ui.unit.dp
16 | import com.d10ng.compose.ui.AppColor
17 | import com.d10ng.compose.utils.next
18 | import org.jetbrains.compose.resources.DrawableResource
19 | import org.jetbrains.compose.resources.painterResource
20 |
21 | /**
22 | * Switch 开关
23 | * @Author d10ng
24 | * @Date 2023/9/6 14:22
25 | */
26 |
27 | /**
28 | * Switch 开关
29 | * @param modifier Modifier
30 | * @param checked Boolean 是否选中
31 | * @param onCheckedChange Function1 选中状态变化
32 | * @param disabled Boolean 是否禁用
33 | * @param loading Boolean 是否加载中
34 | * @param activeColor Color 选中颜色
35 | * @param inactiveColor Color 未选中颜色
36 | * @param iconResource DrawableResource? 图标ID
37 | * @param size Dp 大小
38 | */
39 | @Composable
40 | fun Switch(
41 | modifier: Modifier = Modifier,
42 | checked: Boolean,
43 | onCheckedChange: (Boolean) -> Unit,
44 | disabled: Boolean = false,
45 | loading: Boolean = false,
46 | activeColor: Color = AppColor.Main.primary,
47 | inactiveColor: Color = AppColor.Neutral.line,
48 | iconResource: DrawableResource? = null,
49 | size: Dp = 32.dp
50 | ) {
51 | val color = SwitchDefaults.colors(
52 | checkedThumbColor = Color.White,
53 | uncheckedThumbColor = Color.White,
54 | disabledCheckedThumbColor = Color.White.next(0.2),
55 | disabledUncheckedThumbColor = Color.White.next(0.2),
56 | checkedTrackColor = activeColor,
57 | uncheckedTrackColor = inactiveColor,
58 | disabledCheckedTrackColor = activeColor.next(0.2),
59 | disabledUncheckedTrackColor = inactiveColor.next(0.2),
60 | checkedBorderColor = activeColor,
61 | uncheckedBorderColor = inactiveColor,
62 | disabledCheckedBorderColor = activeColor.next(0.2),
63 | disabledUncheckedBorderColor = inactiveColor.next(0.2),
64 | checkedIconColor = activeColor,
65 | uncheckedIconColor = inactiveColor,
66 | disabledCheckedIconColor = activeColor.next(0.2),
67 | disabledUncheckedIconColor = inactiveColor.next(0.2),
68 | )
69 | val loadingColor = remember(checked, disabled, activeColor, inactiveColor) {
70 | val cc = if (checked) activeColor else inactiveColor
71 | if (disabled) cc.next(0.2) else cc
72 | }
73 | val scale = remember(size) {
74 | size.value / 32f
75 | }
76 | androidx.compose.material3.Switch(
77 | modifier = modifier
78 | .scale(scale)
79 | .height(size),
80 | checked = checked,
81 | onCheckedChange = onCheckedChange,
82 | colors = color,
83 | enabled = !disabled && !loading,
84 | thumbContent = {
85 | if (loading && iconResource == null) {
86 | CircularProgressIndicator(
87 | modifier = Modifier.padding(5.dp),
88 | color = loadingColor,
89 | strokeCap = StrokeCap.Round,
90 | strokeWidth = 1.5.dp
91 | )
92 | }
93 | if (iconResource != null) {
94 | Icon(
95 | painter = painterResource(resource = iconResource),
96 | contentDescription = null,
97 | tint = loadingColor,
98 | modifier = Modifier.padding(5.dp),
99 | )
100 | }
101 | }
102 | )
103 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/form/TimePicker.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.form
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.remember
5 | import androidx.compose.ui.text.TextStyle
6 | import com.d10ng.compose.ui.AppText
7 |
8 | /**
9 | * 时间选择器
10 | * @Author d10ng
11 | * @Date 2023/9/11 19:11
12 | */
13 |
14 | enum class TimePickerMode(
15 | val getItems: (Set, Set, Set) -> List>,
16 | val getSelectedItems: (String, String, String) -> List,
17 | val getDate: (List) -> Int,
18 | val getDateList: (Int) -> List,
19 | ) {
20 | // 时分秒
21 | HMS(
22 | { h, m, s -> listOf(h, m, s) },
23 | { h, m, s -> listOf(h, m, s) },
24 | { l -> l[0].toInt() * 3600 + l[1].toInt() * 60 + l[2].toInt() },
25 | { v -> listOf(v.hour(), v.minute(), v.second()) }
26 | ),
27 |
28 | // 时分
29 | HM(
30 | { h, m, _ -> listOf(h, m) },
31 | { h, m, _ -> listOf(h, m) },
32 | { l -> l[0].toInt() * 3600 + l[1].toInt() * 60 },
33 | { v -> listOf(v.hour(), v.minute()) }
34 | ),
35 | }
36 |
37 | /**
38 | * 时间选择器
39 | * @param value Int 选中的时间,单位秒,0-86399,小时*3600+分钟*60+秒
40 | * @param onValueChange Function2, Unit> 选中时间改变事件,单位秒,0-86399,小时*3600+分钟*60+秒,Int为选中的时间,List为选中的时间列表
41 | * @param start Int 开始时间,单位秒,0-86399,小时*3600+分钟*60+秒
42 | * @param endInclude Int 结束时间,包含,单位秒,0-86399,小时*3600+分钟*60+秒
43 | * @param textStyle TextStyle 文本样式
44 | * @param mode TimePickerMode 选择器模式
45 | * @param itemText Function2 选项文本
46 | */
47 | @Composable
48 | fun TimePicker(
49 | value: Int = 0,
50 | onValueChange: (Int, List) -> Unit,
51 | start: Int = 0,
52 | endInclude: Int = 86399,
53 | textStyle: TextStyle = AppText.Normal.Title.default,
54 | mode: TimePickerMode = TimePickerMode.HMS,
55 | itemText: (Int, String) -> String = { _, item -> item },
56 | ) {
57 | // 小时列表
58 | val hours = remember(start, endInclude) {
59 | (start.hour()..endInclude.hour()).map {
60 | it.toString().padStart(2, '0')
61 | }.toSet()
62 | }
63 | // 选择小时
64 | val hour = remember(value) {
65 | value.hour()
66 | }
67 | // 分钟列表
68 | val minutes = remember(hour, start, endInclude) {
69 | val startMinute = if (hour == start.hour()) start.minute() else 0
70 | val endMinute = if (hour == endInclude.hour()) endInclude.minute() else 59
71 | (startMinute..endMinute).map {
72 | it.toString().padStart(2, '0')
73 | }.toSet()
74 | }
75 | // 选择分钟
76 | val minute = remember(value) {
77 | value.minute()
78 | }
79 | // 秒列表
80 | val seconds = remember(hour, minute, start, endInclude) {
81 | val startSecond =
82 | if (hour == start.hour() && minute == start.minute()) start.second() else 0
83 | val endSecond =
84 | if (hour == endInclude.hour() && minute == endInclude.minute()) endInclude.second() else 59
85 | (startSecond..endSecond).map {
86 | it.toString().padStart(2, '0')
87 | }.toSet()
88 | }
89 | // 选择秒
90 | val second = remember(value) {
91 | value.second()
92 | }
93 |
94 | val items = remember(mode, hours, minutes, seconds) {
95 | mode.getItems(hours, minutes, seconds)
96 | }
97 | val selectedItems = remember(mode, hour, minute, second) {
98 | mode.getSelectedItems(
99 | hour.toString().padStart(2, '0'),
100 | minute.toString().padStart(2, '0'),
101 | second.toString().padStart(2, '0')
102 | )
103 | }
104 |
105 | MultiPicker(
106 | items = items,
107 | itemText = itemText,
108 | textStyle = textStyle,
109 | selectedItems = selectedItems,
110 | onValueChange = {
111 | val time = mode.getDate(it).coerceAtLeast(start).coerceAtMost(endInclude)
112 | onValueChange(time, mode.getDateList(time))
113 | }
114 | )
115 | }
116 |
117 | internal fun Int.hour(): Int = this / 3600
118 | internal fun Int.minute(): Int = this / 60 % 60
119 | internal fun Int.second(): Int = this % 60
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/sheet/builder/ActionSheetBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.sheet.builder
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.height
9 | import androidx.compose.foundation.layout.navigationBarsPadding
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.material3.Text
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.ui.Alignment
14 | import androidx.compose.ui.Modifier
15 | import androidx.compose.ui.graphics.Color
16 | import androidx.compose.ui.text.TextStyle
17 | import androidx.compose.ui.unit.dp
18 | import com.d10ng.compose.ui.AppColor
19 | import com.d10ng.compose.ui.AppText
20 | import com.d10ng.compose.ui.sheet.SheetBox
21 |
22 | /**
23 | * 动作面板构建器
24 | * @Author d10ng
25 | * @Date 2023/9/8 18:07
26 | */
27 | class ActionSheetBuilder(
28 | // 选项
29 | private val items: Set,
30 | // 选项文本
31 | private val itemText: (T) -> String = { it.toString() },
32 | // 选项文本样式
33 | private val itemStyle: (T) -> TextStyle = { AppText.Normal.Title.default },
34 | // 取消文本
35 | private val cancelText: String = "取消",
36 | // 选项点击事件
37 | private val onItemClick: (T) -> Unit = {},
38 | ): SheetBuilder() {
39 | @Composable
40 | override fun Build() {
41 | SheetBox {
42 | Column(
43 | modifier = Modifier
44 | .fillMaxWidth()
45 | .background(AppColor.Neutral.card)
46 | .padding(top = 16.dp)
47 | .navigationBarsPadding()
48 | ) {
49 | // 选项
50 | items.forEach { item ->
51 | ItemView(
52 | text = itemText(item),
53 | style = itemStyle(item)
54 | ) {
55 | onItemClick(item)
56 | dismiss()
57 | }
58 | }
59 | // 间隔
60 | Box(modifier = Modifier.height(8.dp))
61 | // 取消按钮
62 | ItemView(
63 | text = cancelText
64 | ) {
65 | dismiss()
66 | }
67 | }
68 | }
69 | }
70 |
71 | @Composable
72 | private fun ItemView(
73 | text: String,
74 | style: TextStyle = AppText.Normal.Title.default,
75 | onClick: () -> Unit
76 | ) {
77 | Box(
78 | modifier = Modifier
79 | .padding(bottom = 1.dp)
80 | .fillMaxWidth()
81 | .height(48.dp)
82 | .background(Color.White)
83 | .clickable { onClick() },
84 | contentAlignment = Alignment.Center
85 | ) {
86 | Text(
87 | text = text,
88 | style = style
89 | )
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/sheet/builder/DatePickerSheetBuilder.kt:
--------------------------------------------------------------------------------
1 | @file:OptIn(ExperimentalTime::class)
2 |
3 | package com.d10ng.compose.ui.sheet.builder
4 |
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.runtime.getValue
7 | import androidx.compose.runtime.mutableLongStateOf
8 | import androidx.compose.runtime.remember
9 | import androidx.compose.runtime.setValue
10 | import androidx.compose.ui.text.TextStyle
11 | import com.d10ng.compose.ui.AppText
12 | import com.d10ng.compose.ui.form.DatePicker
13 | import com.d10ng.compose.ui.form.DatePickerMode
14 | import com.d10ng.compose.ui.sheet.SheetColumn
15 | import kotlinx.coroutines.CoroutineScope
16 | import kotlin.time.ExperimentalTime
17 |
18 | /**
19 | * 日期选择器构建器
20 | * @Author d10ng
21 | * @Date 2023/9/11 17:44
22 | */
23 | class DatePickerSheetBuilder(
24 | // 标题
25 | private val title: String = "请选择",
26 | // 选中的日期
27 | private val value: Long,
28 | // 开始日期
29 | private val start: Long = 0,
30 | // 结束日期,包含
31 | private val endInclude: Long = kotlin.time.Clock.System.now().toEpochMilliseconds(),
32 | // 文本样式
33 | private val textStyle: TextStyle = AppText.Normal.Title.default,
34 | // 选择器模式
35 | private val mode: DatePickerMode = DatePickerMode.YMD,
36 | // 选项文本
37 | private val itemText: (Int, String) -> String = { _, item -> item },
38 | // 取消文本
39 | private val cancelText: String = "取消",
40 | // 确定文本
41 | private val confirmText: String = "确定",
42 | // 取消按钮点击事件,返回true则隐藏弹窗
43 | private val onCancelClick: suspend CoroutineScope.() -> Boolean = { true },
44 | // 确定按钮点击事件,返回true则隐藏弹窗
45 | private val onConfirmClick: suspend CoroutineScope.(Long) -> Boolean = { true },
46 | ): SheetBuilder() {
47 | @Composable
48 | override fun Build() {
49 | var selected by remember(value) {
50 | mutableLongStateOf(value)
51 | }
52 | SheetColumn {
53 | // 标题栏
54 | TitleBar(
55 | title = title,
56 | cancelText = cancelText,
57 | confirmText = confirmText,
58 | onCancelClick = onCancelClick,
59 | onConfirmClick = { onConfirmClick(selected) }
60 | )
61 | // 选项
62 | DatePicker(
63 | value = selected,
64 | onValueChange = { selected = it },
65 | start = start,
66 | endInclude = endInclude,
67 | textStyle = textStyle,
68 | mode = mode,
69 | itemText = itemText
70 | )
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/sheet/builder/MultiPickerSheetBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.sheet.builder
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.getValue
5 | import androidx.compose.runtime.mutableStateOf
6 | import androidx.compose.runtime.remember
7 | import androidx.compose.runtime.setValue
8 | import androidx.compose.ui.text.TextStyle
9 | import com.d10ng.compose.ui.AppText
10 | import com.d10ng.compose.ui.form.MultiPicker
11 | import com.d10ng.compose.ui.sheet.SheetColumn
12 | import kotlinx.coroutines.CoroutineScope
13 |
14 | /**
15 | * 多列滚轮选择器构建器
16 | * @Author d10ng
17 | * @Date 2023/9/11 15:52
18 | */
19 | class MultiPickerSheetBuilder(
20 | // 标题
21 | private val title: String = "请选择",
22 | // 选项
23 | private val items: List>,
24 | // 选项文本
25 | private val itemText: (Int, T) -> String = { _, item -> item.toString() },
26 | // 文本样式
27 | private val textStyle: TextStyle = AppText.Normal.Title.default,
28 | // 选中的项
29 | private val selectedItems: List = items.map { it.first() },
30 | // 取消文本
31 | private val cancelText: String = "取消",
32 | // 确定文本
33 | private val confirmText: String = "确定",
34 | // 取消按钮点击事件,返回true则隐藏弹窗
35 | private val onCancelClick: suspend CoroutineScope.() -> Boolean = { true },
36 | // 确定按钮点击事件,返回true则隐藏弹窗
37 | private val onConfirmClick: suspend CoroutineScope.(List) -> Boolean = { true },
38 | ): SheetBuilder() {
39 | @Composable
40 | override fun Build() {
41 | var selected by remember(selectedItems) {
42 | mutableStateOf(selectedItems)
43 | }
44 | SheetColumn {
45 | // 标题栏
46 | TitleBar(
47 | title = title,
48 | cancelText = cancelText,
49 | confirmText = confirmText,
50 | onCancelClick = onCancelClick,
51 | onConfirmClick = { onConfirmClick(selected) }
52 | )
53 | // 选项
54 | MultiPicker(
55 | items = items,
56 | itemText = itemText,
57 | textStyle = textStyle,
58 | selectedItems = selected,
59 | onValueChange = { selected = it }
60 | )
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/sheet/builder/RadioSheetBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.sheet.builder
2 |
3 | import androidx.compose.foundation.layout.Box
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.layout.height
7 | import androidx.compose.foundation.rememberScrollState
8 | import androidx.compose.foundation.verticalScroll
9 | import androidx.compose.material3.Text
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.runtime.getValue
12 | import androidx.compose.runtime.mutableStateOf
13 | import androidx.compose.runtime.remember
14 | import androidx.compose.runtime.rememberCoroutineScope
15 | import androidx.compose.runtime.setValue
16 | import androidx.compose.ui.Alignment
17 | import androidx.compose.ui.Modifier
18 | import androidx.compose.ui.text.style.TextAlign
19 | import androidx.compose.ui.unit.dp
20 | import com.d10ng.compose.ui.AppText
21 | import com.d10ng.compose.ui.form.RadioCell
22 | import com.d10ng.compose.ui.sheet.SheetColumn
23 | import kotlinx.coroutines.CoroutineScope
24 | import kotlinx.coroutines.launch
25 |
26 | /**
27 | * 单选面板构建器
28 | * @Author d10ng
29 | * @Date 2023/9/8 18:08
30 | */
31 | class RadioSheetBuilder(
32 | // 标题
33 | private val title: String = "请选择",
34 | // 选项
35 | private val items: Set,
36 | // 选项文本
37 | private val itemText: (T) -> String = { it.toString() },
38 | // 选中的项
39 | private val selectedItem: T = items.first(),
40 | // 是否显示确定和取消按钮
41 | private val showButton: Boolean = true,
42 | // 取消文本
43 | private val cancelText: String = "取消",
44 | // 确定文本
45 | private val confirmText: String = "确定",
46 | // 取消按钮点击事件,返回true则隐藏弹窗
47 | private val onCancelClick: suspend CoroutineScope.() -> Boolean = { true },
48 | // 确定按钮点击事件,返回true则隐藏弹窗
49 | private val onConfirmClick: suspend CoroutineScope.(T) -> Boolean = { true },
50 | ): SheetBuilder() {
51 |
52 | @Composable
53 | override fun Build() {
54 | var selected by remember(selectedItem) {
55 | mutableStateOf(selectedItem)
56 | }
57 | SheetColumn {
58 | // 标题栏
59 | if (showButton) {
60 | TitleBar(
61 | title = title,
62 | cancelText = cancelText,
63 | confirmText = confirmText,
64 | onCancelClick = onCancelClick,
65 | onConfirmClick = { onConfirmClick(selected) }
66 | )
67 | } else {
68 | Box(
69 | modifier = Modifier.fillMaxWidth().height(56.dp),
70 | contentAlignment = Alignment.Center
71 | ) {
72 | Text(
73 | text = title,
74 | style = AppText.Bold.Title.large,
75 | textAlign = TextAlign.Center
76 | )
77 | }
78 | }
79 | // 选项
80 | val scope = rememberCoroutineScope()
81 | Column(
82 | modifier = Modifier
83 | .fillMaxWidth()
84 | .verticalScroll(rememberScrollState()),
85 | ) {
86 | items.forEachIndexed { index, item ->
87 | RadioCell(
88 | label = itemText(item),
89 | selected = selected == item,
90 | onClick = {
91 | selected = item
92 | if (showButton.not()) {
93 | scope.launch { if (onConfirmClick(item)) dismiss() }
94 | }
95 | },
96 | border = index != items.size - 1
97 | )
98 | }
99 | }
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/sheet/builder/SheetBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.sheet.builder
2 |
3 | import androidx.compose.foundation.layout.WindowInsets
4 | import androidx.compose.foundation.layout.asPaddingValues
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.layout.height
7 | import androidx.compose.foundation.layout.padding
8 | import androidx.compose.foundation.layout.statusBars
9 | import androidx.compose.material3.Text
10 | import androidx.compose.material3.TextButton
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.rememberCoroutineScope
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.unit.Dp
15 | import androidx.compose.ui.unit.dp
16 | import com.d10ng.compose.model.UiViewModelManager
17 | import com.d10ng.compose.ui.AppText
18 | import kotlinx.coroutines.CoroutineScope
19 | import kotlinx.coroutines.Dispatchers
20 | import kotlinx.coroutines.delay
21 | import kotlinx.coroutines.flow.MutableStateFlow
22 | import kotlinx.coroutines.launch
23 | import tech.annexflow.constraintlayout.compose.ConstraintLayout
24 |
25 | /**
26 | * 底部弹窗构建器
27 | * @Author d10ng
28 | * @Date 2023/9/8 18:01
29 | */
30 | abstract class SheetBuilder(
31 | // 是否允许点击外部隐藏弹窗
32 | var clickOutsideDismiss: Boolean = true,
33 | // 屏幕顶部距离
34 | var topMargin: @Composable () -> Dp = { WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + 56.dp },
35 | ) {
36 | companion object {
37 | private val scope = CoroutineScope(Dispatchers.Default)
38 | }
39 |
40 | val visibleFlow = MutableStateFlow(false)
41 |
42 | /**
43 | * 隐藏弹窗
44 | */
45 | fun dismiss() {
46 | visibleFlow.value = false
47 | scope.launch {
48 | delay(300)
49 | UiViewModelManager.hideSheet(this@SheetBuilder)
50 | }
51 | }
52 |
53 | /**
54 | * 构建弹窗内容
55 | */
56 | @Composable
57 | abstract fun Build()
58 | }
59 |
60 | @Composable
61 | fun SheetBuilder.TitleBar(
62 | title: String = "请选择",
63 | cancelText: String = "取消",
64 | confirmText: String = "确定",
65 | onCancelClick: suspend CoroutineScope.() -> Boolean = { true },
66 | onConfirmClick: suspend CoroutineScope.() -> Boolean = { true },
67 | ) {
68 | val scope = rememberCoroutineScope()
69 | ConstraintLayout(
70 | modifier = Modifier
71 | .fillMaxWidth()
72 | .padding(horizontal = 4.dp)
73 | .height(56.dp)
74 | ) {
75 | val (cancelButton, titleText, confirmButton) = createRefs()
76 | // 取消按钮
77 | TextButton(
78 | onClick = {
79 | scope.launch {
80 | if (onCancelClick()) dismiss()
81 | }
82 | },
83 | modifier = Modifier
84 | .constrainAs(cancelButton) {
85 | start.linkTo(parent.start)
86 | top.linkTo(parent.top)
87 | bottom.linkTo(parent.bottom)
88 | }
89 | ) {
90 | Text(text = cancelText, style = AppText.Normal.Tips.default)
91 | }
92 | // 标题
93 | Text(
94 | text = title,
95 | style = AppText.Bold.Title.large,
96 | modifier = Modifier
97 | .constrainAs(titleText) {
98 | start.linkTo(parent.start)
99 | end.linkTo(parent.end)
100 | top.linkTo(parent.top)
101 | bottom.linkTo(parent.bottom)
102 | }
103 | )
104 | // 确定按钮
105 | TextButton(
106 | onClick = {
107 | scope.launch {
108 | if (onConfirmClick()) dismiss()
109 | }
110 | },
111 | modifier = Modifier
112 | .constrainAs(confirmButton) {
113 | end.linkTo(parent.end)
114 | top.linkTo(parent.top)
115 | bottom.linkTo(parent.bottom)
116 | }
117 | ) {
118 | Text(text = confirmText, style = AppText.Normal.Title.default)
119 | }
120 | }
121 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/sheet/builder/SinglePickerSheetBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.sheet.builder
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.getValue
5 | import androidx.compose.runtime.mutableStateOf
6 | import androidx.compose.runtime.remember
7 | import androidx.compose.runtime.setValue
8 | import androidx.compose.ui.text.TextStyle
9 | import com.d10ng.compose.ui.AppText
10 | import com.d10ng.compose.ui.form.Picker
11 | import com.d10ng.compose.ui.sheet.SheetColumn
12 | import kotlinx.coroutines.CoroutineScope
13 |
14 | /**
15 | * 单列滚轮选择器构建器
16 | * @Author d10ng
17 | * @Date 2023/9/11 15:38
18 | */
19 | class SinglePickerSheetBuilder(
20 | // 标题
21 | private val title: String = "请选择",
22 | // 选项
23 | private val items: Set,
24 | // 选项文本
25 | private val itemText: (T) -> String = { it.toString() },
26 | // 文本样式
27 | private val textStyle: TextStyle = AppText.Normal.Title.default,
28 | // 选中的项
29 | private val selectedItem: T = items.first(),
30 | // 取消文本
31 | private val cancelText: String = "取消",
32 | // 确定文本
33 | private val confirmText: String = "确定",
34 | // 取消按钮点击事件,返回true则隐藏弹窗
35 | private val onCancelClick: suspend CoroutineScope.() -> Boolean = { true },
36 | // 确定按钮点击事件,返回true则隐藏弹窗
37 | private val onConfirmClick: suspend CoroutineScope.(T) -> Boolean = { true },
38 | ): SheetBuilder() {
39 | @Composable
40 | override fun Build() {
41 | var selected by remember(selectedItem) {
42 | mutableStateOf(selectedItem)
43 | }
44 | SheetColumn {
45 | // 标题栏
46 | TitleBar(
47 | title = title,
48 | cancelText = cancelText,
49 | confirmText = confirmText,
50 | onCancelClick = onCancelClick,
51 | onConfirmClick = { onConfirmClick(selected) }
52 | )
53 | // 选项
54 | Picker(
55 | items = items,
56 | itemText = itemText,
57 | textStyle = textStyle,
58 | selectedItem = selected,
59 | onValueChange = { selected = it }
60 | )
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/sheet/builder/TimePickerSheetBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.sheet.builder
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.getValue
5 | import androidx.compose.runtime.mutableIntStateOf
6 | import androidx.compose.runtime.mutableStateOf
7 | import androidx.compose.runtime.remember
8 | import androidx.compose.runtime.setValue
9 | import androidx.compose.ui.text.TextStyle
10 | import com.d10ng.compose.ui.AppText
11 | import com.d10ng.compose.ui.form.TimePicker
12 | import com.d10ng.compose.ui.form.TimePickerMode
13 | import com.d10ng.compose.ui.form.hour
14 | import com.d10ng.compose.ui.form.minute
15 | import com.d10ng.compose.ui.form.second
16 | import com.d10ng.compose.ui.sheet.SheetColumn
17 | import kotlinx.coroutines.CoroutineScope
18 | import kotlinx.datetime.TimeZone
19 | import kotlinx.datetime.toLocalDateTime
20 | import kotlin.time.Clock
21 | import kotlin.time.ExperimentalTime
22 | import kotlin.time.Instant
23 |
24 | /**
25 | * 时间选择器构建器
26 | * @Author d10ng
27 | * @Date 2023/9/12 11:23
28 | */
29 | @ExperimentalTime
30 | class TimePickerSheetBuilder(
31 | // 标题
32 | private val title: String = "请选择",
33 | // 选中的时间
34 | private var value: Int = 0,
35 | // 开始时间
36 | private val start: Int = 0,
37 | // 结束时间,包含
38 | private val endInclude: Int = 86399,
39 | // 文本样式
40 | private val textStyle: TextStyle = AppText.Normal.Title.default,
41 | // 选择器模式
42 | private val mode: TimePickerMode = TimePickerMode.HMS,
43 | // 选项文本
44 | private val itemText: (Int, String) -> String = { _, item -> item },
45 | // 取消文本
46 | private val cancelText: String = "取消",
47 | // 确定文本
48 | private val confirmText: String = "确定",
49 | // 取消按钮点击事件,返回true则隐藏弹窗
50 | private val onCancelClick: suspend CoroutineScope.() -> Boolean = { true },
51 | // 确定按钮点击事件,返回true则隐藏弹窗
52 | private val onConfirmClick: suspend CoroutineScope.(Int, List) -> Boolean = { _, _ -> true },
53 | ) : SheetBuilder() {
54 |
55 | /**
56 | * 设置选择当前时间
57 | * > 仅在未设置value,并且触发弹窗展示前有效
58 | * @param timestamp Long 时间戳,默认当前时间,单位毫秒
59 | */
60 | fun setCurrentTime(timestamp: Long = Clock.System.now().toEpochMilliseconds()) {
61 | val datetime = Instant.fromEpochMilliseconds(timestamp)
62 | .toLocalDateTime(TimeZone.currentSystemDefault())
63 | this.value = datetime.hour * 3600 + datetime.minute * 60 + datetime.second
64 | }
65 |
66 | @Composable
67 | override fun Build() {
68 | var selected by remember(value) {
69 | mutableIntStateOf(value)
70 | }
71 | var selectedList by remember(value) {
72 | mutableStateOf(listOf(value.hour(), value.minute(), value.second()))
73 | }
74 | SheetColumn {
75 | // 标题栏
76 | TitleBar(
77 | title = title,
78 | cancelText = cancelText,
79 | confirmText = confirmText,
80 | onCancelClick = onCancelClick,
81 | onConfirmClick = { onConfirmClick(selected, selectedList) }
82 | )
83 | // 选项
84 | TimePicker(
85 | value = selected,
86 | onValueChange = { s, l ->
87 | selected = s
88 | selectedList = l
89 | },
90 | start = start,
91 | endInclude = endInclude,
92 | textStyle = textStyle,
93 | mode = mode,
94 | itemText = itemText
95 | )
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/show/Avatar.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.show
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.size
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material3.Text
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Alignment
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.graphics.Color
12 | import androidx.compose.ui.unit.Dp
13 | import androidx.compose.ui.unit.TextUnit
14 | import androidx.compose.ui.unit.dp
15 | import androidx.compose.ui.unit.sp
16 | import com.d10ng.compose.ui.AppShape
17 | import com.d10ng.compose.ui.AppText
18 |
19 | /**
20 | * 头像
21 | * @Author d10ng
22 | * @Date 2023/9/12 15:22
23 | */
24 |
25 | /**
26 | * 头像
27 | * @param char Char
28 | * @param size Dp
29 | * @param backgroundColor Color
30 | * @param contentColor Color
31 | * @param shape RoundedCornerShape
32 | * @param fontSize TextUnit
33 | * @param content [@androidx.compose.runtime.Composable] Function0
34 | */
35 | @Composable
36 | fun Avatar(
37 | char: Char,
38 | size: Dp = 56.dp,
39 | backgroundColor: Color = Color.LightGray,
40 | contentColor: Color = Color.White,
41 | shape: RoundedCornerShape = AppShape.RC.Cycle,
42 | fontSize: TextUnit = 26.sp,
43 | content: @Composable () -> Unit = {}
44 | ) {
45 | Box(
46 | modifier = Modifier
47 | .size(size)
48 | .background(backgroundColor, shape),
49 | contentAlignment = Alignment.Center
50 | ) {
51 | content()
52 | Text(
53 | text = char.toString().uppercase(),
54 | style = AppText.Bold.Surface.v26,
55 | color = contentColor,
56 | fontSize = fontSize
57 | )
58 | }
59 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/show/Badge.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.show
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.defaultMinSize
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.foundation.layout.widthIn
8 | import androidx.compose.material3.Text
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.runtime.remember
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.text.style.TextOverflow
15 | import androidx.compose.ui.unit.dp
16 | import com.d10ng.compose.ui.AppColor
17 | import com.d10ng.compose.ui.AppShape
18 | import com.d10ng.compose.ui.AppText
19 |
20 | /**
21 | * 徽标盒子
22 | * @param badge [@androidx.compose.runtime.Composable] Function0
23 | * @param content [@androidx.compose.runtime.Composable] Function0
24 | */
25 | @Composable
26 | fun BadgeBox(
27 | badge: @Composable () -> Unit,
28 | content: @Composable () -> Unit
29 | ) {
30 | Box(
31 | modifier = Modifier
32 | ) {
33 | Box(modifier = Modifier.padding(4.dp)) {
34 | content()
35 | }
36 | Box(
37 | modifier = Modifier
38 | .align(Alignment.TopEnd)
39 | ) {
40 | badge()
41 | }
42 | }
43 | }
44 |
45 | /**
46 | * 徽标
47 | * @param content String 徽标内容,为空时显示小圆点
48 | * @param color Color 徽标颜色
49 | */
50 | @Composable
51 | fun Badge(
52 | content: String = "",
53 | color: Color = AppColor.Func.error
54 | ) {
55 | if (content.isEmpty()) {
56 | Box(
57 | modifier = Modifier
58 | .defaultMinSize(minWidth = 12.dp, minHeight = 12.dp)
59 | .background(color, AppShape.RC.Cycle)
60 | )
61 | } else {
62 | Box(
63 | modifier = Modifier
64 | .defaultMinSize(minWidth = 18.dp, minHeight = 18.dp)
65 | .background(color, AppShape.RC.v10)
66 | .padding(horizontal = 4.dp, vertical = 1.dp),
67 | contentAlignment = Alignment.Center
68 | ) {
69 | Text(
70 | text = content,
71 | style = AppText.Bold.Surface.mini,
72 | modifier = Modifier.widthIn(max = 32.dp),
73 | maxLines = 1,
74 | overflow = TextOverflow.Clip
75 | )
76 | }
77 | }
78 | }
79 |
80 | /**
81 | * 徽标
82 | * @param num Int 徽标数字,为0时不显示
83 | * @param max Int 最大值,超过最大值显示最大值+,默认99
84 | * @param color Color 徽标颜色
85 | */
86 | @Composable
87 | fun Badge(
88 | num: Int,
89 | max: Int = 99,
90 | color: Color = AppColor.Func.error
91 | ) {
92 | if (num > 0) {
93 | val content = remember(num, max) {
94 | if (num > max) "$max+" else num.toString()
95 | }
96 | Badge(content, color)
97 | }
98 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/show/Divider.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.show
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.fillMaxHeight
6 | import androidx.compose.foundation.layout.fillMaxWidth
7 | import androidx.compose.foundation.layout.height
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.layout.width
10 | import androidx.compose.material3.MaterialTheme
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.unit.Dp
15 | import androidx.compose.ui.unit.dp
16 |
17 | /**
18 | * Divider
19 | * @Author d10ng
20 | * @Date 2023/9/5 11:51
21 | */
22 |
23 | /**
24 | * 横向分割线
25 | * @param modifier Modifier 修饰符
26 | * @param color Color 分割线颜色
27 | * @param thickness Dp 分割线高度
28 | * @param paddingStart Dp 左边距
29 | * @param paddingEnd Dp 右边距
30 | */
31 | @Composable
32 | fun HorizontalDivider(
33 | modifier: Modifier = Modifier,
34 | color: Color = MaterialTheme.colorScheme.outlineVariant,
35 | thickness: Dp = 0.5.dp,
36 | paddingStart: Dp = 0.dp,
37 | paddingEnd: Dp = 0.dp,
38 | ) {
39 | Box(
40 | modifier = modifier
41 | .fillMaxWidth()
42 | .height(thickness)
43 | .padding(start = paddingStart, end = paddingEnd)
44 | .background(color)
45 | )
46 | }
47 |
48 | /**
49 | * 纵向分割线
50 | * @param modifier Modifier 修饰符
51 | * @param color Color 分割线颜色
52 | * @param thickness Dp 分割线高度
53 | * @param paddingTop Dp 上边距
54 | * @param paddingBottom Dp 下边距
55 | */
56 | @Composable
57 | fun VerticalDivider(
58 | modifier: Modifier = Modifier,
59 | color: Color = MaterialTheme.colorScheme.outlineVariant,
60 | thickness: Dp = 0.5.dp,
61 | paddingTop: Dp = 0.dp,
62 | paddingBottom: Dp = 0.dp,
63 | ) {
64 | Box(
65 | modifier = modifier
66 | .fillMaxHeight()
67 | .width(thickness)
68 | .padding(top = paddingTop, bottom = paddingBottom)
69 | .background(color)
70 | )
71 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/ui/show/Tag.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.ui.show
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.border
5 | import androidx.compose.foundation.clickable
6 | import androidx.compose.foundation.layout.Box
7 | import androidx.compose.foundation.layout.padding
8 | import androidx.compose.foundation.shape.RoundedCornerShape
9 | import androidx.compose.material3.Text
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.runtime.remember
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.draw.clip
15 | import androidx.compose.ui.graphics.Color
16 | import androidx.compose.ui.graphics.Shape
17 | import androidx.compose.ui.unit.dp
18 | import com.d10ng.compose.ui.AppColor
19 | import com.d10ng.compose.ui.AppShape
20 | import com.d10ng.compose.ui.AppText
21 |
22 | /**
23 | * 标签
24 | * @Author d10ng
25 | * @Date 2023/9/7 10:16
26 | */
27 |
28 | enum class TagType(val color: Color) {
29 | Primary(AppColor.Main.primary),
30 | Success(AppColor.Func.success),
31 | Warning(AppColor.Func.assist),
32 | Danger(AppColor.Func.error),
33 | }
34 |
35 | enum class TagStyle(val shape: Shape) {
36 | // 填充
37 | Fill(AppShape.RC.v2),
38 |
39 | // 边框
40 | Outline(AppShape.RC.v2),
41 |
42 | // 圆角
43 | Round(AppShape.RC.Cycle),
44 |
45 | // 标记
46 | Mark(RoundedCornerShape(topEndPercent = 100, bottomEndPercent = 100)),
47 | }
48 |
49 | @Composable
50 | fun Tag(
51 | text: String,
52 | modifier: Modifier = Modifier,
53 | type: TagType = TagType.Primary,
54 | style: TagStyle = TagStyle.Fill,
55 | color: Color? = null,
56 | contentColor: Color? = null,
57 | onClick: (() -> Unit)? = null
58 | ) {
59 | // 字体颜色
60 | val textColor = remember(style, type) {
61 | contentColor ?: when (style) {
62 | TagStyle.Outline -> color ?: type.color
63 | else -> Color.White
64 | }
65 | }
66 | // 背景颜色
67 | val bgColor = remember(style, type) {
68 | when (style) {
69 | TagStyle.Outline -> Color.Transparent
70 | else -> color ?: type.color
71 | }
72 | }
73 | // 边框颜色
74 | val borderColor = remember(style, type) {
75 | when (style) {
76 | TagStyle.Outline -> color ?: type.color
77 | else -> Color.Transparent
78 | }
79 | }
80 | // 背景样式
81 | val bgShape = style.shape
82 | Box(
83 | modifier = modifier
84 | .background(bgColor, bgShape)
85 | .then(
86 | when (style) {
87 | TagStyle.Outline -> Modifier.border(1.dp, borderColor, bgShape)
88 | else -> Modifier
89 | }
90 | )
91 | .clip(bgShape)
92 | .clickable(enabled = onClick != null) { onClick?.invoke() },
93 | contentAlignment = Alignment.Center
94 | ) {
95 | Text(
96 | text = text,
97 | style = AppText.Bold.Surface.mini,
98 | color = textColor,
99 | modifier = Modifier
100 | .padding(vertical = 3.dp, horizontal = 6.dp)
101 | )
102 | }
103 | }
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/utils/BackHandlerUtils.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.utils
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 | /**
6 | * 返回键处理
7 | * @Author d10ng
8 | * @Date 2024/9/12 11:26
9 | */
10 |
11 | @Composable
12 | expect fun BackHandler(enabled: Boolean = true, onBack: () -> Unit)
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/com/d10ng/compose/utils/ColorUtils.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.utils
2 |
3 | import androidx.compose.ui.graphics.Color
4 | import androidx.compose.ui.graphics.luminance
5 | import kotlin.math.roundToInt
6 |
7 | /**
8 | * 判断颜色是否为深色
9 | * @receiver Color
10 | * @return Boolean
11 | */
12 | fun Color.isDark() = luminance() <= 0.5f
13 |
14 | /**
15 | * 获取颜色的深色或浅色
16 | * @receiver Color
17 | * @param level Double -1.0~1.0,当为-1.0时,返回纯黑色,当为1.0时,返回纯白色
18 | * @return Color
19 | */
20 | fun Color.next(level: Double): Color {
21 | // 参数合法性校验
22 | require(level in -1.0..1.0) { "Level must be in [-1.0, 1.0]" }
23 | val amount = level.toFloat()
24 | return when {
25 | amount < 0 -> blendWith(Color.Black, -amount)
26 | amount > 0 -> blendWith(Color.White, amount)
27 | else -> this
28 | }
29 | }
30 |
31 | private fun Color.blendWith(target: Color, ratio: Float): Color {
32 | val inverseRatio = 1f - ratio
33 | return Color(
34 | red = red * inverseRatio + target.red * ratio,
35 | green = green * inverseRatio + target.green * ratio,
36 | blue = blue * inverseRatio + target.blue * ratio,
37 | alpha = alpha // 保持原始透明度
38 | )
39 | }
40 |
41 | /**
42 | * 将颜色转换为十六进制字符串
43 | * @receiver [Color]
44 | * @param includeAlpha [Boolean] 是否包含透明度,默认包含
45 | * @return [String] 十六进制字符串,如果包含透明度,则为 #RRGGBBAA,否则为 #RRGGBB
46 | */
47 | fun Color.toHex(includeAlpha: Boolean = true): String {
48 | fun toHexComponent(value: Float) = value.times(255).roundToInt()
49 | .toString(16)
50 | .padStart(2, '0') // 确保始终是 2 位
51 | .uppercase()
52 |
53 | val r = toHexComponent(red)
54 | val g = toHexComponent(green)
55 | val b = toHexComponent(blue)
56 | val a = toHexComponent(alpha)
57 |
58 | return if (includeAlpha) "#$a$r$g$b" else "#$r$g$b"
59 | }
60 |
61 | /**
62 | * 获取颜色的相关颜色
63 | * @receiver [Color]
64 | * @return [List] 0: onColor; 1: colorContainer; 2: onColorContainer; 3: inverseColor;
65 | */
66 | fun Color.makeRelatedColors(): List {
67 | val dark = isDark()
68 | return listOf(
69 | if (dark) Color.White else Color.Black,
70 | next(if (dark) 0.5 else -0.5),
71 | next(if (dark) -0.5 else 0.5),
72 | next(if (dark) 0.7 else -0.7)
73 | )
74 | }
75 |
--------------------------------------------------------------------------------
/library/src/iosMain/kotlin/com/d10ng/compose/utils/BackHandlerUtils.ios.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.utils
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 | /**
6 | * 返回键处理
7 | * @Author d10ng
8 | * @Date 2024/9/12 11:26
9 | */
10 |
11 | /**
12 | * 返回键处理
13 | * @Author d10ng
14 | * @Date 2024/9/12 11:26
15 | */
16 | @Composable
17 | actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {
18 | // TODO IOS暂时不支持
19 | }
--------------------------------------------------------------------------------
/library/src/wasmJsMain/kotlin/com/d10ng/compose/utils/BackHandlerUtils.wasmJs.kt:
--------------------------------------------------------------------------------
1 | package com.d10ng.compose.utils
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 | @Composable
6 | actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {
7 | // TODO("Not yet implemented")
8 | }
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
2 |
3 | pluginManagement {
4 | repositories {
5 | google {
6 | mavenContent {
7 | includeGroupAndSubgroups("androidx")
8 | includeGroupAndSubgroups("com.android")
9 | includeGroupAndSubgroups("com.google")
10 | }
11 | }
12 | mavenCentral()
13 | gradlePluginPortal()
14 | }
15 | }
16 |
17 | dependencyResolutionManagement {
18 | repositories {
19 | google {
20 | mavenContent {
21 | includeGroupAndSubgroups("androidx")
22 | includeGroupAndSubgroups("com.android")
23 | includeGroupAndSubgroups("com.google")
24 | }
25 | }
26 | mavenCentral()
27 | maven("https://jitpack.io")
28 | maven("https://raw.githubusercontent.com/D10NGYANG/maven-repo/main/repository")
29 | }
30 | }
31 | rootProject.name = "DLJetpackComposeUtil-Project"
32 | include(":androidApp", ":composeApp", ":library")
33 | project(":library").name = "DLJetpackComposeUtil"
34 |
--------------------------------------------------------------------------------