├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── themes.xml │ │ │ │ └── colors.xml │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── logo.jpg │ │ │ │ ├── zan.png │ │ │ │ ├── caver.webp │ │ │ │ ├── pinglun.png │ │ │ │ ├── icon_code.png │ │ │ │ ├── icon_copy.png │ │ │ │ ├── icon_data.png │ │ │ │ ├── icon_kafi.png │ │ │ │ ├── icon_left.png │ │ │ │ ├── logo_mini.jpg │ │ │ │ ├── anim_draw.webp │ │ │ │ ├── base_draw.webp │ │ │ │ ├── head_icon.webp │ │ │ │ ├── ic_launcher.webp │ │ │ │ ├── icon_about.png │ │ │ │ ├── icon_colloct.png │ │ │ │ ├── icon_head.webp │ │ │ │ ├── icon_share.png │ │ │ │ ├── icon_version.png │ │ │ │ ├── icon_app_setting.png │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── 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-xxxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── xml │ │ │ │ ├── backup_rules.xml │ │ │ │ └── data_extraction_rules.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── toly1994 │ │ │ │ └── composeunit │ │ │ │ ├── ui │ │ │ │ └── theme │ │ │ │ │ ├── Color.kt │ │ │ │ │ ├── Shape.kt │ │ │ │ │ ├── Type.kt │ │ │ │ │ └── Theme.kt │ │ │ │ ├── app │ │ │ │ ├── UnitApplication.kt │ │ │ │ ├── ComposeUnitApp.kt │ │ │ │ ├── navigation │ │ │ │ │ ├── RouterRes.kt │ │ │ │ │ ├── UnitAppBar.kt │ │ │ │ │ └── UnitNavigation.kt │ │ │ │ ├── data_manager │ │ │ │ │ └── DataManagePage.kt │ │ │ │ └── splash │ │ │ │ │ └── UnitSplash.kt │ │ │ │ ├── repository │ │ │ │ ├── NodeRepository.kt │ │ │ │ ├── WidgetRepository.kt │ │ │ │ ├── impl │ │ │ │ │ ├── DbNodeRepository.kt │ │ │ │ │ ├── MemoryNodeRepository.kt │ │ │ │ │ ├── DbWidgetRepository.kt │ │ │ │ │ └── MemoryWidgetRepository.kt │ │ │ │ ├── database │ │ │ │ │ ├── dao │ │ │ │ │ │ ├── NodeDao.kt │ │ │ │ │ │ └── WidgetDao.kt │ │ │ │ │ ├── entity │ │ │ │ │ │ └── WidgetPo.kt │ │ │ │ │ └── ComposeUnitDB.kt │ │ │ │ └── memory │ │ │ │ │ ├── MemoryWidgetDataStore.kt │ │ │ │ │ └── MemoryNodeDataStore.kt │ │ │ │ ├── models │ │ │ │ ├── NodeModel.kt │ │ │ │ ├── WidgetModel.kt │ │ │ │ └── state │ │ │ │ │ └── WidgetSearchState.kt │ │ │ │ ├── components │ │ │ │ ├── style │ │ │ │ │ └── Gap.kt │ │ │ │ ├── tolyui │ │ │ │ │ └── Panel.kt │ │ │ │ └── CodeHighlighter.kt │ │ │ │ ├── layouts │ │ │ │ ├── github_search │ │ │ │ │ ├── repository │ │ │ │ │ │ ├── GitHubClient.kt │ │ │ │ │ │ └── GithubRepository.kt │ │ │ │ │ ├── view_model │ │ │ │ │ │ └── NodeViewModel.kt │ │ │ │ │ └── views │ │ │ │ │ │ ├── GithubSearchPage.kt │ │ │ │ │ │ └── GithubRepoItem.kt │ │ │ │ ├── counter │ │ │ │ │ ├── CounterPageV0.kt │ │ │ │ │ └── CounterPageV1.kt │ │ │ │ ├── home │ │ │ │ │ └── LayoutHomePage.kt │ │ │ │ ├── unit_widget_item │ │ │ │ │ ├── UnitWidgetItemV1.kt │ │ │ │ │ └── UnitWidgetItemV0.kt │ │ │ │ ├── juejin_article_item │ │ │ │ │ ├── JuejinArticleItemV1.kt │ │ │ │ │ └── JuejinArticleItemV0.kt │ │ │ │ └── wechat_item │ │ │ │ │ └── WeChatItem.kt │ │ │ │ ├── widgets │ │ │ │ ├── Text │ │ │ │ │ ├── node1.kt │ │ │ │ │ ├── node4.kt │ │ │ │ │ ├── node2.kt │ │ │ │ │ ├── node3.kt │ │ │ │ │ └── node5.kt │ │ │ │ ├── Column │ │ │ │ │ ├── node3.kt │ │ │ │ │ ├── node2.kt │ │ │ │ │ └── node1.kt │ │ │ │ ├── Row │ │ │ │ │ ├── node3.kt │ │ │ │ │ ├── node2.kt │ │ │ │ │ └── node1.kt │ │ │ │ ├── Box │ │ │ │ │ ├── node1.kt │ │ │ │ │ └── node2.kt │ │ │ │ ├── Icon │ │ │ │ │ └── node1.kt │ │ │ │ ├── LazyColumn │ │ │ │ │ └── node1.kt │ │ │ │ ├── LazyRow │ │ │ │ │ └── node1.kt │ │ │ │ ├── Image │ │ │ │ │ ├── node1.kt │ │ │ │ │ ├── node3.kt │ │ │ │ │ ├── node2.kt │ │ │ │ │ └── node4.kt │ │ │ │ ├── LazyVerticalGrid │ │ │ │ │ └── node1.kt │ │ │ │ ├── LazyHorizontalGrid │ │ │ │ │ └── node1.kt │ │ │ │ └── WidgetMap.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── home │ │ │ │ ├── WidgetViewModel.kt │ │ │ │ └── UnitHomePage.kt │ │ │ │ ├── details │ │ │ │ └── NodeViewModel.kt │ │ │ │ ├── doing │ │ │ │ └── Doing.kt │ │ │ │ └── user │ │ │ │ └── UnitUserPage.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── toly1994 │ │ │ └── composeunit │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── toly1994 │ │ └── composeunit │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── highlight ├── .gitignore ├── consumer-rules.pro ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── neo │ │ │ └── highlight │ │ │ ├── util │ │ │ ├── scheme │ │ │ │ ├── contract │ │ │ │ │ ├── LinkSchemeContract.java │ │ │ │ │ └── SchemeScope.java │ │ │ │ ├── base │ │ │ │ │ ├── BaseColorScheme.java │ │ │ │ │ └── BaseScheme.java │ │ │ │ ├── BackgroundScheme.java │ │ │ │ ├── Scope.java │ │ │ │ ├── ColorScheme.java │ │ │ │ ├── OnMatchScheme.java │ │ │ │ ├── StyleScheme.java │ │ │ │ ├── LinkScheme.java │ │ │ │ ├── FontScheme.java │ │ │ │ └── OnClickScheme.java │ │ │ └── listener │ │ │ │ └── HighlightTextWatcher.java │ │ │ └── core │ │ │ ├── Scheme.java │ │ │ ├── SpanUtils.java │ │ │ ├── HighlightContract.java │ │ │ └── LinesTextWatcher.java │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── neo │ │ │ └── highlight │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── neo │ │ └── highlight │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── .idea ├── .gitignore ├── compiler.xml ├── vcs.xml ├── misc.xml ├── gradle.xml └── inspectionProfiles │ └── Project_Default.xml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle ├── README.md ├── gradle.properties └── gradlew.bat /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /highlight/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /highlight/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ComposeUnit 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/logo.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/zan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/zan.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/caver.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/caver.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/pinglun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/pinglun.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_code.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_copy.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_data.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_kafi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_kafi.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_left.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/logo_mini.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/logo_mini.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/anim_draw.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/anim_draw.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/base_draw.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/base_draw.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/head_icon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/head_icon.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_about.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_colloct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_colloct.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_head.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_head.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_share.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_version.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_app_setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/icon_app_setting.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/ComposeUnit/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /highlight/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Oct 31 06:38:05 CST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val Purple200 = Color(0xFFBB86FC) 6 | val Purple500 = Color(0xFF6200EE) 7 | val Purple700 = Color(0xFF3700B3) 8 | val Teal200 = Color(0xFF03DAC5) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/app/UnitApplication.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.app 2 | 3 | import android.app.Application 4 | import com.toly1994.composeunit.repository.database.LocalDb 5 | 6 | class UnitApplication: Application() { 7 | override fun onCreate() { 8 | super.onCreate() 9 | LocalDb.offer(this) 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/NodeRepository.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository 2 | 3 | import com.toly1994.composeunit.models.NodeModel 4 | import com.toly1994.composeunit.models.WidgetModel 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | interface NodeRepository { 8 | fun queryNodeByWidgetId(widgetId:Int): Flow> 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/WidgetRepository.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository 2 | 3 | import com.toly1994.composeunit.models.WidgetModel 4 | import kotlinx.coroutines.flow.Flow 5 | 6 | interface WidgetRepository { 7 | fun queryAllWidget(): Flow> 8 | 9 | fun searchWidget(arg:String): Flow> 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/ui/theme/Shape.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.ui.theme 2 | 3 | import androidx.compose.foundation.shape.RoundedCornerShape 4 | import androidx.compose.material.Shapes 5 | import androidx.compose.ui.unit.dp 6 | 7 | val Shapes = Shapes( 8 | small = RoundedCornerShape(4.dp), 9 | medium = RoundedCornerShape(4.dp), 10 | large = RoundedCornerShape(0.dp) 11 | ) -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | } 15 | rootProject.name = "ComposeUnit" 16 | include ':app' 17 | include ':highlight' 18 | -------------------------------------------------------------------------------- /app/src/test/java/com/toly1994/composeunit/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/models/NodeModel.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.models 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | 7 | @Entity(tableName = "node") 8 | data class NodeModel( 9 | @ColumnInfo(name = "widget_id") 10 | val widgetId: Int, 11 | @PrimaryKey 12 | val name: String, 13 | @ColumnInfo 14 | val info: String, 15 | @ColumnInfo 16 | val code: String, 17 | ) 18 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/contract/LinkSchemeContract.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme.contract; 2 | 3 | import androidx.annotation.ColorInt; 4 | 5 | import com.neo.highlight.core.Scheme; 6 | import com.neo.highlight.util.scheme.LinkScheme; 7 | 8 | public interface LinkSchemeContract { 9 | Scheme setPainText(boolean painText); 10 | Scheme setPainTextColor(@ColorInt int painTextColor); 11 | Scheme setPainTextUnderline(boolean painTextUnderline); 12 | } 13 | -------------------------------------------------------------------------------- /highlight/src/test/java/com/neo/highlight/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/core/Scheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.core; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import java.util.regex.Pattern; 7 | 8 | /** 9 | * @author Irineu A. Silva 10 | */ 11 | public interface Scheme { 12 | 13 | @Nullable 14 | Pattern getRegex(); 15 | 16 | @Nullable 17 | Object getSpan(@NonNull CharSequence text, int start, int end); 18 | 19 | boolean getClearOldSpan(); 20 | 21 | @NonNull 22 | Scheme setClearOldSpan(boolean clearOldSpan); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/contract/SchemeScope.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme.contract; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import com.neo.highlight.core.Scheme; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author Irineu A. Silva 12 | */ 13 | public interface SchemeScope { 14 | 15 | @Nullable 16 | List getScopeSchemes(); 17 | void setScopeSchemes(List schemes); 18 | Scheme addScopeScheme(@NonNull Scheme... schemes); 19 | Scheme clearScopeSchemes(); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/components/style/Gap.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.components.style 2 | 3 | 4 | 5 | import androidx.compose.foundation.layout.Row 6 | import androidx.compose.foundation.layout.Spacer 7 | import androidx.compose.foundation.layout.height 8 | import androidx.compose.foundation.layout.width 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.ui.Modifier 11 | import androidx.compose.ui.unit.dp 12 | 13 | 14 | @Composable 15 | fun Gap(width: Float = 0f, height: Float = 0f) { 16 | Spacer(modifier = Modifier 17 | .width(width.dp) 18 | .height(height.dp)) 19 | } -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/impl/DbNodeRepository.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.impl 2 | 3 | import com.toly1994.composeunit.models.NodeModel 4 | import com.toly1994.composeunit.repository.NodeRepository 5 | import com.toly1994.composeunit.repository.database.LocalDb 6 | import com.toly1994.composeunit.repository.memory.MemoryNodeDataStore 7 | import kotlinx.coroutines.flow.Flow 8 | import kotlinx.coroutines.flow.flow 9 | 10 | 11 | class DbNodeRepository : NodeRepository { 12 | 13 | override fun queryNodeByWidgetId(widgetId: Int): Flow> { 14 | return LocalDb.database.nodeDao().queryByWidgetId(widgetId) 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/impl/MemoryNodeRepository.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.impl 2 | 3 | import com.toly1994.composeunit.models.NodeModel 4 | import com.toly1994.composeunit.repository.NodeRepository 5 | import com.toly1994.composeunit.repository.memory.MemoryNodeDataStore 6 | import kotlinx.coroutines.flow.Flow 7 | import kotlinx.coroutines.flow.flow 8 | 9 | 10 | class MemoryNodeRepository : NodeRepository { 11 | 12 | override fun queryNodeByWidgetId(widgetId: Int): Flow> = flow { 13 | val nodes = MemoryNodeDataStore.allNodes.filter { model -> model.widgetId == widgetId } 14 | emit(nodes) 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/github_search/repository/GitHubClient.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts.github_search.repository 2 | 3 | import com.toly1994.composeunit.layouts.github_search.repository.GitHubApi.searchUserRepo 4 | import com.toly1994.composeunit.layouts.github_search.repository.models.GithubRepo 5 | import retrofit2.http.GET 6 | import retrofit2.http.Path 7 | 8 | object GitHubApi { 9 | val baseUrl = "https://api.github.com/" 10 | const val searchUserRepo = "users/{username}/repos" 11 | } 12 | 13 | interface GitHubClient { 14 | 15 | @GET(searchUserRepo) 16 | suspend fun getRepositoryByUser(@Path("username") username: String): List 17 | 18 | } -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/base/BaseColorScheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme.base; 2 | 3 | import androidx.annotation.ColorInt; 4 | import androidx.annotation.NonNull; 5 | 6 | import java.util.regex.Pattern; 7 | 8 | /** 9 | * Base to spannable colors 10 | * @author Irineu A. Silva 11 | */ 12 | abstract public class BaseColorScheme extends BaseScheme { 13 | 14 | @ColorInt 15 | protected final int color; 16 | 17 | public BaseColorScheme(@NonNull Pattern pattern, @ColorInt int color) { 18 | super(pattern); 19 | this.color = color; 20 | } 21 | 22 | public BaseColorScheme(@ColorInt int color) { 23 | super(null); 24 | this.color = color; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | 11 | 12 | #009999 13 | #00627A 14 | #DD1045 15 | #93880D 16 | #FF00b0e8 17 | #FF6F42C1 18 | 19 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/core/SpanUtils.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.core; 2 | 3 | import android.text.Editable; 4 | import android.text.Spanned; 5 | 6 | /** 7 | * @author Irineu A. Silva 8 | */ 9 | final public class SpanUtils { 10 | 11 | private SpanUtils() {} 12 | 13 | public static void setSpan(Editable editable, Object span, int start, int end) { 14 | editable.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 15 | } 16 | 17 | public static void removeSpans(Editable editable, Class tClass, int start, int end) { 18 | Object[] spans = editable.getSpans(start, end, tClass); 19 | 20 | for (Object span : spans) { 21 | editable.removeSpan(span); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/models/WidgetModel.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.models 2 | 3 | import com.toly1994.composeunit.repository.database.entity.WidgetPo 4 | import com.toly1994.composeunit.repository.database.entity.WidgetPoMap 5 | 6 | data class WidgetModel( 7 | val id: Int, 8 | val name: String, 9 | val nameCN: String, 10 | val info: String, 11 | val family: String, 12 | val lever: Int, 13 | val collectd: Boolean, 14 | ) { 15 | fun toPo(): WidgetPo { 16 | val collectdValue = WidgetPoMap.widgetCollectdMap[collectd]!! 17 | val familyValue = WidgetPoMap.widgetFamilyMap[family]!! 18 | return WidgetPo( 19 | id, name, nameCN, info, lever, collectdValue, familyValue, 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/database/dao/NodeDao.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.database.dao 2 | 3 | import androidx.room.* 4 | import com.toly1994.composeunit.models.NodeModel 5 | import com.toly1994.composeunit.models.WidgetModel 6 | import com.toly1994.composeunit.repository.database.entity.WidgetPo 7 | import com.toly1994.composeunit.repository.database.entity.WidgetPoMap 8 | import kotlinx.coroutines.flow.Flow 9 | 10 | @Dao 11 | interface NodeDao { 12 | @Query("SELECT * FROM node WHERE widget_id = :widgetId") 13 | fun queryByWidgetId(widgetId:Int):Flow> 14 | 15 | @Insert(onConflict = OnConflictStrategy.REPLACE) 16 | fun insertAll(vararg data: NodeModel) 17 | 18 | @Query("DELETE from node") 19 | fun deleteAll() 20 | } -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/toly1994/composeunit/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.toly1994.composeunit", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/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 -------------------------------------------------------------------------------- /highlight/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 -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/BackgroundScheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme; 2 | 3 | import android.text.style.BackgroundColorSpan; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | import com.neo.highlight.util.scheme.base.BaseColorScheme; 8 | 9 | import java.util.regex.Pattern; 10 | 11 | /** 12 | * Paint the background 13 | * @author Irineu A. Silva 14 | */ 15 | final public class BackgroundScheme extends BaseColorScheme { 16 | 17 | public BackgroundScheme(@NonNull Pattern pattern, int color) { 18 | super(pattern, color); 19 | } 20 | 21 | public BackgroundScheme(int color) { 22 | super(color); 23 | } 24 | 25 | @NonNull 26 | @Override 27 | public Object getSpan(@NonNull CharSequence text, int start, int end) { 28 | return new BackgroundColorSpan(super.color); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/Scope.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import com.neo.highlight.core.Scheme; 7 | import com.neo.highlight.util.scheme.base.BaseScheme; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.regex.Pattern; 12 | 13 | /** 14 | * Scope for schemes 15 | * @author Irineu A. Silva 16 | */ 17 | final public class Scope extends BaseScheme { 18 | 19 | public Scope(@NonNull Pattern pattern, @NonNull Scheme... scopeSchemes) { 20 | super(pattern); 21 | setScopeSchemes(new ArrayList<>(Arrays.asList(scopeSchemes))); 22 | } 23 | 24 | @Override 25 | @Nullable 26 | public Object getSpan(@NonNull CharSequence text, int start, int end) { 27 | return null; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/ColorScheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme; 2 | 3 | import android.text.style.ForegroundColorSpan; 4 | 5 | import androidx.annotation.ColorInt; 6 | import androidx.annotation.NonNull; 7 | 8 | import com.neo.highlight.util.scheme.base.BaseColorScheme; 9 | 10 | import java.util.regex.Pattern; 11 | 12 | /** 13 | * Paint the text 14 | * @author Irineu A. Silva 15 | */ 16 | final public class ColorScheme extends BaseColorScheme { 17 | 18 | public ColorScheme(@NonNull Pattern pattern, @ColorInt int color) { 19 | super(pattern, color); 20 | } 21 | 22 | public ColorScheme(@ColorInt int color) { 23 | super(color); 24 | } 25 | 26 | @Override 27 | @NonNull 28 | public Object getSpan(@NonNull CharSequence text, int start, int end) { 29 | return new ForegroundColorSpan(color); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/impl/DbWidgetRepository.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.impl 2 | 3 | import com.toly1994.composeunit.models.WidgetModel 4 | import com.toly1994.composeunit.repository.WidgetRepository 5 | import com.toly1994.composeunit.repository.database.LocalDb 6 | import com.toly1994.composeunit.repository.memory.MemoryWidgetDataStore 7 | import kotlinx.coroutines.flow.* 8 | 9 | 10 | class DbWidgetRepository : WidgetRepository { 11 | 12 | override fun queryAllWidget(): Flow> { 13 | val pos = LocalDb.database.widgetDao().queryAll() 14 | return pos.map { it.map { po -> po.toModel() } } 15 | } 16 | 17 | override fun searchWidget(arg: String): Flow> { 18 | val pos = LocalDb.database.widgetDao().searchByName(arg) 19 | return pos.map { it.map { po -> po.toModel() } } 20 | } 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | | - | - | 2 | | --- | --- | 3 | | ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0380d817119c475e80f6a4f807a191d6~tplv-k3u1fbpfcp-watermark.image?) | ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/50ca721ddf48465980720e32e714cabe~tplv-k3u1fbpfcp-watermark.image?) | 4 | 5 | 6 | --- 7 | 8 | | - | - | 9 | | --- | --- | 10 | | ![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5a3f027c7a574bc18f9e15c07bbaee92~tplv-k3u1fbpfcp-watermark.image?) | ![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0a3dac68018d458b92a65cf97d348d3e~tplv-k3u1fbpfcp-watermark.image?) | 11 | 12 | 13 | --- 14 | 15 | | - | - | 16 | | --- | --- | 17 | | ![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8c413b918ca0428a8328579bb9bab81f~tplv-k3u1fbpfcp-watermark.image?) | ![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2eda7c9750e64b39931aeeacc54c63f8~tplv-k3u1fbpfcp-watermark.image?) | -------------------------------------------------------------------------------- /highlight/src/androidTest/java/com/neo/highlight/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.neo.highlight.test", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/impl/MemoryWidgetRepository.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.impl 2 | 3 | import com.toly1994.composeunit.models.WidgetModel 4 | import com.toly1994.composeunit.repository.WidgetRepository 5 | import com.toly1994.composeunit.repository.memory.MemoryWidgetDataStore 6 | import kotlinx.coroutines.flow.Flow 7 | import kotlinx.coroutines.flow.flow 8 | 9 | 10 | class MemoryWidgetRepository : WidgetRepository { 11 | 12 | override fun queryAllWidget(): Flow> = flow { 13 | emit(MemoryWidgetDataStore.allWidget) 14 | } 15 | 16 | override fun searchWidget(arg: String): Flow> = flow { 17 | emit(MemoryWidgetDataStore.allWidget.filter { model -> 18 | model.name.contains(arg, ignoreCase = true) || model.nameCN.contains( 19 | arg, ignoreCase = true 20 | ) 21 | }) 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.ui.theme 2 | 3 | import androidx.compose.material.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 | body1 = TextStyle( 12 | fontFamily = FontFamily.Default, 13 | fontWeight = FontWeight.Normal, 14 | fontSize = 16.sp 15 | ) 16 | /* Other default text styles to override 17 | button = TextStyle( 18 | fontFamily = FontFamily.Default, 19 | fontWeight = FontWeight.W500, 20 | fontSize = 14.sp 21 | ), 22 | caption = TextStyle( 23 | fontFamily = FontFamily.Default, 24 | fontWeight = FontWeight.Normal, 25 | fontSize = 12.sp 26 | ) 27 | */ 28 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/models/state/WidgetSearchState.kt: -------------------------------------------------------------------------------- 1 | //package com.toly1994.composeunit.models.state 2 | // 3 | //import androidx.compose.runtime.State 4 | //import androidx.compose.runtime.getValue 5 | //import androidx.compose.runtime.mutableStateOf 6 | //import androidx.compose.runtime.setValue 7 | //import androidx.lifecycle.SavedStateHandle 8 | //import androidx.lifecycle.ViewModel 9 | //import com.toly1994.composeunit.models.WidgetModel 10 | //import com.toly1994.composeunit.repository.WidgetRepository 11 | //import kotlinx.coroutines.flow.Flow 12 | // 13 | // 14 | //class WidgetSearchState { 15 | // var result: List by mutableStateOf(listOf()) 16 | //} 17 | // 18 | //class WidgetViewModel( 19 | // private val repository:WidgetRepository, 20 | // private val savedState:SavedStateHandle 21 | //):ViewModel(){ 22 | // 23 | //// val uiState :State 24 | // val widgets:Flow> = repository.getAllWidget() 25 | //} -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/github_search/repository/GithubRepository.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts.github_search.repository 2 | 3 | import com.toly1994.composeunit.layouts.github_search.repository.models.GithubRepo 4 | import kotlinx.coroutines.flow.Flow 5 | import kotlinx.coroutines.flow.flow 6 | import retrofit2.Retrofit 7 | import retrofit2.converter.gson.GsonConverterFactory 8 | import retrofit2.create 9 | 10 | class GithubRepository { 11 | 12 | private val retorfit: Retrofit by lazy { 13 | Retrofit.Builder() 14 | .baseUrl(GitHubApi.baseUrl) 15 | .addConverterFactory(GsonConverterFactory.create()) 16 | .build() 17 | } 18 | 19 | private val gitHubClient = retorfit.create() 20 | 21 | suspend fun getRepositoryByUser(username: String = "toly1994328"): Flow> = 22 | flow { 23 | val data = gitHubClient.getRepositoryByUser(username) 24 | emit(data) 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/database/dao/WidgetDao.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.database.dao 2 | 3 | import androidx.room.* 4 | import com.toly1994.composeunit.models.WidgetModel 5 | import com.toly1994.composeunit.repository.database.entity.WidgetPo 6 | import com.toly1994.composeunit.repository.database.entity.WidgetPoMap 7 | import kotlinx.coroutines.flow.Flow 8 | 9 | @Dao 10 | interface WidgetDao { 11 | @Query("SELECT * FROM widget") 12 | fun queryAll(): Flow> 13 | 14 | @Query("SELECT * FROM widget WHERE id = :id") 15 | fun queryById(id:Int):Flow> 16 | 17 | @Query("SELECT * FROM widget WHERE name LIKE :arg OR name_cn LIKE :arg") 18 | fun searchByName(arg:String): Flow> 19 | 20 | @Insert(onConflict = OnConflictStrategy.REPLACE) 21 | fun insertAll(vararg widgetPo: WidgetPo) 22 | 23 | @Delete 24 | fun delete(widgetPo: WidgetPo) 25 | 26 | @Query("DELETE from widget") 27 | fun deleteAll() 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/app/ComposeUnitApp.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.app 2 | 3 | import androidx.compose.runtime.Composable 4 | import com.toly1994.composeunit.app.data_manager.DataManagePage 5 | import com.toly1994.composeunit.app.navigation.UnitNavigation 6 | import com.toly1994.composeunit.details.WidgetDetail 7 | import com.toly1994.composeunit.layouts.counter.CountViewModel 8 | import com.toly1994.composeunit.layouts.counter.CounterPageV2 9 | import com.toly1994.composeunit.layouts.github_search.views.GithubSearchPage 10 | import com.toly1994.composeunit.widgets.Center 11 | import com.toly1994.composeunit.widgets.WidgetNodeMap 12 | 13 | @Composable 14 | fun ComposeUnitApp( 15 | onShare: (String) -> Unit, 16 | ) { 17 | UnitNavigation(onShare=onShare) 18 | // DataManagePage() 19 | // GithubSearchPage() 20 | // CounterPageV2(title = "计时器 ViewModel + Flow") 21 | // WidgetDetail(onShare = onShare) { 22 | // 23 | // } 24 | // Center { 25 | // WidgetNodeMap(10,0) 26 | // } 27 | 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/components/tolyui/Panel.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.components.tolyui 2 | 3 | import androidx.compose.foundation.layout.Box 4 | import androidx.compose.foundation.layout.fillMaxWidth 5 | import androidx.compose.foundation.layout.padding 6 | import androidx.compose.foundation.shape.RoundedCornerShape 7 | import androidx.compose.material.Surface 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.ui.Modifier 10 | import androidx.compose.ui.draw.clip 11 | import androidx.compose.ui.graphics.Color 12 | import androidx.compose.ui.unit.dp 13 | 14 | @Composable 15 | fun Panel( 16 | radius: Float = 5.0f, 17 | color: Color = Color(0xffF6F8FA), 18 | content: @Composable () -> Unit, 19 | ) { 20 | Surface( 21 | color = color, 22 | modifier = Modifier 23 | .fillMaxWidth() 24 | .padding(10.dp) 25 | .clip(RoundedCornerShape(radius.dp)) 26 | ) { 27 | Box(modifier = Modifier.padding(10.dp) 28 | ) { content() } 29 | } 30 | } -------------------------------------------------------------------------------- /highlight/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'maven-publish' 4 | } 5 | 6 | android { 7 | compileSdk 31 8 | 9 | defaultConfig { 10 | minSdk 21 11 | targetSdk 31 12 | versionCode 3 13 | versionName "1.0.4" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | consumerProguardFiles "consumer-rules.pro" 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_7 27 | targetCompatibility JavaVersion.VERSION_1_7 28 | } 29 | } 30 | 31 | dependencies { 32 | 33 | implementation 'androidx.appcompat:appcompat:1.4.0' 34 | implementation 'com.google.android.material:material:1.4.0' 35 | testImplementation 'junit:junit:4.+' 36 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 37 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 38 | } 39 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/OnMatchScheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import com.neo.highlight.util.scheme.base.BaseScheme; 7 | 8 | import java.util.regex.Pattern; 9 | 10 | /** 11 | * Execute action when match 12 | * @author Irineu A. Silva 13 | */ 14 | final public class OnMatchScheme extends BaseScheme { 15 | 16 | @NonNull 17 | private final OnMatchListener onMatchListener; 18 | 19 | public OnMatchScheme(@NonNull Pattern pattern, @NonNull OnMatchListener onMatchListener) { 20 | super(pattern); 21 | this.onMatchListener = onMatchListener; 22 | } 23 | 24 | public OnMatchScheme(@NonNull OnMatchListener onMatchListener) { 25 | super(null); 26 | this.onMatchListener = onMatchListener; 27 | } 28 | 29 | @Nullable 30 | @Override 31 | public Object getSpan(@NonNull CharSequence text, int start, int end) { 32 | onMatchListener.onMatch(text, start, end); 33 | return null; 34 | } 35 | 36 | public interface OnMatchListener { 37 | void onMatch(CharSequence text, int start, int end); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Text/node1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Text 2 | 3 | import androidx.compose.material.Text 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.graphics.Color 6 | import androidx.compose.ui.text.TextStyle 7 | import androidx.compose.ui.text.font.FontStyle 8 | import androidx.compose.ui.text.font.FontWeight 9 | import androidx.compose.ui.tooling.preview.Preview 10 | import androidx.compose.ui.unit.sp 11 | 12 | // "widgetId": 1, 13 | // "name": "文字的基本样式", 14 | // "subtitle": 15 | // 【text】 : 文字 【String】 16 | // 【style】: 文字样式 【TextStyle】 17 | // 【color】: 文字颜色 【Color】 18 | // 【fontSize】: 文字大小 【TextUnit】 19 | // 【fontWeight】: 字重 【FontWeight?】 20 | // 【fontStyle】: 字体样式 【FontStyle?】 21 | // 【letterSpacing】: 字距 【TextUnit】 22 | 23 | @Composable 24 | fun TextNode1() { 25 | val style = TextStyle( 26 | color = Color.Blue, 27 | fontSize = 20.sp, 28 | fontStyle = FontStyle.Italic, 29 | fontWeight = FontWeight.Bold, 30 | letterSpacing = 10.sp 31 | ) 32 | Text( 33 | text = "toly-张风捷特烈-1994`", 34 | style = style, 35 | ) 36 | } 37 | 38 | @Preview 39 | @Composable 40 | fun TextNode1Preview() { 41 | TextNode1() 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Text/node4.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Text 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.padding 5 | import androidx.compose.foundation.layout.width 6 | import androidx.compose.material.Text 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.graphics.Color 10 | import androidx.compose.ui.text.style.TextOverflow 11 | import androidx.compose.ui.tooling.preview.Preview 12 | import androidx.compose.ui.unit.dp 13 | import androidx.compose.ui.unit.sp 14 | 15 | // "widgetId": 1, 16 | // "name": "多行与包裹溢出", 17 | // "subtitle": 18 | // 【softWrap】 : 是否自动换行 【Boolean】 19 | // 【overflow】: 溢出方式 【TextOverflow】 20 | // 【maxLines】: 最大行数 【Int】 21 | 22 | @Composable 23 | fun TextNode4() { 24 | Text( 25 | modifier = Modifier 26 | .width(200.dp) 27 | .background(Color(0xffEFEFEF)) 28 | .padding(10.dp), 29 | text = "ComposeUnit is an application for learn Compose.", 30 | fontSize = 16.sp, 31 | softWrap = true, 32 | overflow = TextOverflow.Ellipsis, 33 | maxLines = 2, 34 | ) 35 | } 36 | 37 | @Preview 38 | @Composable 39 | fun TextNode4Preview() { 40 | TextNode4() 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.ui.theme 2 | 3 | import androidx.compose.foundation.isSystemInDarkTheme 4 | import androidx.compose.material.MaterialTheme 5 | import androidx.compose.material.darkColors 6 | import androidx.compose.material.lightColors 7 | import androidx.compose.runtime.Composable 8 | 9 | private val DarkColorPalette = darkColors( 10 | primary = Purple200, 11 | primaryVariant = Purple700, 12 | secondary = Teal200 13 | ) 14 | 15 | private val LightColorPalette = lightColors( 16 | primary = Purple500, 17 | primaryVariant = Purple700, 18 | secondary = Teal200 19 | 20 | /* Other default colors to override 21 | background = Color.White, 22 | surface = Color.White, 23 | onPrimary = Color.White, 24 | onSecondary = Color.Black, 25 | onBackground = Color.Black, 26 | onSurface = Color.Black, 27 | */ 28 | ) 29 | 30 | @Composable 31 | fun ComposeUnitTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { 32 | val colors = if (darkTheme) { 33 | DarkColorPalette 34 | } else { 35 | LightColorPalette 36 | } 37 | 38 | MaterialTheme( 39 | colors = colors, 40 | typography = Typography, 41 | shapes = Shapes, 42 | content = content 43 | ) 44 | } -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/core/HighlightContract.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.core; 2 | 3 | import android.text.Editable; 4 | import android.text.SpannableString; 5 | import android.widget.TextView; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author Irineu A. Silva 13 | */ 14 | public interface HighlightContract { 15 | 16 | //setSpan EditText 17 | void setSpan(Editable editable, int start, int end); 18 | void setSpan(Editable editable); 19 | 20 | //setSpan TextView 21 | void setSpan(TextView textView, int start, int end); 22 | void setSpan(TextView textView); 23 | 24 | //setSpan Spannable 25 | void setSpan(SpannableString spannableString, int start, int end); 26 | void setSpan(SpannableString spannableString); 27 | 28 | //removeSpan EditText 29 | void removeSpan(Editable editable, int start, int end); 30 | void removeSpan(Editable editable); 31 | 32 | //schemes 33 | List getSchemes(); 34 | void setSchemes(@NonNull List schemes); 35 | void addScheme(@NonNull Scheme... scheme); 36 | void clearScheme(); 37 | 38 | //types 39 | List> getSpanTypes(); 40 | void setSpanTypes(@NonNull List> spanTypes); 41 | void addSpanType(Class span); 42 | void clearSpanTypes(); 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import androidx.activity.ComponentActivity 7 | import androidx.activity.compose.setContent 8 | import androidx.activity.viewModels 9 | import androidx.core.view.WindowCompat 10 | import androidx.room.Room 11 | import com.toly1994.composeunit.app.ComposeUnitApp 12 | import com.toly1994.composeunit.layouts.counter.CountViewModel 13 | import com.toly1994.composeunit.repository.database.ComposeUnitDB 14 | import com.toly1994.composeunit.repository.database.entity.WidgetPo 15 | import com.toly1994.composeunit.repository.memory.MemoryWidgetDataStore 16 | 17 | 18 | class MainActivity : ComponentActivity() { 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContent { 23 | ComposeUnitApp( 24 | onShare = { 25 | share(it) 26 | } 27 | ) 28 | } 29 | } 30 | 31 | private fun share(content: String) { 32 | val shareIntent = Intent(Intent.ACTION_SEND) 33 | shareIntent.setType("text/plain") 34 | shareIntent.putExtra(Intent.EXTRA_TEXT, content) 35 | startActivity(Intent.createChooser(shareIntent, "代码分享")) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/database/entity/WidgetPo.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.database.entity 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | import com.toly1994.composeunit.models.WidgetModel 7 | 8 | @Entity(tableName = "widget") 9 | data class WidgetPo( 10 | @PrimaryKey 11 | val id: Int, 12 | @ColumnInfo 13 | val name: String, 14 | @ColumnInfo(name = "name_cn") 15 | val nameCN: String, 16 | @ColumnInfo 17 | val info: String, 18 | @ColumnInfo 19 | val lever: Int, 20 | @ColumnInfo 21 | val collectd: Int, // 对应关系见 [PoMap#widgetCollectdMap] 22 | @ColumnInfo 23 | val family: Int, // 对应关系见 [PoMap#widgetFamilyMap] 24 | ){ 25 | fun toModel(): WidgetModel { 26 | val collectdValue = WidgetPoMap.widgetCollectdMap.keys.toList()[collectd] 27 | val familyValue = WidgetPoMap.widgetFamilyMap.keys.toList()[family] 28 | return WidgetModel( 29 | id, name, nameCN, info, familyValue,lever, collectdValue, 30 | ) 31 | } 32 | } 33 | 34 | object WidgetPoMap { 35 | // // 收藏 0 未收藏 1 36 | val widgetCollectdMap = mapOf( 37 | false to 0, 38 | true to 1, 39 | ) 40 | val widgetFamilyMap = mapOf( 41 | "无内容组件" to 0, 42 | "单内容组件" to 1, 43 | "多内容组件" to 2, 44 | "卡槽型组件" to 3, 45 | ) 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Text/node2.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Text 2 | 3 | import androidx.compose.material.Text 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | import androidx.compose.ui.draw.clip 7 | import androidx.compose.ui.geometry.Offset 8 | import androidx.compose.ui.graphics.Color 9 | import androidx.compose.ui.graphics.RectangleShape 10 | import androidx.compose.ui.graphics.Shadow 11 | import androidx.compose.ui.text.TextStyle 12 | import androidx.compose.ui.text.font.FontStyle 13 | import androidx.compose.ui.text.font.FontWeight 14 | import androidx.compose.ui.tooling.preview.Preview 15 | import androidx.compose.ui.unit.sp 16 | 17 | // "widgetId": 1, 18 | // "name": "文字背景与阴影", 19 | // "subtitle": 20 | // 【backgroundColor】 : 背景颜色 【Color】 21 | // 【shadow】: 阴影 【Shadow】 22 | 23 | @Composable 24 | fun TextNode2() { 25 | val style = TextStyle( 26 | color = Color.White, 27 | fontSize = 50.sp, 28 | background = Color.Black, 29 | shadow = Shadow( 30 | color = Color.Cyan, 31 | offset = Offset(1f,1f), 32 | blurRadius = 10f 33 | ) 34 | ) 35 | Text( 36 | text = "张风捷特烈", 37 | style = style, 38 | modifier = Modifier.clip(RectangleShape) 39 | ) 40 | } 41 | 42 | @Preview 43 | @Composable 44 | fun TextNode2Preview() { 45 | TextNode2() 46 | } 47 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | android.injected.testOnly=false -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/StyleScheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme; 2 | 3 | import android.graphics.Typeface; 4 | import android.text.style.StyleSpan; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import com.neo.highlight.util.scheme.base.BaseScheme; 9 | 10 | import java.util.regex.Pattern; 11 | 12 | /** 13 | * Pain text style 14 | * @author Irineu A. Silva 15 | */ 16 | final public class StyleScheme extends BaseScheme { 17 | 18 | @NonNull 19 | private final STYLE style; 20 | 21 | public StyleScheme(@NonNull Pattern pattern, @NonNull STYLE style) { 22 | super(pattern); 23 | this.style = style; 24 | } 25 | 26 | public StyleScheme(@NonNull STYLE style) { 27 | super(null); 28 | this.style = style; 29 | } 30 | 31 | @NonNull 32 | @Override 33 | public Object getSpan(@NonNull CharSequence text, int start, int end) { 34 | return new StyleSpan(getType()); 35 | } 36 | 37 | private int getType() { 38 | switch (style) { 39 | 40 | case NORMAL: 41 | return Typeface.NORMAL; 42 | case ITALIC: 43 | return Typeface.ITALIC; 44 | case BOLD: 45 | return Typeface.BOLD; 46 | case BOLD_ITALIC: 47 | return Typeface.BOLD_ITALIC; 48 | } 49 | 50 | return Typeface.NORMAL; 51 | } 52 | 53 | public enum STYLE { 54 | NORMAL, 55 | ITALIC, 56 | BOLD, 57 | BOLD_ITALIC 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/home/WidgetViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.home 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.toly1994.composeunit.models.WidgetModel 6 | import com.toly1994.composeunit.repository.impl.MemoryWidgetRepository 7 | import com.toly1994.composeunit.repository.WidgetRepository 8 | import com.toly1994.composeunit.repository.impl.DbWidgetRepository 9 | import kotlinx.coroutines.flow.MutableStateFlow 10 | import kotlinx.coroutines.flow.StateFlow 11 | import kotlinx.coroutines.flow.catch 12 | import kotlinx.coroutines.launch 13 | 14 | class WidgetViewModel ( 15 | private val repository: WidgetRepository = MemoryWidgetRepository() 16 | // private val repository: WidgetRepository = DbWidgetRepository() 17 | ): ViewModel() { 18 | // 状态数据 19 | private val _uiState = MutableStateFlow(WidgetModelState()) 20 | val uiState: StateFlow = _uiState 21 | 22 | init { 23 | loadData() 24 | } 25 | 26 | fun loadData(){ 27 | viewModelScope.launch { 28 | repository.queryAllWidget() 29 | .catch { ex -> 30 | _uiState.value = WidgetModelState(error = ex.message) 31 | } 32 | .collect { data -> 33 | _uiState.value = WidgetModelState( 34 | models = data 35 | ) 36 | } 37 | } 38 | } 39 | 40 | } 41 | 42 | data class WidgetModelState( 43 | val models: List = listOf(), 44 | val error: String? = null 45 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/database/ComposeUnitDB.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.database 2 | 3 | import android.content.Context 4 | import android.util.Log 5 | import androidx.room.Database 6 | import androidx.room.Room 7 | import androidx.room.RoomDatabase 8 | import androidx.sqlite.db.SupportSQLiteDatabase 9 | import com.toly1994.composeunit.models.NodeModel 10 | import com.toly1994.composeunit.repository.database.dao.NodeDao 11 | import com.toly1994.composeunit.repository.database.dao.WidgetDao 12 | import com.toly1994.composeunit.repository.database.entity.WidgetPo 13 | import java.io.File 14 | 15 | object LocalDb{ 16 | // 数据库名 17 | private const val dbName: String = "compose_unit.db" 18 | 19 | lateinit var database: ComposeUnitDB 20 | private set 21 | 22 | fun offer(context: Context) { 23 | database = Room.databaseBuilder(context, ComposeUnitDB::class.java, dbName) 24 | .allowMainThreadQueries() //允许在主线程操作 25 | .addCallback(DbCreateCallBack) // 回调监听 26 | // .addMigrations()// 数据库升级 27 | .build() 28 | } 29 | 30 | private object DbCreateCallBack : RoomDatabase.Callback() { 31 | override fun onOpen(db: SupportSQLiteDatabase) { 32 | Log.e("LocalDb", "onOpen: " + db.version) 33 | } 34 | 35 | override fun onCreate(db: SupportSQLiteDatabase) { 36 | super.onCreate(db) 37 | Log.e("LocalDb", "first onCreate db version: " + db.version) 38 | } 39 | } 40 | } 41 | 42 | @Database(entities = [WidgetPo::class,NodeModel::class], version = 1, exportSchema = false) 43 | abstract class ComposeUnitDB : RoomDatabase() { 44 | abstract fun widgetDao(): WidgetDao 45 | abstract fun nodeDao(): NodeDao 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Column/node3.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Column 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.layout.* 6 | import androidx.compose.material.Text 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.Alignment 9 | import androidx.compose.ui.Modifier 10 | import androidx.compose.ui.graphics.Color 11 | import androidx.compose.ui.layout.ContentScale 12 | import androidx.compose.ui.res.painterResource 13 | import androidx.compose.ui.text.TextStyle 14 | import androidx.compose.ui.text.font.FontStyle 15 | import androidx.compose.ui.text.font.FontWeight 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import androidx.compose.ui.unit.dp 18 | import androidx.compose.ui.unit.sp 19 | import com.toly1994.composeunit.R 20 | import com.toly1994.composeunit.widgets.Image.ImageContentScaleItem 21 | 22 | // "widgetId": 5, 23 | // "name": "列中的组件高度占比", 24 | // "subtitle": 25 | // Modifier 的 weight 属性只能用于 Row 和 Column 中,该案例里蓝色和绿色区域高度占比 1:2,且无视盒自身高度,使 Column 区域竖向占满。 26 | 27 | @Composable 28 | fun ColumnNode3() { 29 | val colors = arrayOf(Color.Red, Color.Blue, Color.Green,) 30 | Column( 31 | Modifier.width(250.dp).height(100.dp).background(Color(0xffEFEFEF)), 32 | horizontalAlignment = Alignment.CenterHorizontally 33 | ) { 34 | Spacer(Modifier.width(30.dp).height(30.dp).background(colors[0])) 35 | Spacer(Modifier.width(30.dp).height(30.dp).background(colors[1]).weight(1f)) 36 | Spacer(Modifier.width(30.dp).height(30.dp).background(colors[2]).weight(2f)) 37 | } 38 | } 39 | 40 | @Preview 41 | @Composable 42 | fun ColumnNode3Preview() { 43 | ColumnNode3() 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Text/node3.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Text 2 | 3 | import androidx.compose.foundation.layout.Row 4 | import androidx.compose.foundation.layout.padding 5 | import androidx.compose.material.Text 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.Modifier 8 | import androidx.compose.ui.draw.clip 9 | import androidx.compose.ui.geometry.Offset 10 | import androidx.compose.ui.graphics.Color 11 | import androidx.compose.ui.graphics.RectangleShape 12 | import androidx.compose.ui.graphics.Shadow 13 | import androidx.compose.ui.text.TextStyle 14 | import androidx.compose.ui.text.font.FontStyle 15 | import androidx.compose.ui.text.font.FontWeight 16 | import androidx.compose.ui.text.style.TextDecoration 17 | import androidx.compose.ui.text.style.TextIndent 18 | import androidx.compose.ui.tooling.preview.Preview 19 | import androidx.compose.ui.unit.dp 20 | import androidx.compose.ui.unit.sp 21 | 22 | // "widgetId": 1, 23 | // "name": "文字装饰线与缩进", 24 | // "subtitle": 25 | // 【textDecoration】 : 文字装饰 【TextDecoration】 26 | // 【textIndent】: 文字缩进 【textIndent】 27 | 28 | @Composable 29 | fun TextNode3() { 30 | val style1 = TextStyle( 31 | fontSize = 25.sp, 32 | textDecoration = TextDecoration.LineThrough 33 | ) 34 | val style2 = TextStyle( 35 | fontSize = 25.sp, 36 | textIndent = TextIndent(20.sp), 37 | textDecoration = TextDecoration.Underline 38 | ) 39 | Row{ 40 | Text( 41 | text = "张风捷特烈", 42 | style = style1, 43 | ) 44 | Text( 45 | text = "张风捷特烈", 46 | style = style2, 47 | ) 48 | } 49 | } 50 | 51 | @Preview 52 | @Composable 53 | fun TextNode3Preview() { 54 | TextNode3() 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Row/node3.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Row 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.material.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.layout.ContentScale 13 | import androidx.compose.ui.res.painterResource 14 | import androidx.compose.ui.text.TextStyle 15 | import androidx.compose.ui.text.font.FontStyle 16 | import androidx.compose.ui.text.font.FontWeight 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | import androidx.compose.ui.unit.sp 20 | import com.toly1994.composeunit.R 21 | import com.toly1994.composeunit.widgets.Image.ImageContentScaleItem 22 | 23 | // "widgetId": 4, 24 | // "name": "行中的组件宽度占比", 25 | // "subtitle": 26 | // Modifier 的 weight 属性只能用于 Row 和 Column 中,该案例里蓝色和绿色区域宽度占比 1:2,且无视盒自身宽度,使 Row 区域横向占满。 27 | @SuppressLint("SuspiciousIndentation") 28 | @Composable 29 | fun RowNode3() { 30 | val colors = arrayOf(Color.Red, Color.Blue, Color.Green,) 31 | Row( 32 | Modifier.width(250.dp).height(100.dp).background(Color(0xffEFEFEF)), 33 | verticalAlignment = Alignment.CenterVertically 34 | ) { 35 | Spacer(Modifier.width(30.dp).height(30.dp).background(colors[0])) 36 | Spacer(Modifier.width(30.dp).height(30.dp).background(colors[1]).weight(1f)) 37 | Spacer(Modifier.width(30.dp).height(30.dp).background(colors[2]).weight(2f)) 38 | } 39 | } 40 | 41 | @Preview 42 | @Composable 43 | fun RowNode3Preview() { 44 | RowNode3() 45 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Box/node1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Box 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.material.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.layout.ContentScale 13 | import androidx.compose.ui.res.painterResource 14 | import androidx.compose.ui.text.TextStyle 15 | import androidx.compose.ui.text.font.FontStyle 16 | import androidx.compose.ui.text.font.FontWeight 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | import androidx.compose.ui.unit.sp 20 | import com.toly1994.composeunit.R 21 | import com.toly1994.composeunit.widgets.Image.ImageContentScaleItem 22 | 23 | // "widgetId": 6, 24 | // "name": "Box 的对齐方式", 25 | // "subtitle": 26 | // 【contentAlignment】 : 内容对齐模式 【Alignment】 27 | // 【content】: 内容组件列表 【@Composable BoxScope.() -> Unit】 28 | 29 | @SuppressLint("SuspiciousIndentation") 30 | @Composable 31 | fun BoxNode1() { 32 | val colors = arrayOf(Color.Red, Color.Yellow , Color.Blue, Color.Green) 33 | Box( 34 | Modifier.width(250.dp).height(100.dp).background(Color(0xffEFEFEF)), 35 | contentAlignment = Alignment.Center 36 | ) { 37 | Spacer(Modifier.width(60.dp).height(60.dp).background(colors[3])) 38 | Spacer(Modifier.width(50.dp).height(50.dp).background(colors[2])) 39 | Spacer(Modifier.width(40.dp).height(40.dp).background(colors[1])) 40 | Spacer(Modifier.width(30.dp).height(30.dp).background(colors[0])) 41 | } 42 | } 43 | 44 | @Preview 45 | @Composable 46 | fun BoxNode1Preview() { 47 | BoxNode1() 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Box/node2.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Box 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.material.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.layout.ContentScale 13 | import androidx.compose.ui.res.painterResource 14 | import androidx.compose.ui.text.TextStyle 15 | import androidx.compose.ui.text.font.FontStyle 16 | import androidx.compose.ui.text.font.FontWeight 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | import androidx.compose.ui.unit.sp 20 | import com.toly1994.composeunit.R 21 | import com.toly1994.composeunit.widgets.Image.ImageContentScaleItem 22 | 23 | // "widgetId": 6, 24 | // "name": "修改单个子组件的对齐方式", 25 | // "subtitle": 26 | // BoxScope 中定义了 Modifier.align, 通过它可以修改某一组件的对齐方式。本案例中内容底部居中,红色组件在右上方。 27 | 28 | @SuppressLint("SuspiciousIndentation") 29 | @Composable 30 | fun BoxNode2() { 31 | val colors = arrayOf(Color.Red, Color.Yellow , Color.Blue, Color.Green) 32 | Box( 33 | Modifier.width(250.dp).height(100.dp).background(Color(0xffEFEFEF)), 34 | contentAlignment = Alignment.BottomCenter 35 | ) { 36 | Spacer(Modifier.width(60.dp).height(60.dp).background(colors[3])) 37 | Spacer(Modifier.width(50.dp).height(50.dp).background(colors[2])) 38 | Spacer(Modifier.width(40.dp).height(40.dp).background(colors[1])) 39 | Spacer(Modifier.width(30.dp).height(30.dp).background(colors[0]) 40 | .align(Alignment.TopEnd)) 41 | } 42 | } 43 | 44 | @Preview 45 | @Composable 46 | fun BoxNode2Preview() { 47 | BoxNode2() 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/home/UnitHomePage.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.home 2 | 3 | import android.util.Log 4 | import androidx.compose.foundation.ScrollState 5 | import androidx.compose.foundation.clickable 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.foundation.lazy.LazyColumn 8 | import androidx.compose.foundation.lazy.itemsIndexed 9 | import androidx.compose.foundation.verticalScroll 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.runtime.collectAsState 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.unit.dp 14 | import androidx.lifecycle.viewmodel.compose.viewModel 15 | import com.toly1994.composeunit.layouts.UnitWidgetItemV1 16 | import com.toly1994.composeunit.models.WidgetModel 17 | import com.toly1994.composeunit.repository.memory.MemoryWidgetDataStore 18 | 19 | @Composable 20 | fun HomeWidgetList() { 21 | Column( 22 | Modifier 23 | .verticalScroll(ScrollState(0)) 24 | .padding(bottom = 20.dp) 25 | ) { 26 | MemoryWidgetDataStore.allWidget.forEach { widget -> 27 | Box(modifier = Modifier.padding(top = 10.dp)) { 28 | UnitWidgetItemV1(model = widget) 29 | } 30 | } 31 | } 32 | } 33 | 34 | @Composable 35 | fun HomeLazyWidgetList( 36 | viewModel: WidgetViewModel = viewModel(), 37 | onTapItem: (WidgetModel) -> Unit, 38 | ) { 39 | val data = viewModel.uiState.collectAsState().value.models 40 | LazyColumn( 41 | verticalArrangement = Arrangement.spacedBy(10.dp), 42 | contentPadding = PaddingValues(top = 10.dp, bottom = 10.dp) 43 | ) { 44 | itemsIndexed(data) { index, widget -> 45 | UnitWidgetItemV1(model = widget, 46 | modifier = Modifier.clickable { 47 | onTapItem(widget) 48 | }) 49 | Log.d("HomeLazyWidgetList", "$index") 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/details/NodeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.details 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import androidx.navigation.NavHostController 6 | import com.toly1994.composeunit.app.navigation.UnitRoute 7 | import com.toly1994.composeunit.models.NodeModel 8 | import com.toly1994.composeunit.models.WidgetModel 9 | import com.toly1994.composeunit.repository.NodeRepository 10 | import com.toly1994.composeunit.repository.impl.DbNodeRepository 11 | import com.toly1994.composeunit.repository.impl.MemoryNodeRepository 12 | import kotlinx.coroutines.flow.MutableStateFlow 13 | import kotlinx.coroutines.flow.StateFlow 14 | import kotlinx.coroutines.flow.catch 15 | import kotlinx.coroutines.launch 16 | 17 | class NodeViewModel( 18 | private val repository: NodeRepository = MemoryNodeRepository() 19 | // private val repository: NodeRepository = DbNodeRepository() 20 | ) : ViewModel() { 21 | // 状态数据 22 | private val _uiState = MutableStateFlow(NodeModelState()) 23 | val uiState: StateFlow = _uiState 24 | 25 | fun handleEnterWidget(model: WidgetModel, topNavCtrl: NavHostController) { 26 | viewModelScope.launch { 27 | repository.queryNodeByWidgetId(model.id) 28 | .catch { ex -> 29 | _uiState.value = NodeModelState( 30 | error = ex.message, 31 | widget = model 32 | ) 33 | } 34 | .collect { data -> 35 | _uiState.value = NodeModelState( 36 | widget = model, 37 | nodes = data 38 | ) 39 | topNavCtrl.navigate(UnitRoute.widgetDetail) 40 | } 41 | } 42 | } 43 | } 44 | 45 | data class NodeModelState( 46 | val widget: WidgetModel? = null, 47 | val nodes: List = listOf(), 48 | val error: String? = null 49 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/github_search/view_model/NodeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts.github_search.view_model 2 | 3 | import android.util.Log 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.viewModelScope 6 | import com.toly1994.composeunit.layouts.github_search.repository.GithubRepository 7 | import com.toly1994.composeunit.layouts.github_search.repository.models.GithubRepo 8 | import kotlinx.coroutines.flow.MutableStateFlow 9 | import kotlinx.coroutines.flow.StateFlow 10 | import kotlinx.coroutines.flow.catch 11 | import kotlinx.coroutines.launch 12 | 13 | class GithubSearchViewModel( 14 | private val repository: GithubRepository = GithubRepository() 15 | ) : ViewModel() { 16 | 17 | // 状态数据 18 | private val _uiState = MutableStateFlow(GithubRepoUIState.Init) 19 | val uiState: StateFlow = _uiState 20 | 21 | fun searchRepositoryByUserName(arg: String) { 22 | if (arg == "") { 23 | _uiState.value = GithubRepoUIState.Init 24 | return 25 | } 26 | viewModelScope.launch { 27 | _uiState.value = GithubRepoUIState.Loading 28 | repository.getRepositoryByUser(arg) 29 | .catch { ex -> 30 | _uiState.value = GithubRepoUIState.Error( 31 | error = ex.message, 32 | ) 33 | } 34 | .collect { data -> 35 | Log.d("RepositoryByUserName", "searchRepositoryByUserName: ${data.size}") 36 | _uiState.value = GithubRepoUIState.Fill( 37 | repos = data 38 | ) 39 | } 40 | } 41 | } 42 | } 43 | 44 | sealed class GithubRepoUIState{ 45 | data class Fill( 46 | val repos: List = listOf(), 47 | ):GithubRepoUIState() 48 | 49 | object Loading : GithubRepoUIState() 50 | 51 | data class Error( 52 | val error: String? = null 53 | ):GithubRepoUIState() 54 | 55 | object Init:GithubRepoUIState() 56 | } -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/LinkScheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme; 2 | 3 | import android.text.TextPaint; 4 | import android.text.style.URLSpan; 5 | 6 | import androidx.annotation.ColorInt; 7 | import androidx.annotation.NonNull; 8 | 9 | import com.neo.highlight.util.scheme.base.BaseScheme; 10 | import com.neo.highlight.util.scheme.contract.LinkSchemeContract; 11 | 12 | import java.util.regex.Pattern; 13 | 14 | /** 15 | * Pain and makes clickable links 16 | * @author Irineu A. Silva 17 | */ 18 | final public class LinkScheme extends BaseScheme implements LinkSchemeContract { 19 | 20 | private boolean painText = true; 21 | 22 | private boolean painTextUnderline = true; 23 | 24 | @ColorInt 25 | private int painTextColor = -1; 26 | 27 | public LinkScheme() { 28 | super(Pattern.compile("\\bhttps?://[^\\s]+\\b/?")); 29 | } 30 | 31 | @Override 32 | public Object getSpan(@NonNull CharSequence text, int start, int end) { 33 | return new URLSpan(text.toString()) { 34 | @Override 35 | public void updateDrawState(@NonNull TextPaint ds) { 36 | 37 | if (painText) { 38 | 39 | if (painTextColor == -1) { 40 | ds.setColor(ds.linkColor); 41 | } else { 42 | ds.setColor(painTextColor); 43 | } 44 | 45 | ds.setUnderlineText(painTextUnderline); 46 | }; 47 | } 48 | }; 49 | } 50 | 51 | //override LinkSchemeContract 52 | @Override 53 | public LinkScheme setPainText(boolean painText) { 54 | this.painText = painText; 55 | return this; 56 | } 57 | 58 | @Override 59 | public LinkScheme setPainTextColor(@ColorInt int painTextColor) { 60 | this.painTextColor = painTextColor; 61 | return setPainText(true); 62 | } 63 | 64 | @Override 65 | public LinkScheme setPainTextUnderline(boolean painTextUnderline) { 66 | this.painTextUnderline = painTextUnderline; 67 | return this; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/base/BaseScheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme.base; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import com.neo.highlight.core.Scheme; 7 | import com.neo.highlight.util.scheme.contract.SchemeScope; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | import java.util.regex.Pattern; 13 | 14 | /** 15 | * Base to schemes 16 | * @author Irineu A. Silva 17 | */ 18 | abstract public class BaseScheme implements Scheme, SchemeScope { 19 | 20 | @Nullable 21 | private List scopeSchemes; 22 | 23 | @Nullable 24 | private final Pattern pattern; 25 | 26 | private boolean clearOldSpan = false; 27 | 28 | public BaseScheme(@Nullable Pattern pattern) { 29 | this.pattern = pattern; 30 | } 31 | 32 | //override Scheme 33 | 34 | @Nullable 35 | @Override 36 | public Pattern getRegex() { 37 | return pattern; 38 | } 39 | 40 | 41 | @Override 42 | public boolean getClearOldSpan() { 43 | return clearOldSpan; 44 | } 45 | 46 | @NonNull 47 | @Override 48 | public BaseScheme setClearOldSpan(boolean clearOldSpan) { 49 | this.clearOldSpan = clearOldSpan; 50 | return this; 51 | } 52 | 53 | //override ScopeSchemeContract 54 | 55 | @Nullable 56 | @Override 57 | public List getScopeSchemes() { 58 | return scopeSchemes; 59 | } 60 | 61 | @Override 62 | public void setScopeSchemes(@Nullable List schemes) { 63 | this.scopeSchemes = schemes; 64 | } 65 | 66 | @Override 67 | public BaseScheme addScopeScheme(@NonNull Scheme... schemes) { 68 | if (scopeSchemes == null) { 69 | scopeSchemes = new ArrayList<>(); 70 | } 71 | 72 | scopeSchemes.addAll(Arrays.asList(schemes)); 73 | return this; 74 | } 75 | 76 | @Override 77 | public BaseScheme clearScopeSchemes() { 78 | if (scopeSchemes != null) { 79 | scopeSchemes.clear(); 80 | } 81 | return this; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/counter/CounterPageV0.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts.counter 2 | 3 | 4 | import android.annotation.SuppressLint 5 | import androidx.compose.foundation.layout.Arrangement 6 | import androidx.compose.foundation.layout.Column 7 | import androidx.compose.foundation.layout.fillMaxHeight 8 | import androidx.compose.foundation.layout.fillMaxWidth 9 | import androidx.compose.material.* 10 | import androidx.compose.material.icons.Icons 11 | import androidx.compose.material.icons.rounded.Add 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.runtime.MutableState 14 | import androidx.compose.runtime.mutableStateOf 15 | import androidx.compose.runtime.remember 16 | import androidx.compose.ui.Alignment 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.graphics.Color 19 | import androidx.compose.ui.text.TextStyle 20 | import androidx.compose.ui.unit.sp 21 | 22 | // V0 计数器 23 | 24 | @SuppressLint("UnusedMaterialScaffoldPaddingParameter") 25 | @Composable 26 | fun CounterPageV0(title: String) { 27 | val count: MutableState = remember { mutableStateOf(0) } 28 | Scaffold( 29 | topBar = { 30 | TopAppBar( 31 | title = { Text(title) }, 32 | ) 33 | }, 34 | floatingActionButton = { 35 | FloatingActionButton( 36 | backgroundColor = MaterialTheme.colors.primary, 37 | content = { 38 | Icon(Icons.Rounded.Add, "") 39 | }, 40 | onClick = { count.value++ } 41 | ) 42 | }) 43 | { 44 | Column( 45 | modifier = Modifier 46 | .fillMaxHeight() 47 | .fillMaxWidth(), 48 | verticalArrangement = Arrangement.Center, 49 | horizontalAlignment = Alignment.CenterHorizontally 50 | ) { 51 | Text(text = "You have pushed the button this many times:") 52 | Text( 53 | text = "$count", style = TextStyle( 54 | fontSize = 36.sp, 55 | color = Color.Gray 56 | ) 57 | ) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/doing/Doing.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.doing 2 | 3 | import androidx.compose.foundation.layout.* 4 | import androidx.compose.material.Icon 5 | import androidx.compose.material.MaterialTheme 6 | import androidx.compose.material.Text 7 | import androidx.compose.material.icons.Icons 8 | import androidx.compose.material.icons.filled.Build 9 | import androidx.compose.material.icons.filled.ThumbUp 10 | import androidx.compose.material.icons.filled.Warning 11 | import androidx.compose.material.icons.outlined.Build 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.res.stringResource 17 | import androidx.compose.ui.text.TextStyle 18 | import androidx.compose.ui.text.font.FontWeight 19 | import androidx.compose.ui.text.style.TextAlign 20 | import androidx.compose.ui.tooling.preview.Preview 21 | import androidx.compose.ui.unit.dp 22 | import androidx.compose.ui.unit.sp 23 | 24 | @Composable 25 | fun Doing( 26 | modifier: Modifier = Modifier, 27 | name:String 28 | ) { 29 | Column( 30 | modifier = modifier.fillMaxSize(), 31 | verticalArrangement = Arrangement.Center, 32 | horizontalAlignment = Alignment.CenterHorizontally 33 | ) { 34 | 35 | Icon( 36 | Icons.Outlined.Build, "", 37 | tint = Color(0xffC5C5C5), 38 | modifier = Modifier.size(80.dp,80.dp)) 39 | Text( 40 | modifier = Modifier.padding(12.dp), 41 | text = name, 42 | style = TextStyle( 43 | fontWeight = FontWeight.Bold, 44 | fontSize = 20.sp, 45 | color = Color(0xff5A576C), 46 | ), 47 | textAlign = TextAlign.Center, 48 | ) 49 | Text( 50 | modifier = Modifier.padding(horizontal = 8.dp), 51 | text = "功能正在开发之中,敬请期待...", 52 | style = MaterialTheme.typography.body1, 53 | textAlign = TextAlign.Center, 54 | color = Color(0xffC5C5C5) 55 | ) 56 | } 57 | } 58 | 59 | @Preview 60 | @Composable 61 | fun ComingSoonPreview() { 62 | Doing(name="布局集录") 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Text/node5.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Text 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.material.Text 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.Alignment 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.graphics.Color 10 | import androidx.compose.ui.text.style.TextAlign 11 | import androidx.compose.ui.text.style.TextDecoration 12 | import androidx.compose.ui.tooling.preview.Preview 13 | import androidx.compose.ui.unit.dp 14 | import androidx.compose.ui.unit.sp 15 | 16 | // "widgetId": 1, 17 | // "name": "文字对齐与行高", 18 | // "subtitle": 19 | // 【textAlign】: 文字对齐 【TextAlign?】 20 | // 【lineHeight】 : 行高 【TextUnit】 21 | 22 | 23 | @Composable 24 | fun TextNode5() { 25 | val data = arrayOf( 26 | TextAlign.Start, 27 | TextAlign.Center, 28 | TextAlign.End, 29 | TextAlign.Justify, 30 | TextAlign.Right, 31 | TextAlign.Left, 32 | ) 33 | 34 | Column { 35 | for (index in data.indices step 2) { 36 | Row( 37 | Modifier.fillMaxWidth(), 38 | horizontalArrangement = Arrangement.SpaceEvenly, 39 | verticalAlignment = Alignment.CenterVertically 40 | ) { 41 | TextAlignItem(data[index]) 42 | TextAlignItem(data[index + 1]) 43 | } 44 | } 45 | } 46 | } 47 | 48 | @Composable 49 | fun TextAlignItem(align: TextAlign) { 50 | Column(horizontalAlignment = Alignment.CenterHorizontally) { 51 | Box( 52 | modifier = Modifier.width(150.dp).height(90.dp) 53 | .padding(bottom = 3.dp).background(Color(0xffEFEFEF)) 54 | ) { 55 | Text( 56 | text = "ComposeUnit is an application for learn Compose.", 57 | textAlign = align, 58 | lineHeight = 20.sp 59 | ) 60 | } 61 | Text(text = "TextAlign.$align", color = Color.Gray, fontSize = 12.sp) 62 | Spacer(modifier = Modifier.height(5.dp)) 63 | } 64 | } 65 | 66 | @Preview 67 | @Composable 68 | fun TextNode5Preview() { 69 | TextNode5() 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/counter/CounterPageV1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts.counter 2 | 3 | 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.fillMaxHeight 7 | import androidx.compose.foundation.layout.fillMaxWidth 8 | import androidx.compose.material.* 9 | import androidx.compose.material.icons.Icons 10 | import androidx.compose.material.icons.rounded.Add 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.runtime.MutableState 13 | import androidx.compose.runtime.mutableStateOf 14 | import androidx.compose.runtime.remember 15 | import androidx.compose.ui.Alignment 16 | import androidx.compose.ui.Modifier 17 | import androidx.compose.ui.graphics.Color 18 | import androidx.compose.ui.text.TextStyle 19 | import androidx.compose.ui.unit.sp 20 | 21 | // 计数器: V1 版 22 | // 拆分组件,明确结构 23 | 24 | @Composable 25 | fun CounterPageV1(title: String) { 26 | val count: MutableState = remember { mutableStateOf(0) } 27 | Scaffold( 28 | topBar = { HomeTopBar(title) }, 29 | floatingActionButton = { 30 | HomeFab(onClick = { count.value++ }) 31 | }) 32 | { HomeContent(count.value) } 33 | } 34 | 35 | // 对于比较简单的构建逻辑 36 | // 单独抽离组件就会显得多此一举 37 | @Composable 38 | fun HomeTopBar(title: String) { 39 | TopAppBar( 40 | title = { Text(title) }, 41 | ) 42 | } 43 | 44 | @Composable 45 | fun HomeFab(onClick: () -> Unit) { 46 | FloatingActionButton( 47 | backgroundColor = MaterialTheme.colors.primary, 48 | content = { 49 | Icon(Icons.Rounded.Add, "") 50 | }, 51 | onClick = onClick 52 | ) 53 | } 54 | 55 | @Composable 56 | fun HomeContent(count: Int) { 57 | Column( 58 | modifier = Modifier 59 | .fillMaxHeight() 60 | .fillMaxWidth(), 61 | verticalArrangement = Arrangement.Center, 62 | horizontalAlignment = Alignment.CenterHorizontally 63 | ) { 64 | Text(text = "You have pushed the button this many times:") 65 | Text( 66 | text = "$count", style = TextStyle( 67 | fontSize = 36.sp, 68 | color = Color.Gray 69 | ) 70 | ) 71 | } 72 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Icon/node1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Icon 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.material.Icon 6 | import androidx.compose.material.MaterialTheme 7 | import androidx.compose.material.Text 8 | import androidx.compose.material.icons.Icons 9 | import androidx.compose.material.icons.filled.Lock 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.graphics.Color 13 | import androidx.compose.ui.graphics.ImageBitmap 14 | import androidx.compose.ui.res.imageResource 15 | import androidx.compose.ui.res.painterResource 16 | import androidx.compose.ui.text.TextStyle 17 | import androidx.compose.ui.text.font.FontStyle 18 | import androidx.compose.ui.text.font.FontWeight 19 | import androidx.compose.ui.tooling.preview.Preview 20 | import androidx.compose.ui.unit.dp 21 | import androidx.compose.ui.unit.sp 22 | import com.toly1994.composeunit.R 23 | 24 | // "widgetId": 3, 25 | // "name": "图标的使用", 26 | // "subtitle": 27 | // 【painter】 : 画板加载 【Painter】 28 | // 【imageVector】: 矢量图片 【ImageVector】 29 | // 【bitmap】: 位图加载 【ImageBitmap】 30 | // 【tint】: 颜色 【Color】 31 | // 【contentDescription】: 无障碍描述 【String?】 32 | 33 | @Composable 34 | fun IconNode1() { 35 | Row(Modifier.fillMaxWidth(), 36 | horizontalArrangement = Arrangement.SpaceEvenly 37 | ) { 38 | Icon( 39 | painter = painterResource(id = R.mipmap.icon_code), 40 | contentDescription = null, 41 | tint = MaterialTheme.colors.primary, 42 | modifier = Modifier.size(40.dp, 40.dp), 43 | ) 44 | Icon( 45 | imageVector = Icons.Default.Lock, 46 | modifier = Modifier.width(50.dp).height(50.dp), 47 | tint = Color.Blue, 48 | contentDescription = null, 49 | ) 50 | val imageBitmap = ImageBitmap.imageResource(R.mipmap.icon_kafi) 51 | Icon( 52 | bitmap = imageBitmap, 53 | tint = Color.Magenta, 54 | modifier = Modifier.width(60.dp).height(60.dp), 55 | contentDescription = null, 56 | ) 57 | } 58 | } 59 | 60 | 61 | @Preview 62 | @Composable 63 | fun TextNode1Preview() { 64 | IconNode1() 65 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/home/LayoutHomePage.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.home 2 | 3 | 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.material.Scaffold 6 | import androidx.compose.material.Text 7 | import androidx.compose.material.TopAppBar 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 com.toly1994.composeunit.layouts.UnitWidgetItemV1 14 | import com.toly1994.composeunit.models.WidgetModel 15 | 16 | @Composable 17 | fun LayoutHomePage(title: String) { 18 | val text = WidgetModel( 19 | id = 2, 20 | name = "Text", 21 | nameCN = "文字组件", 22 | lever = 5, 23 | family = "无内容组件", 24 | collectd = true, 25 | info = "用于显示文字的组件。拥有的属性非常多,足够满足你的使用需求,核心样式由style属性控制。" 26 | ) 27 | 28 | val column = WidgetModel( 29 | id = 2, 30 | name = "Column", 31 | nameCN = "列布局组件", 32 | lever = 4, 33 | family = "多内容组件", 34 | collectd = false, 35 | info = "排布方向为竖向的布局,可容纳多个组件,可以通过属性控制排布的对齐方式。" 36 | ) 37 | 38 | val row = WidgetModel( 39 | id = 2, 40 | name = "Row", 41 | nameCN = "行布局组件", 42 | lever = 4, 43 | family = "多内容组件", 44 | collectd = true, 45 | info = "水平方向为竖向的布局,可容纳多个组件,可以通过属性控制排布的对齐方式。" 46 | ) 47 | 48 | Scaffold( 49 | backgroundColor = Color(0xffF3F5F4), 50 | topBar = { 51 | TopAppBar( 52 | title = { Text(title) }, 53 | ) 54 | }) { 55 | Column( 56 | Modifier 57 | .padding(it) 58 | .fillMaxWidth() 59 | .fillMaxHeight(), 60 | verticalArrangement = Arrangement.Center, 61 | horizontalAlignment = Alignment.CenterHorizontally 62 | ) { 63 | UnitWidgetItemV1(model = text) 64 | Spacer(Modifier.height(10.dp)) 65 | UnitWidgetItemV1(model =column) 66 | Spacer(Modifier.height(10.dp)) 67 | UnitWidgetItemV1(model =row) 68 | // WeChatItem(banned = true) 69 | // JuejinArticleItemV0() 70 | 71 | // Text(text = "content") 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Column/node2.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Column 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.layout.* 6 | import androidx.compose.material.Text 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.Alignment 9 | import androidx.compose.ui.Modifier 10 | import androidx.compose.ui.graphics.Color 11 | import androidx.compose.ui.tooling.preview.Preview 12 | import androidx.compose.ui.unit.dp 13 | import androidx.compose.ui.unit.sp 14 | 15 | // "widgetId": 5, 16 | // "name": "列的水平对齐模式", 17 | // "subtitle": 18 | // 【horizontalAlignment】 : 水平对齐 【Alignment.Horizontal】 19 | @SuppressLint("SuspiciousIndentation") 20 | @Composable 21 | fun ColumnNode2() { 22 | val data = mapOf( 23 | Alignment.Start to "Start", 24 | Alignment.CenterHorizontally to "CenterHorizontally", 25 | Alignment.End to "End", 26 | ) 27 | val keys = data.keys.toList() 28 | val values = data.values.toList() 29 | Column { 30 | for (index in data.keys.indices step 3) { 31 | Row( 32 | Modifier.fillMaxWidth(), 33 | horizontalArrangement = Arrangement.SpaceEvenly, 34 | verticalAlignment = Alignment.CenterVertically 35 | ) { 36 | ColumnHAItem(keys[index], values[index]) 37 | if (index+ 1 < data.size) 38 | ColumnHAItem(keys[index + 1], values[index + 1]) 39 | if (index+ 2 < data.size) 40 | ColumnHAItem(keys[index + 2], values[index + 2]) 41 | } 42 | } 43 | } 44 | } 45 | 46 | @Composable 47 | fun ColumnHAItem(arrangement: Alignment.Horizontal, info: String) { 48 | val colors = arrayOf(Color.Red, Color.Blue, Color.Green) 49 | Column(horizontalAlignment = Alignment.CenterHorizontally) { 50 | Column( 51 | Modifier.width(80.dp).height(120.dp).background(Color(0xffEFEFEF)), 52 | horizontalAlignment = arrangement, 53 | ) { 54 | colors.forEach { 55 | Spacer(modifier = Modifier.width(30.dp).height(30.dp).background(it)) 56 | } 57 | } 58 | Text(text = info, color = Color.Gray, fontSize = 12.sp) 59 | Spacer(modifier = Modifier.height(5.dp)) 60 | } 61 | } 62 | 63 | @Preview 64 | @Composable 65 | fun ColumnNode2Preview() { 66 | ColumnNode2() 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/LazyColumn/node1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.LazyColumn 2 | 3 | import android.util.Log 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.clickable 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.foundation.lazy.LazyColumn 8 | import androidx.compose.foundation.lazy.itemsIndexed 9 | import androidx.compose.material.Divider 10 | import androidx.compose.material.Text 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.ui.Alignment 13 | import androidx.compose.ui.Modifier 14 | import androidx.compose.ui.graphics.Color 15 | import androidx.compose.ui.text.font.FontWeight 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import androidx.compose.ui.unit.dp 18 | import androidx.compose.ui.unit.sp 19 | import com.toly1994.composeunit.layouts.UnitWidgetItemV1 20 | import okhttp3.internal.toHexString 21 | 22 | // "widgetId": 7, 23 | // "name": "延迟纵向列表基本使用", 24 | // "subtitle": 25 | // 【content】 : 内容 【LazyListScope.() -> Unit】 26 | // 【reverseLayout】: 是否反序 【Boolean】 27 | // 【contentPadding】: 门边距 【PaddingValues】 28 | // 【userScrollEnabled】: 是否允许滑动 【Boolean】 29 | // 【horizontalAlignment】: 水平对齐方式 【Alignment.Horizontal】 30 | // 【verticalArrangement】: 竖直对齐方式 【Arrangement.Vertical】 31 | 32 | @Composable 33 | fun LazyColumnNode1() { 34 | val count = 20 35 | val step = 256 / count 36 | val colors = mutableListOf() 37 | for (index in 0..count) { 38 | colors.add(0xffff00ff - index * step) 39 | } 40 | LazyColumn( 41 | modifier = Modifier.padding(horizontal = 20.dp).height(230.dp), 42 | userScrollEnabled = true, 43 | reverseLayout = false 44 | ) { 45 | itemsIndexed(colors) { _, value -> 46 | Box(modifier = Modifier 47 | .background(Color(value)) 48 | .fillMaxWidth(), 49 | contentAlignment = Alignment.Center 50 | ){ 51 | Text( 52 | modifier = Modifier.padding(vertical = 15.dp), 53 | text = "0x${value.toHexString()}", 54 | color = Color.White, 55 | fontSize = 18.sp, 56 | fontWeight = FontWeight.Bold 57 | ) 58 | } 59 | } 60 | } 61 | } 62 | 63 | @Preview 64 | @Composable 65 | fun LazyColumnNode1Preview() { 66 | LazyColumnNode1() 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/LazyRow/node1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.LazyRow 2 | 3 | import android.util.Log 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.clickable 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.foundation.lazy.LazyColumn 8 | import androidx.compose.foundation.lazy.LazyRow 9 | import androidx.compose.foundation.lazy.itemsIndexed 10 | import androidx.compose.material.Divider 11 | import androidx.compose.material.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.font.FontWeight 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | import androidx.compose.ui.unit.sp 20 | import com.toly1994.composeunit.layouts.UnitWidgetItemV1 21 | import okhttp3.internal.toHexString 22 | 23 | // "widgetId": 8, 24 | // "name": "延迟横向列表基本使用", 25 | // "subtitle": 26 | // 【content】 : 内容 【LazyListScope.() -> Unit】 27 | // 【reverseLayout】: 是否反序 【Boolean】 28 | // 【contentPadding】: 门边距 【PaddingValues】 29 | // 【userScrollEnabled】: 是否允许滑动 【Boolean】 30 | // 【horizontalAlignment】: 水平对齐方式 【Alignment.Horizontal】 31 | // 【verticalArrangement】: 竖直对齐方式 【Arrangement.Vertical】 32 | 33 | @Composable 34 | fun LazyRowNode1() { 35 | val count = 32 36 | val step = 256 / count 37 | val colors = mutableListOf() 38 | for (index in 0..count) { 39 | colors.add(0xffff00ff - index * step) 40 | } 41 | LazyRow( 42 | modifier = Modifier.padding(horizontal = 20.dp).height(60.dp), 43 | userScrollEnabled = true, 44 | reverseLayout = false 45 | ) { 46 | itemsIndexed(colors) { index, value -> 47 | Box(modifier = Modifier 48 | .background(Color(value)) 49 | .fillMaxHeight(), 50 | contentAlignment = Alignment.Center 51 | ){ 52 | Text( 53 | modifier = Modifier.padding(horizontal = 15.dp), 54 | text = index.toString(), 55 | color = Color.White, 56 | fontSize = 18.sp, 57 | fontWeight = FontWeight.Bold 58 | ) 59 | } 60 | } 61 | } 62 | } 63 | 64 | @Preview 65 | @Composable 66 | fun LazyRowNode1Node1Preview() { 67 | LazyRowNode1() 68 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Image/node1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Image 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.material.Text 6 | import androidx.compose.material.icons.Icons 7 | import androidx.compose.material.icons.filled.Lock 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.ui.Modifier 10 | import androidx.compose.ui.graphics.Color 11 | import androidx.compose.ui.graphics.ImageBitmap 12 | import androidx.compose.ui.graphics.vector.ImageVector 13 | import androidx.compose.ui.layout.ContentScale 14 | import androidx.compose.ui.res.imageResource 15 | import androidx.compose.ui.res.painterResource 16 | import androidx.compose.ui.res.vectorResource 17 | import androidx.compose.ui.text.TextStyle 18 | import androidx.compose.ui.text.font.FontStyle 19 | import androidx.compose.ui.text.font.FontWeight 20 | import androidx.compose.ui.tooling.preview.Preview 21 | import androidx.compose.ui.unit.dp 22 | import androidx.compose.ui.unit.sp 23 | import com.toly1994.composeunit.R 24 | 25 | // "widgetId": 2, 26 | // "name": "图片加载方式", 27 | // "subtitle": 28 | // 【painter】 : 画板加载 【Painter】 29 | // 【imageVector】: 矢量图片 【ImageVector】 30 | // 【bitmap】: 位图加载 【ImageBitmap】 31 | // 【alpha】: 透明度 【Float】 32 | // 【contentDescription】: 无障碍描述 【String?】 33 | 34 | @Composable 35 | fun ImageNode1() { 36 | Row(Modifier.fillMaxWidth(), 37 | horizontalArrangement = Arrangement.SpaceEvenly 38 | ) { 39 | Image( 40 | painter = painterResource(id = R.mipmap.logo), 41 | modifier = Modifier.width(60.dp).height(60.dp), 42 | contentDescription = null, 43 | ) 44 | Image( 45 | imageVector = Icons.Default.Lock, 46 | modifier = Modifier.width(60.dp).height(60.dp), 47 | contentDescription = null, 48 | ) 49 | val imageBitmap = ImageBitmap.imageResource(R.mipmap.icon_head) 50 | Image( 51 | bitmap = imageBitmap, 52 | modifier = Modifier.width(60.dp).height(60.dp), 53 | contentDescription = null, 54 | ) 55 | Image( 56 | painter = painterResource(id = R.mipmap.logo), 57 | modifier = Modifier.width(60.dp).height(60.dp), 58 | alpha = 0.5f, 59 | contentDescription = null, 60 | ) 61 | } 62 | } 63 | 64 | @Preview 65 | @Composable 66 | fun ImageNode1Preview() { 67 | ImageNode1() 68 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/github_search/views/GithubSearchPage.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts.github_search.views 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.lazy.LazyColumn 6 | import androidx.compose.foundation.lazy.itemsIndexed 7 | import androidx.compose.material.* 8 | import androidx.compose.runtime.* 9 | import androidx.compose.ui.Alignment 10 | import androidx.compose.ui.Modifier 11 | import androidx.compose.ui.text.font.FontWeight 12 | import androidx.compose.ui.unit.dp 13 | import androidx.compose.ui.unit.sp 14 | import androidx.lifecycle.viewmodel.compose.viewModel 15 | import com.toly1994.composeunit.layouts.github_search.repository.models.GithubRepo 16 | import com.toly1994.composeunit.layouts.github_search.view_model.GithubRepoUIState 17 | import com.toly1994.composeunit.layouts.github_search.view_model.GithubSearchViewModel 18 | 19 | @SuppressLint("UnusedMaterialScaffoldPaddingParameter") 20 | @Composable 21 | fun GithubSearchPage( 22 | viewModel: GithubSearchViewModel = viewModel() 23 | ) { 24 | val state = viewModel.uiState.collectAsState().value 25 | Scaffold( 26 | topBar = { 27 | GithubSearchBar() { 28 | viewModel.searchRepositoryByUserName(it) 29 | } 30 | } 31 | ) { 32 | if(state is GithubRepoUIState.Loading){ 33 | SimpleInfo(text = "Loading...") 34 | } 35 | if(state is GithubRepoUIState.Error){ 36 | SimpleInfo(text = "Error") 37 | } 38 | if(state is GithubRepoUIState.Init){ 39 | SimpleInfo(text = "请输入查询参数") 40 | } 41 | if(state is GithubRepoUIState.Fill){ 42 | HomeLazyGithubRepoList( 43 | state.repos 44 | ) 45 | } 46 | } 47 | } 48 | 49 | @Composable 50 | fun SimpleInfo(text:String){ 51 | Box( 52 | modifier = Modifier.fillMaxWidth().fillMaxHeight(), 53 | contentAlignment = Alignment.Center 54 | ) { 55 | Text(text = text, fontSize = 18.sp, fontWeight = FontWeight.Bold) 56 | } 57 | } 58 | 59 | @Composable 60 | fun HomeLazyGithubRepoList( 61 | data: List 62 | ) { 63 | LazyColumn( 64 | verticalArrangement = Arrangement.spacedBy(10.dp), 65 | contentPadding = PaddingValues(top = 10.dp, bottom = 10.dp) 66 | ) { 67 | itemsIndexed(data) { _, item -> 68 | GithubRepoItem(item) 69 | } 70 | } 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/app/navigation/RouterRes.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.app.navigation 2 | 3 | import androidx.compose.material.icons.Icons 4 | import androidx.compose.material.icons.filled.AccountBox 5 | import androidx.compose.material.icons.filled.Favorite 6 | import androidx.compose.material.icons.filled.Home 7 | import androidx.compose.material.icons.filled.Send 8 | import androidx.compose.ui.graphics.vector.ImageVector 9 | import com.toly1994.composeunit.R 10 | 11 | object UnitRoute { 12 | const val homeNav = "HomeNav" 13 | const val splash = "Splash" 14 | const val widgetDetail = "WidgetDetail" 15 | const val widget = "HomeNav/Widget" 16 | const val layout = "HomeNav/Layout" 17 | const val collect = "HomeNav/Collect" 18 | const val user = "HomeNav/User" 19 | } 20 | 21 | object RouterRes { 22 | val bottomNavData = listOf( 23 | BottomNavData( 24 | route = UnitRoute.widget, 25 | icon = Icons.Default.Home, 26 | text = "组件", 27 | ), 28 | BottomNavData( 29 | route = UnitRoute.layout, 30 | icon = Icons.Default.Send, 31 | text = "布局", 32 | ), 33 | BottomNavData( 34 | route = UnitRoute.collect, 35 | icon = Icons.Default.Favorite, 36 | text = "收藏", 37 | ), 38 | BottomNavData( 39 | route = UnitRoute.user, 40 | icon = Icons.Default.AccountBox, 41 | text = "我的", 42 | ), 43 | ) 44 | 45 | val userMenuData = listOf( 46 | MenuItemData( 47 | resImg = R.mipmap.icon_app_setting, 48 | text = "设置中心" 49 | ), 50 | MenuItemData( 51 | resImg = R.mipmap.icon_data, 52 | text = "数据管理" 53 | ), 54 | MenuItemData( 55 | resImg = R.mipmap.icon_colloct, 56 | text = "我的收藏" 57 | ), 58 | MenuItemData(), 59 | MenuItemData( 60 | resImg = R.mipmap.icon_version, 61 | text = "版本信息" 62 | ), 63 | MenuItemData( 64 | resImg = R.mipmap.icon_about, 65 | text = "关于应用" 66 | ), 67 | MenuItemData(), 68 | MenuItemData( 69 | resImg = R.mipmap.icon_kafi, 70 | text = "联系本王" 71 | ) 72 | ) 73 | } 74 | 75 | data class BottomNavData( 76 | val route: String, 77 | val icon: ImageVector, 78 | val text: String 79 | ) 80 | 81 | data class MenuItemData( 82 | val route: String? = null, 83 | val resImg: Int?=null, 84 | val text: String = "" 85 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/LazyVerticalGrid/node1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.LazyVerticalGrid 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.lazy.grid.GridCells 6 | import androidx.compose.foundation.lazy.grid.LazyVerticalGrid 7 | 8 | 9 | import androidx.compose.material.Text 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.text.font.FontWeight 15 | import androidx.compose.ui.tooling.preview.Preview 16 | import androidx.compose.ui.unit.dp 17 | import androidx.compose.ui.unit.sp 18 | import okhttp3.internal.toHexString 19 | 20 | // "widgetId": 7, 21 | // "name": "延迟纵向网格基本使用", 22 | // "subtitle": 23 | // 【content】 : 内容 【LazyListScope.() -> Unit】 24 | // 【reverseLayout】: 是否反序 【Boolean】 25 | // 【columns】: 单元格配置 【GridCells】 26 | // 【contentPadding】: 门边距 【PaddingValues】 27 | // 【userScrollEnabled】: 是否允许滑动 【Boolean】 28 | // 【horizontalArrangement】: 水平间距 【Arrangement.Horizontal】 29 | // 【verticalArrangement】: 竖直间距 【Arrangement.Vertical】 30 | 31 | @Composable 32 | fun LazyVerticalGridNode1() { 33 | val count = 64 34 | val step = 256 / count 35 | val colors = mutableListOf() 36 | for (index in 0..count) { 37 | colors.add(0xffff00ff - index * step) 38 | } 39 | LazyVerticalGrid( 40 | modifier = Modifier 41 | .padding(horizontal = 20.dp) 42 | .height(230.dp), 43 | userScrollEnabled = true, 44 | reverseLayout = false, 45 | columns = GridCells.Fixed(3), 46 | verticalArrangement = Arrangement.spacedBy(4.dp), 47 | horizontalArrangement = Arrangement.spacedBy(4.dp), 48 | ) { 49 | items(colors.size,) { 50 | index -> 51 | Box( 52 | modifier = Modifier 53 | .background(Color(colors[index])) 54 | .fillMaxWidth(), 55 | contentAlignment = Alignment.Center 56 | ) { 57 | Text( 58 | modifier = Modifier.padding(vertical = 15.dp), 59 | text = "0x${colors[index].toHexString()}", 60 | color = Color.White, 61 | fontSize = 16.sp, 62 | fontWeight = FontWeight.Bold 63 | ) 64 | } 65 | } 66 | } 67 | } 68 | 69 | @Preview 70 | @Composable 71 | fun LazyVerticalGridPreview() { 72 | LazyVerticalGridNode1() 73 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/app/data_manager/DataManagePage.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.app.data_manager 2 | 3 | import androidx.compose.foundation.layout.* 4 | import androidx.compose.material.* 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.runtime.rememberCoroutineScope 7 | import androidx.compose.ui.Alignment 8 | import androidx.compose.ui.Modifier 9 | import com.toly1994.composeunit.layouts.counter.CountViewModel 10 | import com.toly1994.composeunit.repository.database.LocalDb 11 | import com.toly1994.composeunit.repository.database.entity.WidgetPo 12 | import com.toly1994.composeunit.repository.memory.MemoryNodeDataStore 13 | import com.toly1994.composeunit.repository.memory.MemoryWidgetDataStore 14 | import kotlinx.coroutines.launch 15 | 16 | @Composable 17 | fun DataManagePage( 18 | ) { 19 | // val db = Room.databaseBuilder(this,ComposeUnitDB::class.java,"compose_unit").allowMainThreadQueries().build() 20 | // db.widgetDao().insertAll(MemoryWidgetDataStore.allWidget.first().toPo()) 21 | 22 | val scaffoldState = rememberScaffoldState() 23 | val scope = rememberCoroutineScope() 24 | 25 | Scaffold( 26 | scaffoldState = scaffoldState, 27 | topBar = { TopAppBar(title = { Text("数据库测试") }) } 28 | ) { 29 | Column(Modifier.padding(it).fillMaxWidth().fillMaxHeight(), 30 | horizontalAlignment = Alignment.CenterHorizontally, 31 | verticalArrangement = Arrangement.Center 32 | ) { 33 | Button(onClick = { 34 | addWidget() 35 | scope.launch { 36 | scaffoldState.snackbarHostState.showSnackbar("插入成功!") 37 | } 38 | // scaffoldState.s 39 | }) { 40 | Text(text = "添加组件数据") 41 | } 42 | Button(onClick = { addNode() 43 | scope.launch { 44 | scaffoldState.snackbarHostState.showSnackbar("插入成功!") 45 | } 46 | }) { 47 | Text(text = "添加节点数据") 48 | } 49 | } 50 | } 51 | } 52 | 53 | private fun addWidget(){ 54 | val dao = LocalDb.database.widgetDao(); 55 | MemoryWidgetDataStore.allWidget.forEach(){ 56 | dao.insertAll(it.toPo()) 57 | } 58 | } 59 | 60 | //private fun findWidget(): List{ 61 | //// val dao = LocalDb.database.widgetDao(); 62 | //// return dao.queryAll() 63 | //} 64 | 65 | private fun addNode(){ 66 | val dao = LocalDb.database.nodeDao(); 67 | MemoryNodeDataStore.allNodes.forEach(){ 68 | dao.insertAll(it) 69 | } 70 | 71 | // val dao = LocalDb.database.widgetDao(); 72 | // dao.deleteAll() 73 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Row/node2.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Row 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.material.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.layout.ContentScale 13 | import androidx.compose.ui.res.painterResource 14 | import androidx.compose.ui.text.TextStyle 15 | import androidx.compose.ui.text.font.FontStyle 16 | import androidx.compose.ui.text.font.FontWeight 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | import androidx.compose.ui.unit.sp 20 | import com.toly1994.composeunit.R 21 | import com.toly1994.composeunit.widgets.Image.ImageContentScaleItem 22 | 23 | // "widgetId": 4, 24 | // "name": "行的竖直对齐模式", 25 | // "subtitle": 26 | // 【verticalAlignment】 : 竖直对齐 【Arrangement.Vertical】 27 | @SuppressLint("SuspiciousIndentation") 28 | @Composable 29 | fun RowNode2() { 30 | val data = mapOf( 31 | Alignment.Top to "Top", 32 | Alignment.CenterVertically to "Center", 33 | Alignment.Bottom to "Bottom", 34 | ) 35 | val keys = data.keys.toList() 36 | val values = data.values.toList() 37 | Column { 38 | for (index in data.keys.indices step 2) { 39 | Row( 40 | Modifier.fillMaxWidth(), 41 | horizontalArrangement = Arrangement.SpaceEvenly, 42 | verticalAlignment = Alignment.CenterVertically 43 | ) { 44 | RowVAItem(keys[index],values[index]) 45 | if(index Unit】 25 | // 【reverseLayout】: 是否反序 【Boolean】 26 | // 【rows】: 单元格配置 【GridCells】 27 | // 【contentPadding】: 门边距 【PaddingValues】 28 | // 【userScrollEnabled】: 是否允许滑动 【Boolean】 29 | // 【horizontalArrangement】: 水平间距 【Arrangement.Horizontal】 30 | // 【verticalArrangement】: 竖直间距 【Arrangement.Vertical】 31 | 32 | @Composable 33 | fun LazyHorizontalGridNode1() { 34 | val count = 64 35 | val step = 256 / count 36 | val colors = mutableListOf() 37 | for (index in 0..count) { 38 | colors.add(0xffff00ff - index * step) 39 | } 40 | LazyHorizontalGrid( 41 | modifier = Modifier 42 | .padding(horizontal = 20.dp) 43 | .height(230.dp), 44 | userScrollEnabled = true, 45 | reverseLayout = false, 46 | rows = GridCells.Fixed(3), 47 | verticalArrangement = Arrangement.spacedBy(4.dp), 48 | horizontalArrangement = Arrangement.spacedBy(4.dp), 49 | ) { 50 | items(colors.size) { 51 | index -> 52 | Box( 53 | modifier = Modifier 54 | .background(Color(colors[index])) 55 | .fillMaxWidth(), 56 | contentAlignment = Alignment.Center 57 | ) { 58 | Text( 59 | modifier = Modifier.padding(horizontal = 15.dp), 60 | text = "0x${colors[index].toHexString()}", 61 | color = Color.White, 62 | fontSize = 16.sp, 63 | fontWeight = FontWeight.Bold 64 | ) 65 | } 66 | } 67 | } 68 | } 69 | 70 | @Preview 71 | @Composable 72 | fun LazyHorizontalGridPreview() { 73 | LazyHorizontalGridNode1() 74 | } -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/scheme/FontScheme.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.scheme; 2 | 3 | import android.content.Context; 4 | import android.graphics.Paint; 5 | import android.graphics.Typeface; 6 | import android.text.TextPaint; 7 | import android.text.style.TypefaceSpan; 8 | 9 | import androidx.annotation.FontRes; 10 | import androidx.annotation.NonNull; 11 | import androidx.annotation.Nullable; 12 | import androidx.core.content.res.ResourcesCompat; 13 | 14 | import com.neo.highlight.util.scheme.base.BaseScheme; 15 | 16 | import java.util.Objects; 17 | import java.util.regex.Pattern; 18 | 19 | final public class FontScheme extends BaseScheme { 20 | 21 | @NonNull 22 | private final Typeface typeface; 23 | 24 | private boolean keepStyle = true; 25 | 26 | public FontScheme(@Nullable Pattern pattern, @NonNull Typeface typeface) { 27 | super(pattern); 28 | this.typeface = typeface; 29 | } 30 | 31 | public FontScheme(@NonNull Typeface typeface) { 32 | super(null); 33 | this.typeface = typeface; 34 | } 35 | 36 | @NonNull 37 | @Override 38 | public Object getSpan(@NonNull CharSequence text, int start, int end) { 39 | return new TypefaceSpan("") { 40 | 41 | @Override 42 | public void updateDrawState(TextPaint paint) { 43 | 44 | if (keepStyle) { 45 | applyTypeFace(paint); 46 | } else { 47 | paint.setTypeface(typeface); 48 | } 49 | } 50 | 51 | private void applyTypeFace(Paint paint) { 52 | Typeface typefaceAnterior = paint.getTypeface(); 53 | 54 | int styleAnterior; 55 | 56 | if (typefaceAnterior == null) { 57 | styleAnterior = 0; 58 | } else { 59 | styleAnterior = typefaceAnterior.getStyle(); 60 | } 61 | 62 | int fake = styleAnterior & typeface.getStyle(); 63 | 64 | if ((fake & Typeface.BOLD) != 0) { 65 | paint.setFakeBoldText(true); 66 | } 67 | 68 | if ((fake & Typeface.ITALIC) != 0) { 69 | paint.setTextSkewX(-0.25f); 70 | } 71 | 72 | paint.setTypeface(typeface); 73 | } 74 | }; 75 | } 76 | 77 | public FontScheme setKeepStyle(boolean keepStyle) { 78 | this.keepStyle = keepStyle; 79 | return this; 80 | } 81 | 82 | @NonNull 83 | public static Typeface getFont(@NonNull Context context, @FontRes int fonResId) { 84 | return Objects.requireNonNull(ResourcesCompat.getFont(context, fonResId)); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/components/CodeHighlighter.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.app.utils 2 | 3 | import android.content.Context 4 | import android.widget.TextView 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.viewinterop.AndroidView 7 | import androidx.core.content.ContextCompat 8 | import com.neo.highlight.core.Highlight 9 | import com.neo.highlight.core.Scheme 10 | import com.neo.highlight.util.scheme.ColorScheme 11 | import com.neo.highlight.util.scheme.Scope 12 | import com.toly1994.composeunit.R 13 | import java.util.regex.Pattern 14 | 15 | @Composable 16 | fun CodeHighlighter(code :String ) { 17 | AndroidView(factory = { 18 | val tv = TextView(it) 19 | val highlight = Highlight() 20 | highlight.schemes = getKotlinScheme(it) 21 | tv.text = code 22 | highlight.setSpan(tv) 23 | tv 24 | }) 25 | } 26 | 27 | 28 | private fun getKotlinScheme(context: Context): List { 29 | val schemes: MutableList = ArrayList() 30 | //keywords 31 | 32 | schemes.add( 33 | ColorScheme( 34 | Pattern.compile("\\b(fun)|(val)|(var)|(sp)|(dp)|(private)\\b"), 35 | ContextCompat.getColor(context, R.color.keyword) 36 | ) 37 | ) 38 | 39 | // 数字 40 | schemes.add( 41 | Scope( 42 | Pattern.compile("\\w+") 43 | ).addScopeScheme( 44 | ColorScheme( 45 | Pattern.compile("^(\\d+\\.\\d+)|^(\\d+)"), 46 | ContextCompat.getColor(context, R.color.num) 47 | ) 48 | ) 49 | ) 50 | // class 51 | schemes.add( 52 | Scope( 53 | Pattern.compile("\\w+") 54 | ).addScopeScheme( 55 | ColorScheme( 56 | Pattern.compile("^[A-Z](.*?)\\w+"), 57 | ContextCompat.getColor(context, R.color.clazz) 58 | ) 59 | ) 60 | ) 61 | 62 | //function declaration 63 | schemes.add( 64 | Scope( 65 | Pattern.compile("\\b(fun)\\b\\s*\\b\\w+\\b\\([^()]*\\)") 66 | ).addScopeScheme( 67 | ColorScheme( 68 | Pattern.compile("\\w*(?=\\()"), 69 | ContextCompat.getColor(context, R.color.function) 70 | ) 71 | ) 72 | ) 73 | 74 | 75 | 76 | //annotations 77 | schemes.add( 78 | ColorScheme( 79 | Pattern.compile("@.+"), 80 | ContextCompat.getColor(context, R.color.annotation) 81 | ) 82 | ) 83 | 84 | //strings 85 | schemes.add( 86 | ColorScheme( 87 | Pattern.compile("\"[^\"]*\""), 88 | ContextCompat.getColor(context, R.color.string) 89 | ) 90 | ) 91 | return schemes 92 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/app/navigation/UnitAppBar.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.app.navigation 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.border 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.foundation.shape.CircleShape 8 | import androidx.compose.foundation.shape.RoundedCornerShape 9 | import androidx.compose.material.MaterialTheme 10 | import androidx.compose.material.Text 11 | import androidx.compose.material.TopAppBar 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.draw.clip 16 | import androidx.compose.ui.draw.shadow 17 | import androidx.compose.ui.graphics.Color 18 | import androidx.compose.ui.layout.ContentScale 19 | import androidx.compose.ui.res.painterResource 20 | import androidx.compose.ui.text.font.FontWeight 21 | import androidx.compose.ui.unit.dp 22 | import androidx.compose.ui.unit.sp 23 | import com.toly1994.composeunit.R 24 | 25 | @Composable 26 | fun UnitAppBar(route:String?){ 27 | when(route){ 28 | UnitRoute.user -> UserPageAppBar() 29 | else -> TopAppBar( 30 | title = { Text("ComposeUnit") }, 31 | ) 32 | } 33 | 34 | } 35 | 36 | 37 | @Composable 38 | fun UserPageAppBar(){ 39 | Box(contentAlignment = Alignment.BottomStart) { 40 | Column { 41 | Image( 42 | modifier = Modifier.fillMaxWidth().height(180.dp), 43 | contentScale = ContentScale.FillWidth, 44 | painter = painterResource(id = R.mipmap.base_draw), 45 | contentDescription = "", 46 | ) 47 | Box(modifier = Modifier 48 | .fillMaxWidth() 49 | .height(50.dp) 50 | .background(Color.White), 51 | contentAlignment = Alignment.CenterEnd 52 | 53 | ){ 54 | Text( 55 | modifier = Modifier.offset(x=(-30).dp), 56 | text = "张风捷特烈", 57 | fontSize = 18.sp, 58 | color = MaterialTheme.colors.primary, 59 | fontWeight = FontWeight.Bold) 60 | } 61 | } 62 | Image( 63 | modifier = Modifier 64 | .width(80.dp) 65 | .height(80.dp) 66 | .offset(40.dp, (-10).dp) 67 | .border(3.dp, Color.White, CircleShape) 68 | .shadow(elevation = 1.dp, shape = CircleShape), 69 | contentScale = ContentScale.FillWidth, 70 | painter = painterResource(id = R.mipmap.icon_head), 71 | contentDescription = "", 72 | ) 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Image/node3.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Image 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.material.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.layout.ContentScale 13 | import androidx.compose.ui.res.painterResource 14 | import androidx.compose.ui.tooling.preview.Preview 15 | import androidx.compose.ui.unit.dp 16 | import androidx.compose.ui.unit.sp 17 | import com.toly1994.composeunit.R 18 | 19 | // "widgetId": 2, 20 | // "name": "图片缩放模式", 21 | // "subtitle": 22 | // 【contentScale】 : 缩放模式 【ContentScale】 23 | 24 | @SuppressLint("SuspiciousIndentation") 25 | @Composable 26 | fun ImageNode3() { 27 | val data = mapOf( 28 | ContentScale.Fit to "Fit", 29 | ContentScale.Crop to "Crop", 30 | ContentScale.FillHeight to "FillHeight", 31 | ContentScale.FillWidth to "FillWidth", 32 | ContentScale.FillBounds to "FillBounds", 33 | ContentScale.None to "None", 34 | ContentScale.Inside to "Inside", 35 | ) 36 | val keys = data.keys.toList(); 37 | val values = data.values.toList(); 38 | Column { 39 | for (index in data.keys.indices step 2) { 40 | Row( 41 | Modifier.fillMaxWidth(), 42 | horizontalArrangement = Arrangement.SpaceEvenly, 43 | verticalAlignment = Alignment.CenterVertically 44 | ) { 45 | ImageContentScaleItem(keys[index],values[index]) 46 | if(index Unit】 28 | @SuppressLint("SuspiciousIndentation") 29 | @Composable 30 | fun RowNode1() { 31 | val data = mapOf( 32 | Arrangement.Center to "Center", 33 | Arrangement.SpaceBetween to "SpaceBetween", 34 | Arrangement.SpaceAround to "SpaceAround", 35 | Arrangement.SpaceEvenly to "SpaceEvenly", 36 | Arrangement.End to "End", 37 | Arrangement.Start to "Start", 38 | ) 39 | val keys = data.keys.toList(); 40 | val values = data.values.toList(); 41 | Column { 42 | for (index in data.keys.indices step 2) { 43 | Row( 44 | Modifier.fillMaxWidth(), 45 | horizontalArrangement = Arrangement.SpaceEvenly, 46 | verticalAlignment = Alignment.CenterVertically 47 | ) { 48 | RowHAItem(keys[index],values[index]) 49 | if(indexNUL 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 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Image/node2.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Image 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.material.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.layout.ContentScale 13 | import androidx.compose.ui.res.painterResource 14 | import androidx.compose.ui.tooling.preview.Preview 15 | import androidx.compose.ui.unit.dp 16 | import androidx.compose.ui.unit.sp 17 | import com.toly1994.composeunit.R 18 | 19 | // "widgetId": 2, 20 | // "name": "图片对齐模式", 21 | // "subtitle": 22 | // 【alignment】 : 对齐模式 【Alignment】 23 | 24 | @SuppressLint("SuspiciousIndentation") 25 | @Composable 26 | fun ImageNode2() { 27 | val data = mapOf( 28 | Alignment.Center to "Center", 29 | Alignment.CenterStart to "CenterStart", 30 | Alignment.CenterEnd to "CenterEnd", 31 | Alignment.TopCenter to "TopCenter", 32 | Alignment.BottomCenter to "BottomCenter", 33 | Alignment.BottomStart to "BottomStart", 34 | Alignment.BottomEnd to "BottomEnd", 35 | Alignment.TopStart to "TopStart", 36 | Alignment.TopEnd to "TopEnd", 37 | 38 | ) 39 | val keys = data.keys.toList(); 40 | val values = data.values.toList(); 41 | Column { 42 | for (index in data.keys.indices step 3) { 43 | Row( 44 | Modifier.fillMaxWidth(), 45 | horizontalArrangement = Arrangement.SpaceEvenly, 46 | verticalAlignment = Alignment.CenterVertically 47 | ) { 48 | ImageAlignmentItem(keys[index],values[index]) 49 | if(index+1 Unit】 28 | 29 | @SuppressLint("SuspiciousIndentation") 30 | @Composable 31 | fun ColumnNode1() { 32 | val data = mapOf( 33 | Arrangement.Top to "Center", 34 | Arrangement.SpaceBetween to "SpaceBetween", 35 | Arrangement.SpaceAround to "SpaceAround", 36 | Arrangement.SpaceEvenly to "SpaceEvenly", 37 | Arrangement.Bottom to "End", 38 | Arrangement.Center to "Start", 39 | ) 40 | val keys = data.keys.toList(); 41 | val values = data.values.toList(); 42 | Column { 43 | for (index in data.keys.indices step 3) { 44 | Row( 45 | Modifier.fillMaxWidth(), 46 | horizontalArrangement = Arrangement.SpaceEvenly, 47 | verticalAlignment = Alignment.CenterVertically 48 | ) { 49 | ColumnVAItem(keys[index],values[index]) 50 | if(index+1 0) { 90 | 91 | char c = editable.charAt(lineStart - 1); 92 | 93 | if (c == '\n') { 94 | break; 95 | } 96 | 97 | lineStart--; 98 | } 99 | 100 | return lineStart; 101 | } 102 | 103 | public static final String TAG = LinesTextWatcher.class.getSimpleName(); 104 | } 105 | 106 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | id 'kotlin-kapt' // 添加 kapt 5 | } 6 | 7 | android { 8 | namespace 'com.toly1994.composeunit' 9 | compileSdk 33 10 | 11 | defaultConfig { 12 | applicationId "com.toly1994.composeunit" 13 | minSdk 21 14 | targetSdk 32 15 | versionCode 1 16 | versionName "1.0" 17 | 18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | vectorDrawables { 20 | useSupportLibrary true 21 | } 22 | } 23 | 24 | buildTypes { 25 | release { 26 | minifyEnabled false 27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 28 | } 29 | } 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | kotlinOptions { 35 | jvmTarget = '1.8' 36 | } 37 | buildFeatures { 38 | compose true 39 | } 40 | composeOptions { 41 | kotlinCompilerExtensionVersion '1.1.1' 42 | } 43 | packagingOptions { 44 | resources { 45 | excludes += '/META-INF/{AL2.0,LGPL2.1}' 46 | } 47 | } 48 | } 49 | 50 | dependencies { 51 | // room 数据库 52 | def room_version = "2.4.3" 53 | implementation "androidx.room:room-runtime:$room_version" 54 | kapt "androidx.room:room-compiler:$room_version" 55 | implementation "androidx.room:room-ktx:$room_version" 56 | 57 | // retrofit 网络请求 58 | implementation "com.squareup.retrofit2:retrofit:2.9.0" 59 | implementation "com.squareup.retrofit2:converter-gson:2.9.0" 60 | 61 | // 网络图片 62 | implementation "io.coil-kt:coil-compose:2.2.2" 63 | 64 | implementation project(":highlight") 65 | implementation 'androidx.core:core-ktx:1.7.0' 66 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' 67 | implementation 'androidx.activity:activity-compose:1.6.0' 68 | implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1' 69 | 70 | 71 | implementation "androidx.compose.ui:ui:$compose_ui_version" 72 | implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version" 73 | implementation 'androidx.compose.material:material:1.3.0' 74 | implementation "androidx.navigation:navigation-compose:2.5.2" 75 | 76 | // 协程核心库 77 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4" 78 | // 协程Android支持库 79 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4" 80 | // 协程Java8支持库 81 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.4" 82 | 83 | testImplementation 'junit:junit:4.13.2' 84 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 85 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 86 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version" 87 | debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version" 88 | debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version" 89 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/widgets/Image/node4.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.widgets.Image 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.material.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.BlendMode 12 | import androidx.compose.ui.graphics.Color 13 | import androidx.compose.ui.graphics.ColorFilter 14 | import androidx.compose.ui.layout.ContentScale 15 | import androidx.compose.ui.res.painterResource 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import androidx.compose.ui.unit.dp 18 | import androidx.compose.ui.unit.sp 19 | import com.toly1994.composeunit.R 20 | 21 | // "widgetId": 2, 22 | // "name": "颜色叠合模式", 23 | // "subtitle": 24 | // 【colorFilter】 : 缩放模式 【ColorFilter】 25 | 26 | @SuppressLint("SuspiciousIndentation") 27 | @Composable 28 | fun ImageNode4() { 29 | val data = arrayOf( 30 | BlendMode.Clear,BlendMode.Src,BlendMode.Dst, 31 | BlendMode.SrcOver,BlendMode.DstOver,BlendMode.SrcIn, 32 | BlendMode.DstIn,BlendMode.SrcOut,BlendMode.DstOut, 33 | BlendMode.SrcAtop,BlendMode.DstAtop,BlendMode.Xor, 34 | BlendMode.Plus,BlendMode.Modulate,BlendMode.Screen, 35 | BlendMode.Overlay,BlendMode.Darken,BlendMode.Lighten, 36 | BlendMode.ColorDodge,BlendMode.ColorBurn,BlendMode.Hardlight, 37 | BlendMode.Softlight,BlendMode.Difference,BlendMode.Exclusion, 38 | BlendMode.Multiply,BlendMode.Hue,BlendMode.Saturation, 39 | BlendMode.Color,BlendMode.Luminosity,) 40 | Column { 41 | for (index in data.indices step 5) { 42 | Row( 43 | Modifier.fillMaxWidth(), 44 | horizontalArrangement = Arrangement.SpaceEvenly, 45 | verticalAlignment = Alignment.CenterVertically 46 | ) { 47 | ImageBlendModeItem(data[index]) 48 | if(index+1 Unit) { 58 | Box( 59 | modifier = Modifier.fillMaxWidth(), 60 | contentAlignment = Alignment.Center 61 | ) { 62 | Surface( 63 | Modifier 64 | .width(200.dp) 65 | .height((0.618 * 0.618 * 200).dp), 66 | color = Color(0xffEFEFEF) 67 | ) { content() } 68 | } 69 | } 70 | 71 | @Composable 72 | fun Center(content: @Composable () -> Unit) { 73 | Box( 74 | modifier = Modifier.fillMaxWidth().fillMaxHeight(), 75 | contentAlignment = Alignment.Center 76 | ) { 77 | content() 78 | } 79 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/unit_widget_item/UnitWidgetItemV1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.* 5 | 6 | import androidx.compose.foundation.shape.CircleShape 7 | import androidx.compose.foundation.shape.RoundedCornerShape 8 | import androidx.compose.material.MaterialTheme 9 | import androidx.compose.material.Text 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.draw.clip 14 | import androidx.compose.ui.geometry.Offset 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.graphics.Shadow 17 | import androidx.compose.ui.text.TextStyle 18 | import androidx.compose.ui.text.font.FontWeight 19 | import androidx.compose.ui.unit.dp 20 | import androidx.compose.ui.unit.sp 21 | import com.toly1994.composeunit.models.WidgetModel 22 | 23 | 24 | 25 | @Composable 26 | fun UnitWidgetItemV1( 27 | modifier: Modifier = Modifier, 28 | model: WidgetModel) { 29 | val titleTextStyle = TextStyle( 30 | fontWeight = FontWeight.Bold, 31 | fontSize = 16.sp, 32 | color = Color(0xff2F3032), 33 | ) 34 | 35 | val contentTextStyle = TextStyle( 36 | fontSize = 14.sp, 37 | color = Color(0xff2F3032), 38 | ) 39 | 40 | val infoTextStyle = TextStyle( 41 | fontSize = 12.sp, 42 | color = Color(0xff86909c), 43 | ) 44 | 45 | val starTextStyle = TextStyle( 46 | color = MaterialTheme.colors.primary, 47 | ) 48 | 49 | val typeTextStyle = TextStyle( 50 | fontSize = 10.sp, 51 | shadow = Shadow( 52 | color = Color.White, 53 | blurRadius = 2.0f, 54 | offset = Offset(1f, 1f) 55 | ) 56 | ) 57 | val collectTextStyle = TextStyle( 58 | fontSize = 10.sp, 59 | color = MaterialTheme.colors.primary, 60 | shadow = Shadow( 61 | color = Color.White, 62 | blurRadius = 2.0f, 63 | offset = Offset(1f, 1f) 64 | ) 65 | ) 66 | var starText = ""; 67 | for (i in 0 until model.lever) { 68 | starText+="★" 69 | } 70 | 71 | Column( 72 | modifier 73 | .fillMaxWidth() 74 | .background(Color.White) 75 | .padding(20.dp, 10.dp) 76 | ) { 77 | Row(verticalAlignment = Alignment.CenterVertically) { 78 | Text(text = model.name, style = titleTextStyle) 79 | Spacer(modifier = Modifier.width(6.dp)) 80 | if(model.collectd){ 81 | Wrapper(wrapperColor = Color(0xffF3F3F5)) { 82 | Text(text = "已收藏", style = collectTextStyle) 83 | } 84 | } 85 | Spacer(modifier = Modifier.weight(1f)) 86 | Text(text = starText, style = starTextStyle) 87 | } 88 | Spacer(modifier = Modifier.height(8.dp)) 89 | Text(text = model.info, style = contentTextStyle) 90 | Spacer(modifier = Modifier.height(8.dp)) 91 | Row(verticalAlignment = Alignment.CenterVertically) { 92 | Spacer( 93 | Modifier 94 | .width(4.dp) 95 | .height(4.dp) 96 | .clip(CircleShape) 97 | .background(infoTextStyle.color) 98 | ) 99 | 100 | Spacer(modifier = Modifier.width(8.dp)) 101 | Text(text = model.nameCN, style = infoTextStyle) 102 | Box( 103 | Modifier.fillMaxWidth(), 104 | contentAlignment = Alignment.CenterEnd 105 | ) { 106 | Wrapper( 107 | wrapperColor = Color(0xffF3F3F5), 108 | shape = RoundedCornerShape(10) 109 | ) { 110 | Text(text = model.family, style = typeTextStyle) 111 | } 112 | } 113 | 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/github_search/views/GithubRepoItem.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts.github_search.views 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.layout.* 6 | import androidx.compose.foundation.shape.CircleShape 7 | import androidx.compose.foundation.shape.RoundedCornerShape 8 | import androidx.compose.material.Divider 9 | import androidx.compose.material.Icon 10 | import androidx.compose.material.MaterialTheme 11 | import androidx.compose.material.Text 12 | import androidx.compose.material.icons.Icons 13 | import androidx.compose.material.icons.filled.Warning 14 | import androidx.compose.runtime.Composable 15 | import androidx.compose.ui.Alignment 16 | import androidx.compose.ui.BiasAlignment 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.draw.clip 19 | import androidx.compose.ui.geometry.Offset 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.Shadow 22 | import androidx.compose.ui.res.painterResource 23 | import androidx.compose.ui.text.TextStyle 24 | import androidx.compose.ui.text.font.FontWeight 25 | import androidx.compose.ui.tooling.preview.Preview 26 | import androidx.compose.ui.unit.dp 27 | import androidx.compose.ui.unit.sp 28 | import coil.compose.AsyncImage 29 | import com.toly1994.composeunit.R 30 | import com.toly1994.composeunit.components.style.Gap 31 | import com.toly1994.composeunit.layouts.Wrapper 32 | import com.toly1994.composeunit.layouts.github_search.repository.models.GithubRepo 33 | import com.toly1994.composeunit.layouts.wechat_item.CircleNumTip 34 | import com.toly1994.composeunit.widgets.Box.BoxNode2 35 | 36 | @Composable 37 | fun GithubRepoItem(githubRepo: GithubRepo) { 38 | val titleTextStyle = TextStyle( 39 | fontWeight = FontWeight.Bold, 40 | fontSize = 16.sp, 41 | color = Color(0xff2F3032), 42 | ) 43 | val collectTextStyle = TextStyle( 44 | fontSize = 10.sp, 45 | color = MaterialTheme.colors.primary, 46 | shadow = Shadow( 47 | color = Color.White, 48 | blurRadius = 2.0f, 49 | offset = Offset(1f, 1f) 50 | ) 51 | ) 52 | val subTextStyle = TextStyle( 53 | fontSize = 12.sp, 54 | color = Color(0xffC5C5C5), 55 | ) 56 | 57 | Column( 58 | Modifier 59 | .fillMaxWidth() 60 | .background(Color.White) 61 | ) { 62 | Box( 63 | modifier = Modifier.padding(10.dp, 10.dp) 64 | ) { 65 | Row( 66 | verticalAlignment = Alignment.Top 67 | ) { 68 | Box( 69 | contentAlignment = BiasAlignment(1.2f, -1.2f) 70 | ) { 71 | AsyncImage( 72 | modifier = Modifier 73 | .width(45.dp) 74 | .clip(RoundedCornerShape(10)), 75 | model = githubRepo.owner.avatar_url, 76 | contentDescription = null 77 | ) 78 | } 79 | 80 | Spacer(modifier = Modifier.width(10.dp)) 81 | Column( 82 | Modifier.weight(1f) 83 | ) { 84 | Text(text = githubRepo.name, style = titleTextStyle) 85 | Spacer(modifier = Modifier.height(4.dp)) 86 | Text(text = githubRepo.description, style = subTextStyle) 87 | } 88 | Row { 89 | Wrapper(wrapperColor = Color(0xffF3F3F5)) { 90 | Text(text = "star : ${githubRepo.stargazers_count}", style = collectTextStyle) 91 | } 92 | Gap(width = 6f) 93 | Wrapper(wrapperColor = Color(0xffF3F3F5)) { 94 | Text(text = "forks : ${githubRepo.forks_count}", style = collectTextStyle) 95 | } 96 | } 97 | } 98 | } 99 | Divider( 100 | startIndent = 70.dp, 101 | thickness = 0.5.dp 102 | ) 103 | } 104 | 105 | } 106 | 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/unit_widget_item/UnitWidgetItemV0.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.* 5 | 6 | import androidx.compose.foundation.shape.CircleShape 7 | import androidx.compose.foundation.shape.RoundedCornerShape 8 | import androidx.compose.material.MaterialTheme 9 | import androidx.compose.material.Text 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.draw.clip 14 | import androidx.compose.ui.geometry.Offset 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.graphics.Shadow 17 | import androidx.compose.ui.text.TextStyle 18 | import androidx.compose.ui.text.font.FontWeight 19 | import androidx.compose.ui.unit.dp 20 | import androidx.compose.ui.unit.sp 21 | 22 | 23 | 24 | @Composable 25 | fun UnitWidgetItem() { 26 | val titleTextStyle = TextStyle( 27 | fontWeight = FontWeight.Bold, 28 | fontSize = 16.sp, 29 | color = Color(0xff2F3032), 30 | ) 31 | 32 | val contentTextStyle = TextStyle( 33 | fontSize = 14.sp, 34 | color = Color(0xff2F3032), 35 | ) 36 | 37 | val infoTextStyle = TextStyle( 38 | fontSize = 12.sp, 39 | color = Color(0xff86909c), 40 | ) 41 | 42 | val starTextStyle = TextStyle( 43 | color = MaterialTheme.colors.primary, 44 | ) 45 | 46 | val typeTextStyle = TextStyle( 47 | fontSize = 10.sp, 48 | shadow = Shadow( 49 | color = Color.White, 50 | blurRadius = 2.0f, 51 | offset = Offset(1f, 1f) 52 | ) 53 | ) 54 | 55 | val collectTextStyle = TextStyle( 56 | fontSize = 10.sp, 57 | color = MaterialTheme.colors.primary, 58 | shadow = Shadow( 59 | color = Color.White, 60 | blurRadius = 2.0f, 61 | offset = Offset(1f, 1f) 62 | ) 63 | ) 64 | 65 | Column( 66 | Modifier 67 | .fillMaxWidth() 68 | .background(Color.White) 69 | .padding(20.dp, 10.dp) 70 | ) { 71 | Row(verticalAlignment = Alignment.CenterVertically) { 72 | Text(text = "Text", style = titleTextStyle) 73 | Spacer(modifier = Modifier.width(6.dp)) 74 | Wrapper(wrapperColor = Color(0xffF3F3F5)) { 75 | Text(text = "已收藏", style = collectTextStyle) 76 | } 77 | 78 | // Box( 79 | // Modifier.fillMaxWidth(), 80 | // contentAlignment = Alignment.CenterEnd 81 | // ) { 82 | // Text(text = "★★★★★★", style = starTextStyle) 83 | // } 84 | Spacer(modifier = Modifier.weight(1f)) 85 | Text(text = "★★★★★★", style = starTextStyle) 86 | 87 | } 88 | Spacer(modifier = Modifier.height(8.dp)) 89 | Text(text = "用于显示文字的组件。拥有的属性非常多,足够满足你的使用需求,核心样式由style属性控制。", style = contentTextStyle) 90 | Spacer(modifier = Modifier.height(8.dp)) 91 | Row(verticalAlignment = Alignment.CenterVertically) { 92 | Spacer( 93 | Modifier 94 | .width(4.dp) 95 | .height(4.dp) 96 | .clip(CircleShape) 97 | .background(infoTextStyle.color) 98 | ) 99 | 100 | Spacer(modifier = Modifier.width(8.dp)) 101 | Text(text = "文字组件", style = infoTextStyle) 102 | Box( 103 | Modifier.fillMaxWidth(), 104 | contentAlignment = Alignment.CenterEnd 105 | ) { 106 | Wrapper( 107 | wrapperColor = Color(0xffF3F3F5), 108 | shape = RoundedCornerShape(10) 109 | ) { 110 | Text(text = "展示型", style = typeTextStyle) 111 | } 112 | } 113 | 114 | } 115 | } 116 | } 117 | 118 | @Composable 119 | fun Wrapper( 120 | wrapperColor: Color, 121 | shape: RoundedCornerShape = CircleShape, 122 | content: @Composable () -> Unit 123 | ) { 124 | Box( 125 | Modifier 126 | .clip(shape) 127 | .background(wrapperColor)) { 128 | Box(Modifier.padding(8.dp, 4.dp)) 129 | { content() } 130 | } 131 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/app/navigation/UnitNavigation.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.app.navigation 2 | 3 | import android.os.Handler 4 | import android.os.Looper 5 | import androidx.compose.foundation.layout.padding 6 | import androidx.compose.material.* 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.runtime.collectAsState 9 | import androidx.compose.ui.Modifier 10 | import androidx.compose.ui.graphics.Color 11 | import androidx.navigation.NavGraph.Companion.findStartDestination 12 | import androidx.navigation.NavHostController 13 | import androidx.navigation.NavType 14 | import androidx.navigation.compose.NavHost 15 | import androidx.navigation.compose.composable 16 | import androidx.lifecycle.viewmodel.compose.viewModel 17 | import androidx.navigation.compose.currentBackStackEntryAsState 18 | import androidx.navigation.compose.rememberNavController 19 | import androidx.navigation.navArgument 20 | import com.toly1994.composeunit.app.splash.UnitSplash 21 | import com.toly1994.composeunit.details.NodeModelState 22 | import com.toly1994.composeunit.details.NodeViewModel 23 | import com.toly1994.composeunit.details.WidgetDetail 24 | import com.toly1994.composeunit.doing.Doing 25 | import com.toly1994.composeunit.home.HomeLazyWidgetList 26 | import com.toly1994.composeunit.models.WidgetModel 27 | import com.toly1994.composeunit.user.UnitUserPage 28 | 29 | @Composable 30 | fun UnitNavigation( 31 | viewModel : NodeViewModel = viewModel(), 32 | onShare: (String) -> Unit) { 33 | val topNavCtrl = rememberNavController() 34 | NavHost( 35 | navController = topNavCtrl, 36 | startDestination = UnitRoute.splash 37 | ) { 38 | composable(UnitRoute.splash) { UnitSplash() } 39 | composable(UnitRoute.homeNav) { 40 | UnitHomeNavigation{ 41 | viewModel.handleEnterWidget(it,topNavCtrl) 42 | } 43 | } 44 | composable(UnitRoute.widgetDetail,) { 45 | val nodeState = viewModel.uiState.collectAsState().value 46 | WidgetDetail(nodeState, onShare) { 47 | topNavCtrl.popBackStack() 48 | } 49 | } 50 | } 51 | delayToHome(topNavCtrl) 52 | } 53 | 54 | private fun delayToHome(topNavCtrl: NavHostController, duration: Long = 1000) { 55 | Handler(Looper.getMainLooper()).postDelayed({ 56 | topNavCtrl.navigate(UnitRoute.homeNav) { 57 | popUpTo(UnitRoute.splash) { 58 | inclusive = true 59 | } 60 | } 61 | }, duration) 62 | } 63 | 64 | @Composable 65 | fun UnitHomeNavigation( 66 | toDetail: (WidgetModel) -> Unit, 67 | ) { 68 | val navCtrl = rememberNavController() 69 | val navEntry = navCtrl.currentBackStackEntryAsState() 70 | val currentRout: String? = navEntry.value?.destination?.route 71 | Scaffold(backgroundColor = Color(0xffF3F5F4), bottomBar = { 72 | UnitBottomNavBar(currentRoute = currentRout, onTapItem = { navigatorTo(navCtrl, it) }) 73 | }, topBar = { 74 | UnitAppBar(currentRout) 75 | }) { 76 | NavHost(navCtrl, startDestination = UnitRoute.widget, Modifier.padding(it)) { 77 | composable(UnitRoute.widget) { 78 | HomeLazyWidgetList(onTapItem = toDetail) 79 | } 80 | composable(UnitRoute.layout) { Doing(name = "布局集录") } 81 | composable(UnitRoute.collect) { Doing(name = "收藏集录") } 82 | composable(UnitRoute.user) { UnitUserPage() } 83 | } 84 | } 85 | } 86 | 87 | 88 | 89 | @Composable 90 | fun UnitBottomNavBar( 91 | currentRoute: String?, 92 | onTapItem: (String) -> Unit, 93 | ) { 94 | BottomNavigation() { 95 | RouterRes.bottomNavData.forEach { data -> 96 | BottomNavigationItem(selected = currentRoute == data.route, 97 | onClick = { onTapItem(data.route) }, 98 | label = { Text(text = data.text) }, 99 | icon = { 100 | Icon( 101 | imageVector = data.icon, contentDescription = "" 102 | ) 103 | }) 104 | } 105 | } 106 | } 107 | 108 | // 路由跳转 109 | private fun navigatorTo( 110 | navCtrl: NavHostController, route: String 111 | ) { 112 | navCtrl.navigate(route) { 113 | popUpTo(navCtrl.graph.findStartDestination().id) { 114 | saveState = true 115 | } 116 | restoreState = true 117 | } 118 | } 119 | 120 | 121 | -------------------------------------------------------------------------------- /highlight/src/main/java/com/neo/highlight/util/listener/HighlightTextWatcher.java: -------------------------------------------------------------------------------- 1 | package com.neo.highlight.util.listener; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | import android.text.Editable; 6 | import android.text.SpannableString; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | 11 | import com.neo.highlight.core.Highlight; 12 | import com.neo.highlight.core.HighlightContract; 13 | import com.neo.highlight.core.LinesTextWatcher; 14 | import com.neo.highlight.core.Scheme; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * Apply schemes to EditText 20 | * @author Irineu A. Silva 21 | */ 22 | final public class HighlightTextWatcher extends LinesTextWatcher implements HighlightContract { 23 | 24 | @NonNull 25 | private RANGE range = RANGE.MODIFIED; 26 | 27 | @NonNull 28 | private Highlight highlight; 29 | 30 | public HighlightTextWatcher() { 31 | highlight = new Highlight(); 32 | } 33 | 34 | public HighlightTextWatcher(@NonNull Highlight highlight) { 35 | this.highlight = highlight; 36 | } 37 | 38 | @Override 39 | protected void onLinesChange( 40 | @NonNull Editable editable, 41 | int start, int end, 42 | int firstLineStart, int lastLineEnd 43 | ) { 44 | 45 | if (range == RANGE.MODIFIED) { 46 | removeSpan(editable, firstLineStart, lastLineEnd); 47 | setSpan(editable, firstLineStart, lastLineEnd); 48 | } else { 49 | final Editable _editable = editable; 50 | new Handler(Looper.getMainLooper()).post(new Runnable() { 51 | 52 | @Override 53 | public void run() { 54 | removeSpan(_editable); 55 | setSpan(_editable); 56 | } 57 | }); 58 | } 59 | } 60 | 61 | public void setRange(@NonNull RANGE range) { 62 | this.range = range; 63 | } 64 | 65 | @NonNull 66 | public RANGE getRange() { 67 | return range; 68 | } 69 | 70 | @NonNull 71 | public Highlight getHighlight() { 72 | return highlight; 73 | } 74 | 75 | public void setHighlight(@NonNull Highlight highlight) { 76 | this.highlight = highlight; 77 | } 78 | 79 | //override HighlightContract 80 | 81 | @Override 82 | public void setSpan(Editable editable, int start, int end) { 83 | this.highlight.setSpan(editable, start, end); 84 | } 85 | 86 | @Override 87 | public void setSpan(Editable editable) { 88 | this.highlight.setSpan(editable); 89 | } 90 | 91 | @Override 92 | public void setSpan(TextView textView, int start, int end) { 93 | this.highlight.setSpan(textView, start, end); 94 | } 95 | 96 | @Override 97 | public void setSpan(TextView textView) { 98 | this.highlight.setSpan(textView); 99 | } 100 | 101 | @Override 102 | public void setSpan(SpannableString spannableString, int start, int end) { 103 | this.highlight.setSpan(spannableString, start, end); 104 | } 105 | 106 | @Override 107 | public void setSpan(SpannableString spannableString) { 108 | this.setSpan(spannableString); 109 | } 110 | 111 | @Override 112 | public void removeSpan(Editable editable) { 113 | this.highlight.removeSpan(editable); 114 | } 115 | 116 | @Override 117 | public void removeSpan(Editable editable, int start, int end) { 118 | this.highlight.removeSpan(editable, start, end); 119 | } 120 | 121 | @Override 122 | public List getSchemes() { 123 | return highlight.getSchemes(); 124 | } 125 | 126 | @Override 127 | public void setSchemes(@NonNull List schemes) { 128 | highlight.setSchemes(schemes); 129 | } 130 | 131 | @Override 132 | public void addScheme(@NonNull Scheme... schemes) { 133 | highlight.addScheme(schemes); 134 | } 135 | 136 | @Override 137 | public void clearScheme() { 138 | highlight.clearScheme(); 139 | } 140 | 141 | @Override 142 | public List> getSpanTypes() { 143 | return highlight.getSpanTypes(); 144 | } 145 | 146 | @Override 147 | public void setSpanTypes(@NonNull List> spanTypes) { 148 | highlight.setSpanTypes(spanTypes); 149 | } 150 | 151 | @Override 152 | public void addSpanType(Class span) { 153 | highlight.addSpanType(span); 154 | } 155 | 156 | @Override 157 | public void clearSpanTypes() { 158 | highlight.clearSpanTypes(); 159 | } 160 | 161 | public enum RANGE { 162 | MODIFIED, 163 | ALL 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/memory/MemoryWidgetDataStore.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.memory 2 | 3 | import com.toly1994.composeunit.models.WidgetModel 4 | 5 | object MemoryWidgetDataStore { 6 | val allWidget = listOf( 7 | WidgetModel( 8 | id = 1, 9 | name = "Text", 10 | nameCN = "文字组件", 11 | lever = 5, 12 | family = "无内容组件", 13 | collectd = true, 14 | info = "用于显示文字的组件。拥有的属性非常多,足够满足你的使用需求,核心样式由style属性控制。" 15 | ), 16 | WidgetModel( 17 | id = 2, 18 | name = "Image", 19 | nameCN = "图片组件", 20 | lever = 5, 21 | family = "无内容组件", 22 | collectd = true, 23 | info = "用于显示一张图片,可以从资源文件中加载。可以指定适应方式、对齐模式、颜色混合模式、透明度等属性。" 24 | ), 25 | WidgetModel( 26 | id = 3, 27 | name = "Icon", 28 | nameCN = "图标组件", 29 | lever = 3, 30 | family = "无内容组件", 31 | collectd = false, 32 | info = "用于图标显示的组件。可指定图标资源、颜色。非常简单,但是非常用。" 33 | ), 34 | WidgetModel( 35 | id = 4, 36 | name = "Row", 37 | nameCN = "行布局组件", 38 | lever = 5, 39 | family = "多内容组件", 40 | collectd = true, 41 | info = "水平方向为竖向的布局,可容纳多个组件,可以通过属性控制排布的对齐方式。" 42 | ), 43 | WidgetModel( 44 | id = 5, 45 | name = "Column", 46 | nameCN = "列布局组件", 47 | lever = 5, 48 | family = "多内容组件", 49 | collectd = false, 50 | info = "排布方向为竖向的布局,可容纳多个组件,可以通过属性控制排布的对齐方式。" 51 | ), 52 | WidgetModel( 53 | id = 6, 54 | name = "Box", 55 | nameCN = "叠放盒组件", 56 | lever = 5, 57 | family = "多内容组件", 58 | collectd = true, 59 | info = "可容纳多个组件,堆叠排放,可以通过属性控制排布的对齐方式等属性。" 60 | ), 61 | WidgetModel( 62 | id = 7, 63 | name = "LazyColumn", 64 | nameCN = "延迟纵向列表", 65 | lever = 5, 66 | family = "多内容组件", 67 | collectd = true, 68 | info = "具有懒加载条目功能的纵向列表,支持纵向滑动处理,是非常常用的列表组件。" 69 | ), 70 | WidgetModel( 71 | id = 8, 72 | name = "LazyRow", 73 | nameCN = "延迟横向列表", 74 | lever = 4, 75 | family = "多内容组件", 76 | collectd = true, 77 | info = "与 LazyColumn 相对应,具有懒加载条目功能的横向列表,支持横向滑动处理。" 78 | ), 79 | WidgetModel( 80 | id = 9, 81 | name = "LazyVerticalGrid", 82 | nameCN = "延迟纵向网格", 83 | lever = 5, 84 | family = "多内容组件", 85 | collectd = true, 86 | info = "具有懒加载条目功能的纵向网格布局,支持纵向滑动处理,是非常常用的网格组件。" 87 | ), 88 | WidgetModel( 89 | id = 10, 90 | name = "LazyHorizontalGrid", 91 | nameCN = "延迟横向网格", 92 | lever = 5, 93 | family = "多内容组件", 94 | collectd = true, 95 | info = "与 LazyHorizontalGrid 相对应,具有懒加载条目功能的横向网格布局,支持横向滑动处理。" 96 | ), 97 | WidgetModel( 98 | id = 11, 99 | name = "Scaffold", 100 | nameCN = "脚手架组件", 101 | lever = 4, 102 | family = "卡槽型组件", 103 | collectd = true, 104 | info = "一个通用 app 结构,包括上、下、左、右、中、浮动按钮部位,对应位置可盛放组件。" 105 | ), 106 | WidgetModel( 107 | id = 12, 108 | name = "AppTopBar", 109 | nameCN = "应用头部栏", 110 | lever = 4, 111 | family = "卡槽型组件", 112 | collectd = true, 113 | info = "一个应用顶部栏的通用结构,可在指定的部位放置相应的组件,常用于Scaffold组件中。" 114 | ), 115 | WidgetModel( 116 | id = 13, 117 | name = "FloatingActionButton", 118 | nameCN = "浮动按钮", 119 | lever = 3, 120 | family = "单内容组件", 121 | collectd = true, 122 | info = "Material 风格,一般用于Scaffold中,可摆放在特定位置。可盛放一个子组件,接收点击、可定义颜色、形状等。" 123 | ), 124 | WidgetModel( 125 | id = 14, 126 | name = "Spacer", 127 | nameCN = "占位组件", 128 | lever = 4, 129 | family = "无内容组件", 130 | collectd = false, 131 | info = "只有 modifier 参数的组件,一般用于占位场景。" 132 | ), 133 | WidgetModel( 134 | id = 15, 135 | name = "Divider", 136 | nameCN = "分割线组件", 137 | lever = 2, 138 | family = "无内容组件", 139 | collectd = false, 140 | info = "横向分割线,默认 1dp,可指定头部空缺长度。" 141 | ) 142 | ) 143 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/repository/memory/MemoryNodeDataStore.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.repository.memory 2 | 3 | import com.toly1994.composeunit.models.NodeModel 4 | import com.toly1994.composeunit.repository.memory.node_res.* 5 | 6 | object MemoryNodeDataStore { 7 | val allNodes = listOf( 8 | //==== Text ========== 9 | NodeModel( 10 | widgetId = 1, 11 | name = "文字的基本样式", 12 | code = TextNode1Code, 13 | info = TextNode1Info 14 | ), 15 | NodeModel( 16 | widgetId = 1, 17 | name = "文字背景与阴影", 18 | code = TextNode2Code, 19 | info = TextNode2Info 20 | ), 21 | NodeModel( 22 | widgetId = 1, 23 | name = "文字装饰线与缩进", 24 | code = TextNode3Code, 25 | info = TextNode3Info 26 | ), 27 | NodeModel( 28 | widgetId = 1, 29 | name = "多行与包裹溢出", 30 | code = TextNode4Code, 31 | info = TextNode4Info 32 | ), 33 | NodeModel( 34 | widgetId = 1, 35 | name = "文字对齐与行高", 36 | code = TextNode5Code, 37 | info = TextNode5Info 38 | ), 39 | //==== Image ========== 40 | NodeModel( 41 | widgetId = 2, 42 | name = "图片加载方式", 43 | code = ImageNode1Code, 44 | info = ImageNode1Info 45 | ), 46 | NodeModel( 47 | widgetId = 2, 48 | name = "图片对齐模式", 49 | code = ImageNode2Code, 50 | info = ImageNode2Info 51 | ), 52 | NodeModel( 53 | widgetId = 2, 54 | name = "图片缩放模式", 55 | code = ImageNode3Code, 56 | info = ImageNode3Info 57 | ), 58 | NodeModel( 59 | widgetId = 2, 60 | name = "颜色叠合模式", 61 | code = ImageNode4Code, 62 | info = ImageNode4Info 63 | ), 64 | //==== Icon ========== 65 | NodeModel( 66 | widgetId = 3, 67 | name = "图标的使用", 68 | code = IconNode1Code, 69 | info = IconNode1Info 70 | ), 71 | //==== Row ========== 72 | NodeModel( 73 | widgetId = 4, 74 | name = "行的水平对齐模式", 75 | code = RowNode1Code, 76 | info = RowNode1Info 77 | ), 78 | NodeModel( 79 | widgetId = 4, 80 | name = "行的竖直对齐模式", 81 | code = RowNode2Code, 82 | info = RowNode2Info 83 | ), 84 | NodeModel( 85 | widgetId = 4, 86 | name = "行中的组件宽度占比", 87 | code = RowNode3Code, 88 | info = RowNode3Info 89 | ), 90 | //==== Column ========== 91 | NodeModel( 92 | widgetId = 5, 93 | name = "列的竖直对齐模式", 94 | code = ColumnNode1Code, 95 | info = ColumnNode1Info 96 | ), 97 | NodeModel( 98 | widgetId = 5, 99 | name = "列的水平对齐模式", 100 | code = ColumnNode2Code, 101 | info = ColumnNode2Info 102 | ), 103 | NodeModel( 104 | widgetId = 5, 105 | name = "列中的组件高度占比", 106 | code = ColumnNode3Code, 107 | info = ColumnNode3Info 108 | ), 109 | //==== Box ========== 110 | NodeModel( 111 | widgetId = 6, 112 | name = "Box 的对齐方式", 113 | code = BoxNode1Code, 114 | info = BoxNode1Info 115 | ), 116 | NodeModel( 117 | widgetId = 6, 118 | name = "修改单个子组件的对齐方式", 119 | code = BoxNode2Code, 120 | info = BoxNode2Info 121 | ), 122 | //==== LazyColumn ========== 123 | NodeModel( 124 | widgetId = 7, 125 | name = "延迟纵向列表基本使用", 126 | code = LazyColumnNode1Code, 127 | info = LazyColumnNode1Info 128 | ), 129 | //==== LazyColumn ========== 130 | NodeModel( 131 | widgetId = 8, 132 | name = "延迟横向列表基本使用", 133 | code = LazyRowNode1Code, 134 | info = LazyRowNode1Info 135 | ), 136 | //==== LazyVerticalGrid ========== 137 | NodeModel( 138 | widgetId = 9, 139 | name = "延迟纵向网格基本使用", 140 | code = LazyVerticalGridNode1Code, 141 | info = LazyVerticalGridNode1Info 142 | ), 143 | //==== LazyHorizontalGrid ========== 144 | NodeModel( 145 | widgetId = 10, 146 | name = "延迟横向网格基本使用", 147 | code = LazyHorizontalGridNode1Code, 148 | info = LazyHorizontalGridNode1Info 149 | ), 150 | ) 151 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/juejin_article_item/JuejinArticleItemV1.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.layout.* 6 | import androidx.compose.foundation.shape.RoundedCornerShape 7 | import androidx.compose.material.Icon 8 | import androidx.compose.material.Text 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.ui.Alignment 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.draw.clip 13 | import androidx.compose.ui.geometry.Offset 14 | import androidx.compose.ui.graphics.Color 15 | import androidx.compose.ui.graphics.Shadow 16 | import androidx.compose.ui.layout.ContentScale 17 | import androidx.compose.ui.res.painterResource 18 | import androidx.compose.ui.text.TextStyle 19 | import androidx.compose.ui.text.font.FontWeight 20 | import androidx.compose.ui.text.style.TextOverflow 21 | import androidx.compose.ui.unit.dp 22 | import androidx.compose.ui.unit.sp 23 | import com.toly1994.composeunit.R 24 | 25 | 26 | @Composable 27 | fun JuejinArticleItemV1() { 28 | val titleTextStyle = TextStyle( 29 | fontWeight = FontWeight.Bold, 30 | fontSize = 16.sp, 31 | color = Color(0xff2F3032), 32 | ) 33 | Column( 34 | Modifier.fillMaxWidth().background(Color.White).padding(20.dp, 10.dp) 35 | ) { 36 | Text(text = "【Flutter 异步编程 - 柒】 | 深入剖析 Stream 机制源码实现", style = titleTextStyle) 37 | JuejinArticleItemCenter() 38 | Spacer(modifier = Modifier.height(8.dp)) 39 | JuejinArticleItemFooter() 40 | } 41 | } 42 | 43 | @Composable 44 | fun JuejinArticleItemCenter() { 45 | val contentTextStyle = TextStyle( 46 | fontSize = 14.sp, 47 | color = Color(0xff5A576C), 48 | ) 49 | val userTextStyle = TextStyle( 50 | fontSize = 14.sp, 51 | color = Color(0xff58575F), 52 | ) 53 | val timeTextStyle = TextStyle( 54 | fontSize = 14.sp, 55 | color = Color(0xff8C929E), 56 | ) 57 | Row( 58 | verticalAlignment = Alignment.CenterVertically, 59 | ) { 60 | Column( 61 | Modifier 62 | .weight(1f) 63 | .padding(end = 5.dp) 64 | ) { 65 | Row( 66 | Modifier.padding(0.dp, 4.dp) 67 | ) { 68 | Text(text = "张风捷特烈", style = userTextStyle) 69 | Text(text = " | ", style = timeTextStyle) 70 | Text(text = "14小时前", style = timeTextStyle) 71 | } 72 | Text( 73 | maxLines = 2, 74 | overflow = TextOverflow.Ellipsis, 75 | text = "一、从 Stream 的回调监听开始说起 在第三篇中,我们已经对 Stream 有了基本的概念认知,以及使用方式。 Stream 的特点是可以通过 listen 方法的第一入参 onData,不断监听", 76 | style = contentTextStyle 77 | ) 78 | } 79 | Image( 80 | modifier = Modifier 81 | .width(90.dp) 82 | .height(60.dp) 83 | .clip(RoundedCornerShape(10)), 84 | painter = painterResource(id = R.mipmap.caver), 85 | contentDescription = "", 86 | contentScale = ContentScale.FillBounds 87 | ) 88 | } 89 | } 90 | 91 | @Composable 92 | fun JuejinArticleItemFooter() { 93 | val typeTextStyle = TextStyle( 94 | fontSize = 12.sp, 95 | color = Color(0xff90959A), 96 | shadow = Shadow( 97 | color = Color.White, 98 | blurRadius = 2.0f, 99 | offset = Offset(1f, 1f) 100 | ) 101 | ) 102 | val infoTextStyle = TextStyle( 103 | fontSize = 12.sp, 104 | color = Color(0xff86909c), 105 | ) 106 | Row(verticalAlignment = Alignment.CenterVertically) { 107 | Icon( 108 | modifier = Modifier.size(18.dp, 18.dp), 109 | tint = Color(0xff1F80FD), 110 | painter = painterResource(id = R.mipmap.zan), contentDescription = "" 111 | ) 112 | Spacer(modifier = Modifier.width(2.dp)) 113 | Text(text = "100", style = infoTextStyle) 114 | Spacer(modifier = Modifier.width(10.dp)) 115 | Icon( 116 | modifier = Modifier.size(18.dp, 18.dp), 117 | tint = infoTextStyle.color, 118 | painter = painterResource(id = R.mipmap.pinglun), contentDescription = "" 119 | ) 120 | Spacer(modifier = Modifier.width(2.dp)) 121 | Text(text = "99", style = infoTextStyle) 122 | Spacer( 123 | Modifier.weight(1f) 124 | ) 125 | Wrapper( 126 | wrapperColor = Color(0xffF3F3F5), 127 | shape = RoundedCornerShape(10) 128 | ) { 129 | Text(text = "Android", style = typeTextStyle) 130 | } 131 | Spacer(modifier = Modifier.width(8.dp)) 132 | Wrapper( 133 | wrapperColor = Color(0xffF3F3F5), 134 | shape = RoundedCornerShape(10) 135 | ) { 136 | Text(text = "Flutter", style = typeTextStyle) 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/wechat_item/WeChatItem.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts.wechat_item 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.foundation.shape.CircleShape 8 | import androidx.compose.foundation.shape.RoundedCornerShape 9 | import androidx.compose.material.* 10 | import androidx.compose.material.icons.Icons 11 | import androidx.compose.material.icons.filled.Warning 12 | import androidx.compose.material.icons.rounded.Add 13 | import androidx.compose.material.icons.rounded.ShoppingCart 14 | import androidx.compose.runtime.Composable 15 | import androidx.compose.ui.Alignment 16 | import androidx.compose.ui.BiasAlignment 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.draw.clip 19 | import androidx.compose.ui.geometry.Offset 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.Shadow 22 | import androidx.compose.ui.res.painterResource 23 | import androidx.compose.ui.text.TextStyle 24 | import androidx.compose.ui.text.font.FontWeight 25 | import androidx.compose.ui.unit.dp 26 | import androidx.compose.ui.unit.sp 27 | import com.toly1994.composeunit.R 28 | 29 | @Composable 30 | fun WeChatItem(banned:Boolean = false) { 31 | val titleTextStyle = TextStyle( 32 | fontWeight = FontWeight.Bold, 33 | fontSize = 16.sp, 34 | color = Color(0xff2F3032), 35 | ) 36 | 37 | val subTextStyle = TextStyle( 38 | fontSize = 12.sp, 39 | color = Color(0xffC5C5C5), 40 | ) 41 | 42 | Column( 43 | Modifier 44 | .fillMaxWidth() 45 | .background(Color.White) 46 | ) { 47 | Box( 48 | modifier = Modifier.padding(10.dp, 10.dp) 49 | ) { 50 | Row( 51 | verticalAlignment = Alignment.Top 52 | ) { 53 | Box( 54 | contentAlignment = BiasAlignment(1.2f, -1.2f) 55 | ) { 56 | Image( 57 | modifier = Modifier 58 | .width(45.dp) 59 | .clip(RoundedCornerShape(10)), 60 | painter = painterResource(id = R.mipmap.head_icon), 61 | contentDescription = "", 62 | ) 63 | if(banned) { 64 | Spacer( 65 | Modifier 66 | .width(10.dp) 67 | .height(10.dp) 68 | .clip(CircleShape) 69 | .background(Color.Red) 70 | ) 71 | } else { 72 | CircleNumTip( 73 | color = Color.Red, radius = 8f, count = 1 74 | ) 75 | } 76 | } 77 | 78 | Spacer(modifier = Modifier.width(10.dp)) 79 | Column( 80 | Modifier.weight(1f) 81 | ) { 82 | Text(text = "堕天使者", style = titleTextStyle) 83 | Spacer(modifier = Modifier.height(4.dp)) 84 | Text(text = "你好,Compose 学的怎么样了?", style = subTextStyle) 85 | } 86 | Column() { 87 | Text(text = "22:25", style = subTextStyle) 88 | if(banned) { 89 | Spacer(modifier = Modifier.height(6.dp)) 90 | } 91 | if(banned) { 92 | Icon( 93 | Icons.Default.Warning, "", 94 | tint = subTextStyle.color, 95 | modifier = Modifier.size(18.dp,18.dp)) 96 | } 97 | } 98 | } 99 | } 100 | Divider( 101 | startIndent = 70.dp, 102 | thickness = 0.5.dp 103 | ) 104 | } 105 | 106 | 107 | } 108 | 109 | @Composable 110 | fun Wrapper( 111 | wrapperColor: Color, 112 | shape: RoundedCornerShape = CircleShape, 113 | content: @Composable () -> Unit 114 | ) { 115 | Box( 116 | Modifier 117 | .clip(shape) 118 | .background(wrapperColor) 119 | ) { 120 | Box(Modifier.padding(8.dp, 4.dp)) 121 | { content() } 122 | } 123 | } 124 | 125 | @Composable 126 | fun CircleNumTip( 127 | color: Color, 128 | count: Int, 129 | radius: Float, 130 | ) { 131 | Box( 132 | Modifier 133 | .width(radius.dp * 2) 134 | .height(radius.dp * 2) 135 | .clip(CircleShape) 136 | .background(color), 137 | contentAlignment = Alignment.Center 138 | ) { 139 | Text( 140 | text = "$count", style = TextStyle( 141 | fontSize = (radius / 0.8).sp, 142 | color = Color.White, 143 | ) 144 | ) 145 | } 146 | } -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/composeunit/layouts/juejin_article_item/JuejinArticleItemV0.kt: -------------------------------------------------------------------------------- 1 | package com.toly1994.composeunit.layouts 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.layout.* 6 | import androidx.compose.foundation.shape.RoundedCornerShape 7 | import androidx.compose.material.Icon 8 | import androidx.compose.material.Text 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.ui.Alignment 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.draw.clip 13 | import androidx.compose.ui.geometry.Offset 14 | import androidx.compose.ui.graphics.Color 15 | import androidx.compose.ui.graphics.Shadow 16 | import androidx.compose.ui.layout.ContentScale 17 | import androidx.compose.ui.res.painterResource 18 | import androidx.compose.ui.text.TextStyle 19 | import androidx.compose.ui.text.font.FontWeight 20 | import androidx.compose.ui.text.style.TextOverflow 21 | import androidx.compose.ui.unit.dp 22 | import androidx.compose.ui.unit.sp 23 | import com.toly1994.composeunit.R 24 | 25 | 26 | @Composable 27 | fun JuejinArticleItemV0() { 28 | val titleTextStyle = TextStyle( 29 | fontWeight = FontWeight.Bold, 30 | fontSize = 16.sp, 31 | color = Color(0xff2F3032), 32 | ) 33 | val contentTextStyle = TextStyle( 34 | fontSize = 14.sp, 35 | color = Color(0xff5A576C), 36 | ) 37 | val infoTextStyle = TextStyle( 38 | fontSize = 12.sp, 39 | color = Color(0xff86909c), 40 | ) 41 | val typeTextStyle = TextStyle( 42 | fontSize = 12.sp, 43 | color = Color(0xff90959A), 44 | shadow = Shadow( 45 | color = Color.White, 46 | blurRadius = 2.0f, 47 | offset = Offset(1f, 1f) 48 | ) 49 | ) 50 | val userTextStyle = TextStyle( 51 | fontSize = 14.sp, 52 | color = Color(0xff58575F), 53 | ) 54 | val timeTextStyle = TextStyle( 55 | fontSize = 14.sp, 56 | color = Color(0xff8C929E), 57 | ) 58 | Column( 59 | Modifier 60 | .fillMaxWidth() 61 | .background(Color.White) 62 | .padding(20.dp, 10.dp) 63 | ) { 64 | Text(text = "【Flutter 异步编程 - 柒】 | 深入剖析 Stream 机制源码实现", style = titleTextStyle) 65 | Row( 66 | verticalAlignment = Alignment.CenterVertically, 67 | ) { 68 | Column( 69 | Modifier 70 | .weight(1f) 71 | .padding(end = 5.dp) 72 | ) { 73 | Row( 74 | Modifier.padding(0.dp, 4.dp) 75 | ) { 76 | Text(text = "张风捷特烈", style = userTextStyle) 77 | Text(text = " | ", style = timeTextStyle) 78 | Text(text = "14小时前", style = timeTextStyle) 79 | } 80 | Text( 81 | maxLines = 2, 82 | overflow = TextOverflow.Ellipsis, 83 | text = "一、从 Stream 的回调监听开始说起 在第三篇中,我们已经对 Stream 有了基本的概念认知,以及使用方式。 Stream 的特点是可以通过 listen 方法的第一入参 onData,不断监听", 84 | style = contentTextStyle 85 | ) 86 | } 87 | Image( 88 | modifier = Modifier 89 | .width(90.dp) 90 | .height(60.dp) 91 | .clip(RoundedCornerShape(10)), 92 | painter = painterResource(id = R.mipmap.caver), 93 | contentDescription = "", 94 | contentScale = ContentScale.FillBounds 95 | ) 96 | } 97 | 98 | Spacer(modifier = Modifier.height(8.dp)) 99 | Row(verticalAlignment = Alignment.CenterVertically) { 100 | Icon( 101 | modifier = Modifier.size(18.dp, 18.dp), 102 | tint = Color(0xff1F80FD), 103 | painter = painterResource(id = R.mipmap.zan), contentDescription = "" 104 | ) 105 | Spacer(modifier = Modifier.width(2.dp)) 106 | Text(text = "100", style = infoTextStyle) 107 | Spacer(modifier = Modifier.width(10.dp)) 108 | Icon( 109 | modifier = Modifier.size(18.dp, 18.dp), 110 | tint = infoTextStyle.color, 111 | painter = painterResource(id = R.mipmap.pinglun), contentDescription = "" 112 | ) 113 | Spacer(modifier = Modifier.width(2.dp)) 114 | Text(text = "99", style = infoTextStyle) 115 | Spacer( 116 | Modifier.weight(1f) 117 | ) 118 | Wrapper( 119 | wrapperColor = Color(0xffF3F3F5), 120 | shape = RoundedCornerShape(10) 121 | ) { 122 | Text(text = "Android", style = typeTextStyle) 123 | } 124 | Spacer(modifier = Modifier.width(8.dp)) 125 | Wrapper( 126 | wrapperColor = Color(0xffF3F3F5), 127 | shape = RoundedCornerShape(10) 128 | ) { 129 | Text(text = "Flutter", style = typeTextStyle) 130 | } 131 | } 132 | } 133 | } 134 | --------------------------------------------------------------------------------