├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── drawable │ │ │ │ ├── btn_simple.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ ├── activity_test.xml │ │ │ │ └── activity_main.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── drake │ │ │ │ └── channel │ │ │ │ └── exmple │ │ │ │ ├── TestActivity.kt │ │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── drake │ │ │ └── channel │ │ │ └── exmple │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── drake │ │ └── channel │ │ └── exmple │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── channel ├── consumer-rules.pro ├── .gitignore ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── drake │ │ │ │ └── channel │ │ │ │ ├── ChannelTag.kt │ │ │ │ ├── ChannelEvent.kt │ │ │ │ ├── ChannelScope.kt │ │ │ │ └── Channel.kt │ │ └── res │ │ │ └── values │ │ │ └── strings.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── drake │ │ │ └── channel │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── drake │ │ └── channel │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── docs ├── api │ ├── styles │ │ ├── logo-styles.css │ │ ├── jetbrains-mono.css │ │ ├── main.css │ │ └── style.css │ ├── images │ │ ├── logo-icon.svg │ │ ├── copy-icon.svg │ │ ├── footer-go-to-link.svg │ │ ├── arrow_down.svg │ │ ├── copy-successful-icon.svg │ │ ├── go-to-top-icon.svg │ │ ├── anchor-copy-button.svg │ │ └── docs_logo.svg │ ├── scripts │ │ ├── sourceset_dependencies.js │ │ ├── navigation-pane.json │ │ ├── clipboard.js │ │ ├── navigation-loader.js │ │ ├── pages.json │ │ └── platform-content-handler.js │ ├── -channel │ │ ├── package-list │ │ └── com.drake.channel │ │ │ ├── send-tag.html │ │ │ ├── receive-tag-live.html │ │ │ ├── receive-event-live.html │ │ │ ├── send-event.html │ │ │ ├── receive-event-handler.html │ │ │ ├── receive-tag-handler.html │ │ │ ├── receive-event.html │ │ │ ├── receive-tag.html │ │ │ └── index.html │ ├── index.html │ └── navigation.html ├── img │ ├── book-open.svg │ ├── discussesions.svg │ └── issues.svg ├── live.md ├── lifecycle.md ├── thread.md ├── index.md ├── css │ └── extra.css └── material │ └── partials │ └── footer.html ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── .github └── workflows │ └── main.yml ├── gradle.properties ├── mkdocs.yml ├── gradlew.bat ├── README.md ├── gradlew └── LICENSE /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /channel/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /channel/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':channel' 2 | rootProject.name='Channel' 3 | -------------------------------------------------------------------------------- /docs/api/styles/logo-styles.css: -------------------------------------------------------------------------------- 1 | #logo { 2 | background-image: url(../images/docs_logo.svg); 3 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangjingkanji/Channel/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /docs/api/images/logo-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/api/scripts/sourceset_dependencies.js: -------------------------------------------------------------------------------- 1 | sourceset_dependencies='{":channel:dokkaHtml/androidTestRelease":[],":channel:dokkaHtml/debug":[],":channel:dokkaHtml/main":[],":channel:dokkaHtml/release":[]}' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/navEditor.xml 5 | /.idea/assetWizardSettings.xml 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | .cxx 11 | /.idea/ 12 | -------------------------------------------------------------------------------- /docs/api/images/copy-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/api/images/footer-go-to-link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/img/book-open.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /docs/api/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 18 10:44:26 CST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /docs/api/images/copy-successful-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/api/images/go-to-top-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/live.md: -------------------------------------------------------------------------------- 1 | 使用`receiveEventLive`指定仅在App前台时接收事件, 如果后台就延迟到前台时接收 2 | 3 | === "发送" 4 | ```kotlin 5 | sendEvent("对话框消息") 6 | ``` 7 | 8 | === "接收" 9 | ```kotlin 10 | receiveEventLive(true) { 11 | tv.text = it 12 | } 13 | ``` 14 | 15 | !!! note "活跃状态" 16 | 非`onPause`或者`onDestroy`都属于正在活跃中 -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | deploy: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-python@v2 12 | with: 13 | python-version: 3.x 14 | - run: pip install mkdocs-material 15 | - run: mkdocs gh-deploy --force 16 | -------------------------------------------------------------------------------- /docs/lifecycle.md: -------------------------------------------------------------------------------- 1 | `Channel.receiveEvent`支持`自动注销`, 当然也支持手动注销 2 | 3 | ## 指定取消生命周期 4 | 5 | 默认在`Lifecycle.Event.ON_DESTROY`销毁, 但是可以指定其参数 6 | 7 | ```kotlin 8 | receiveEvent(lifeEvent = Lifecycle.Event.ON_PAUSE) { 9 | tv.text = it 10 | } 11 | ``` 12 | 13 | ## 手动注销 14 | 15 | 使用`receiveEventHandler`可返回用于手动取消事件的对象 16 | 17 | ```kotlin 18 | val receiver = receiveEventHandler { 19 | tv.text = it 20 | } 21 | 22 | receiver.cancel() // 手动调用函数注销 23 | ``` -------------------------------------------------------------------------------- /docs/thread.md: -------------------------------------------------------------------------------- 1 | - 可以在任何线程发送事件 2 | - 可以在任何线程接收事件, 回调永远在主线程 3 | 4 |
5 | 使用协程函数可以切换回调的线程(也被称为调度器) 6 | 7 | ```kotlin 8 | receiveEvent { 9 | // 当前主线程 10 | tv.text = it 11 | 12 | launch(Dispatchers.IO) { 13 | // 执行异步任务 14 | } 15 | } 16 | ``` 17 | 18 | 具备返回值回调的切换 19 | ```kotlin 20 | receiveEvent { 21 | // 当前主线程 22 | tv.text = withContext(Dispatchers.IO){ 23 | // 切换到IO线程, 返回结果到主线程 24 | "新的姓名" 25 | } 26 | } 27 | ``` -------------------------------------------------------------------------------- /channel/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /channel/src/main/java/com/drake/channel/ChannelTag.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel 18 | 19 | internal class ChannelTag -------------------------------------------------------------------------------- /docs/api/images/anchor-copy-button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Channel 19 | 20 | -------------------------------------------------------------------------------- /channel/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Channel 19 | 20 | -------------------------------------------------------------------------------- /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 22 | -------------------------------------------------------------------------------- /channel/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 22 | -------------------------------------------------------------------------------- /channel/src/main/java/com/drake/channel/ChannelEvent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel 18 | 19 | 20 | /** 21 | * Channel承载事件的模型 22 | */ 23 | @PublishedApi 24 | internal class ChannelEvent(val event: T, val tag: String? = null) -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_simple.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | #008577 19 | #00574B 20 | #008577 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 可以在任何地方发送和接收任何对象 2 | 3 | === "发送" 4 | ```kotlin 5 | sendEvent("任何对象") 6 | ``` 7 | 8 | === "接收" 9 | ```kotlin 10 | receiveEvent() { 11 | tv.text = it 12 | } 13 | ``` 14 | 15 | !!! success "事件匹配" 16 | `sendEvent`的参数和`receiveEvent`的泛型类型匹配即可接受事件, 可以是任何对象 17 | 18 | ## 标签 19 | 如果类型重复, 可以通过加标签来区分事件 20 | 21 | 创建一个事件类 22 | ```kotlin 23 | data class UserInfoEvent(val name:String, val age:Int) 24 | ``` 25 | 26 | === "发送" 27 | ```kotlin 28 | sendEvent(UserInfoEvent("新的姓名", 24), "tag_change_name") 29 | ``` 30 | 31 | === "接收" 32 | ```kotlin 33 | receiveEvent("tag_change_name", "tag_change_username") { 34 | tv.text = it.name // it 即为UserInfoEvent 35 | } 36 | ``` 37 | 38 | 39 | - 标签可以是多个, 只要匹配一个标签, 就可成功接收事件 40 | - 建议遵守前缀`tag_`命名规范, 方便全局搜索标签来定位事件 41 | 42 |
43 | !!! failure "不支持粘性事件" 44 | 因为粘性事件本质属于全局变量, 会在应用意外销毁时被清除, 导致空指针 45 | 46 | 建议使用 [Serialize](https://github.com/liangjingkanji/Serialize) 创建序列化字段, 读写自动映射磁盘 -------------------------------------------------------------------------------- /channel/src/test/java/com/drake/channel/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel 18 | 19 | import org.junit.Assert.assertEquals 20 | import org.junit.Test 21 | 22 | /** 23 | * Example local unit test, which will execute on the development machine (host). 24 | * 25 | * See [testing documentation](http://d.android.com/tools/testing). 26 | */ 27 | class ExampleUnitTest { 28 | @Test 29 | fun addition_isCorrect() { 30 | assertEquals(4, 2 + 2) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/test/java/com/drake/channel/exmple/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel.exmple 18 | 19 | import org.junit.Assert.assertEquals 20 | import org.junit.Test 21 | 22 | /** 23 | * Example local unit test, which will execute on the development machine (host). 24 | * 25 | * See [testing documentation](http://d.android.com/tools/testing). 26 | */ 27 | class ExampleUnitTest { 28 | @Test 29 | fun addition_isCorrect() { 30 | assertEquals(4, 2 + 2) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /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=-Xmx1536m 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 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /docs/api/styles/jetbrains-mono.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Iosevka'; 3 | src: local('Iosevka Medium'), 4 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/iosevka/iosevka-medium.woff2') format('woff2'); 5 | font-display: swap; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | @font-face { 10 | font-family: 'Iosevka'; 11 | src: local('Iosevka-bold'), 12 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/iosevka/iosevka-medium.woff2') format('woff2'); 13 | font-display: swap; 14 | font-weight: bold; 15 | font-style: normal; 16 | } 17 | @font-face{ 18 | font-family: 'HYZhengYuan'; 19 | src: local('HYZhengYuan'), 20 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/HYZhengYuan.ttf') format('truetype'); 21 | font-display: swap; 22 | font-weight: normal; 23 | font-style: normal; 24 | } 25 | @font-face{ 26 | font-family: 'HYZhengYuan'; 27 | src: local('HYZhengYuan-75W'), 28 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/HYZhengYuan.ttf') format('truetype'); 29 | font-display: swap; 30 | font-weight: bold; 31 | font-style: normal; 32 | } -------------------------------------------------------------------------------- /docs/api/scripts/navigation-pane.json: -------------------------------------------------------------------------------- 1 | [{"name":"Channel","description":null,"location":"index.html","searchKeys":["Channel"]},{"name":"com.drake.channel","description":null,"location":"-channel/com.drake.channel/index.html","searchKeys":["com.drake.channel"]},{"name":"receiveEvent()","description":null,"location":"-channel/com.drake.channel/receive-event.html","searchKeys":["receiveEvent()"]},{"name":"receiveEventHandler()","description":null,"location":"-channel/com.drake.channel/receive-event-handler.html","searchKeys":["receiveEventHandler()"]},{"name":"receiveEventLive()","description":null,"location":"-channel/com.drake.channel/receive-event-live.html","searchKeys":["receiveEventLive()"]},{"name":"receiveTag()","description":null,"location":"-channel/com.drake.channel/receive-tag.html","searchKeys":["receiveTag()"]},{"name":"receiveTagHandler()","description":null,"location":"-channel/com.drake.channel/receive-tag-handler.html","searchKeys":["receiveTagHandler()"]},{"name":"receiveTagLive()","description":null,"location":"-channel/com.drake.channel/receive-tag-live.html","searchKeys":["receiveTagLive()"]},{"name":"sendEvent()","description":null,"location":"-channel/com.drake.channel/send-event.html","searchKeys":["sendEvent()"]},{"name":"sendTag()","description":null,"location":"-channel/com.drake.channel/send-tag.html","searchKeys":["sendTag()"]}] 2 | -------------------------------------------------------------------------------- /docs/api/images/docs_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /channel/src/androidTest/java/com/drake/channel/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel 18 | 19 | import androidx.test.ext.junit.runners.AndroidJUnit4 20 | import androidx.test.platform.app.InstrumentationRegistry 21 | import org.junit.Assert.assertEquals 22 | import org.junit.Test 23 | import org.junit.runner.RunWith 24 | 25 | /** 26 | * Instrumented test, which will execute on an Android device. 27 | * 28 | * See [testing documentation](http://d.android.com/tools/testing). 29 | */ 30 | @RunWith(AndroidJUnit4::class) 31 | class ExampleInstrumentedTest { 32 | @Test 33 | fun useAppContext() { 34 | // Context of the app under test. 35 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 36 | assertEquals("com.drake.channel.test", appContext.packageName) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/drake/channel/exmple/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel.exmple 18 | 19 | import androidx.test.ext.junit.runners.AndroidJUnit4 20 | import androidx.test.platform.app.InstrumentationRegistry 21 | import org.junit.Assert.assertEquals 22 | import org.junit.Test 23 | import org.junit.runner.RunWith 24 | 25 | /** 26 | * Instrumented test, which will execute on an Android device. 27 | * 28 | * See [testing documentation](http://d.android.com/tools/testing). 29 | */ 30 | @RunWith(AndroidJUnit4::class) 31 | class ExampleInstrumentedTest { 32 | @Test 33 | fun useAppContext() { 34 | // Context of the app under test. 35 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 36 | assertEquals("com.drake.channel.exmple", appContext.packageName) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/img/discussesions.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 编组备份 5 | 6 | 7 | 8 | 11 | 14 | 16 | 讨论 17 | 18 | 20 | Discussions 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/img/issues.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 编组 5 | 6 | 7 | 8 | 9 | 12 | 14 | 常见问题 15 | 16 | 17 | 18 | 21 | 23 | Issues 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/drake/channel/exmple/TestActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel.exmple 18 | 19 | import android.widget.Toast 20 | import com.drake.channel.exmple.databinding.ActivityTestBinding 21 | import com.drake.channel.sendEvent 22 | import com.drake.engine.base.EngineActivity 23 | 24 | class TestActivity : EngineActivity(R.layout.activity_test) { 25 | 26 | override fun initView() { 27 | binding.btnSendEvent.setOnClickListener { 28 | val event = binding.etEvent.text.toString() 29 | if (event.isBlank()) { 30 | Toast.makeText(this, "请输入事件内容", Toast.LENGTH_SHORT).show() 31 | } else { 32 | sendEvent(event) 33 | } 34 | } 35 | binding.btnSendEvent2.setOnClickListener { 36 | val event = binding.etEvent.text.toString() 37 | if (event.isBlank()) { 38 | Toast.makeText(this, "请输入标签事件内容", Toast.LENGTH_SHORT).show() 39 | } else { 40 | sendEvent(event, "标签1") 41 | } 42 | } 43 | } 44 | 45 | override fun initData() { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /channel/src/main/java/com/drake/channel/ChannelScope.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel 18 | 19 | import androidx.lifecycle.Lifecycle 20 | import androidx.lifecycle.LifecycleEventObserver 21 | import androidx.lifecycle.LifecycleOwner 22 | import kotlinx.coroutines.CoroutineScope 23 | import kotlinx.coroutines.Dispatchers 24 | import kotlinx.coroutines.SupervisorJob 25 | import kotlinx.coroutines.cancel 26 | import kotlin.coroutines.CoroutineContext 27 | 28 | /** 29 | * 异步协程作用域 30 | */ 31 | @PublishedApi 32 | internal open class ChannelScope() : CoroutineScope { 33 | 34 | override val coroutineContext: CoroutineContext = Dispatchers.Main.immediate + SupervisorJob() 35 | 36 | constructor( 37 | lifecycleOwner: LifecycleOwner, 38 | lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY 39 | ) : this() { 40 | lifecycleOwner.lifecycle.addObserver(object : LifecycleEventObserver { 41 | override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { 42 | if (lifeEvent == event) { 43 | cancel() 44 | } 45 | } 46 | }) 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /docs/css/extra.css: -------------------------------------------------------------------------------- 1 | @font-face{ 2 | font-family: 'Iosevka Curly'; 3 | src: local('Iosevka Curly Medium'), 4 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/iosevka-curly/iosevka-curly-medium.woff2') format('woff2'); 5 | font-display: swap; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | @font-face{ 10 | font-family: 'Iosevka Curly'; 11 | src: local('Iosevka Curly Bold'), 12 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/iosevka-curly/iosevka-curly-bold.woff2') format('woff2'); 13 | font-display: swap; 14 | font-weight: bold; 15 | font-style: normal; 16 | } 17 | @font-face{ 18 | font-family: 'HYYouYuan'; 19 | src: local('HYYouYuan-55W'), 20 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/HYYouYuan/HYYouYuan-55W.ttf') format('truetype'); 21 | font-display: swap; 22 | font-weight: normal; 23 | font-style: normal; 24 | } 25 | @font-face{ 26 | font-family: 'HYYouYuan'; 27 | src: local('HYYouYuan-75W'), 28 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/HYYouYuan/HYYouYuan-75W.ttf') format('truetype'); 29 | font-display: swap; 30 | font-weight: bold; 31 | font-style: normal; 32 | } 33 | 34 | * { 35 | -webkit-font-feature-settings: "liga" on, "calt" on; 36 | -webkit-font-smoothing: subpixel-antialiased; 37 | -moz-osx-font-smoothing: auto; 38 | text-rendering: optimizeLegibility; 39 | font-family: "Iosevka Curly", HYYouYuan !important; 40 | } 41 | 42 | code, 43 | .md-nav, 44 | .md-typeset code, 45 | .md-typeset { 46 | font-size: 14px !important; 47 | } 48 | 49 | .highlight span.filename, 50 | .md-typeset .admonition-title, 51 | .md-typeset summary { 52 | font-weight: normal; 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/drake/channel/exmple/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drake.channel.exmple 18 | 19 | import android.content.Intent 20 | import android.widget.Toast 21 | import com.drake.channel.exmple.databinding.ActivityMainBinding 22 | import com.drake.channel.receiveEvent 23 | import com.drake.channel.sendEvent 24 | import com.drake.engine.base.EngineActivity 25 | 26 | class MainActivity : EngineActivity(R.layout.activity_main) { 27 | 28 | override fun initView() { 29 | // 接收事件 30 | receiveEvent { 31 | Toast.makeText(this@MainActivity, "接收到事件: $it", Toast.LENGTH_SHORT).show() 32 | binding.tvEvent.text = it 33 | } 34 | // 接收标签事件 35 | receiveEvent("标签1", "标签2") { 36 | Toast.makeText(this@MainActivity, "接收标签事件: $it", Toast.LENGTH_SHORT).show() 37 | binding.tvEvent2.text = it 38 | } 39 | binding.btnOpenAct.setOnClickListener { 40 | startActivity(Intent(this@MainActivity, TestActivity::class.java)) 41 | } 42 | binding.btnSendToCurrent.setOnClickListener { 43 | sendEvent("发送事件给当前页面") 44 | } 45 | } 46 | 47 | override fun initData() { 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /docs/api/scripts/clipboard.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', () => { 2 | document.querySelectorAll('span.copy-icon').forEach(element => { 3 | element.addEventListener('click', (el) => copyElementsContentToClipboard(element)); 4 | }) 5 | 6 | document.querySelectorAll('span.anchor-icon').forEach(element => { 7 | element.addEventListener('click', (el) => { 8 | if(element.hasAttribute('pointing-to')){ 9 | const location = hrefWithoutCurrentlyUsedAnchor() + '#' + element.getAttribute('pointing-to') 10 | copyTextToClipboard(element, location) 11 | } 12 | }); 13 | }) 14 | }) 15 | 16 | const copyElementsContentToClipboard = (element) => { 17 | const selection = window.getSelection(); 18 | const range = document.createRange(); 19 | range.selectNodeContents(element.parentNode.parentNode); 20 | selection.removeAllRanges(); 21 | selection.addRange(range); 22 | 23 | copyAndShowPopup(element, () => selection.removeAllRanges()) 24 | } 25 | 26 | const copyTextToClipboard = (element, text) => { 27 | var textarea = document.createElement("textarea"); 28 | textarea.textContent = text; 29 | textarea.style.position = "fixed"; 30 | document.body.appendChild(textarea); 31 | textarea.select(); 32 | 33 | copyAndShowPopup(element, () => document.body.removeChild(textarea)) 34 | } 35 | 36 | const copyAndShowPopup = (element, after) => { 37 | try { 38 | document.execCommand('copy'); 39 | element.nextElementSibling.classList.add('active-popup'); 40 | setTimeout(() => { 41 | element.nextElementSibling.classList.remove('active-popup'); 42 | }, 1200); 43 | } catch (e) { 44 | console.error('Failed to write to clipboard:', e) 45 | } 46 | finally { 47 | if(after) after() 48 | } 49 | } 50 | 51 | const hrefWithoutCurrentlyUsedAnchor = () => window.location.href.split('#')[0] 52 | 53 | -------------------------------------------------------------------------------- /channel/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | apply plugin: 'com.android.library' 17 | apply plugin: 'kotlin-android' 18 | apply plugin: 'org.jetbrains.dokka' 19 | 20 | android { 21 | compileSdkVersion 30 22 | 23 | defaultConfig { 24 | minSdkVersion 19 25 | targetSdkVersion 30 26 | versionCode 1 27 | versionName "1.0" 28 | 29 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 30 | consumerProguardFiles 'consumer-rules.pro' 31 | } 32 | 33 | buildTypes { 34 | release { 35 | minifyEnabled false 36 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 37 | } 38 | } 39 | 40 | dokkaHtml { 41 | outputDirectory.set(file("$rootDir/docs/api")) 42 | suppressInheritedMembers.set(true) 43 | moduleName.set("Channel") 44 | } 45 | compileOptions { 46 | sourceCompatibility JavaVersion.VERSION_1_8 47 | targetCompatibility JavaVersion.VERSION_1_8 48 | } 49 | 50 | } 51 | 52 | dependencies { 53 | implementation fileTree(dir: 'libs', include: ['*.jar']) 54 | implementation 'androidx.appcompat:appcompat:1.3.0' 55 | 56 | compileOnly "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version" 57 | compileOnly "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version" 58 | } 59 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Channel 2 | site_description: Channel document 3 | repo_url: https://github.com/liangjingkanji/Channel 4 | extra: 5 | social: 6 | - icon: fontawesome/brands/github 7 | link: https://github.com/liangjingkanji 8 | - icon: fontawesome/brands/qq 9 | link: https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/img/group-qrcode.png 10 | 11 | site_author: 劉強東 12 | copyright: Copyright © 2018 - 2023 劉強東 13 | repo_name: GitHub 14 | docs_dir: 'docs' 15 | extra_css: 16 | - css/extra.css 17 | theme: 18 | name: material 19 | custom_dir: docs/material 20 | favicon: img/book-open.svg 21 | logo: img/book-open.svg 22 | palette: 23 | - media: "(prefers-color-scheme: light)" 24 | scheme: default 25 | primary: white 26 | font: false 27 | language: zh 28 | features: 29 | - navigation.top 30 | - navigation.prune 31 | - navigation.footer 32 | - navigation.instant 33 | - search.highlight 34 | - search.suggest 35 | - search.share 36 | - content.code.copy 37 | - content.code.annotate 38 | plugins: 39 | - offline 40 | - search: 41 | separator: '[\s\-,:!=\[\]()"/]+|(?!\b)(?=[A-Z][a-z])|\.(?!\d)|&[lg]t;' 42 | lang: 43 | - en 44 | - zh 45 | markdown_extensions: 46 | - toc: 47 | permalink: true 48 | - pymdownx.tasklist: 49 | custom_checkbox: true 50 | - pymdownx.tabbed: 51 | alternate_style: true 52 | - pymdownx.highlight: 53 | anchor_linenums: true 54 | line_spans: __span 55 | pygments_lang_class: true 56 | - pymdownx.inlinehilite 57 | - pymdownx.snippets 58 | - pymdownx.superfences 59 | - attr_list 60 | - def_list 61 | - md_in_html 62 | - admonition 63 | - pymdownx.highlight 64 | - pymdownx.details 65 | - pymdownx.caret 66 | - pymdownx.keys 67 | - pymdownx.mark 68 | - pymdownx.tilde 69 | - pymdownx.emoji: 70 | emoji_index: !!python/name:materialx.emoji.twemoji 71 | emoji_generator: !!python/name:materialx.emoji.to_svg 72 | 73 | nav: 74 | - 使用: index.md 75 | - 生命周期: lifecycle.md 76 | - 前台更新: live.md 77 | - 切换线程: thread.md 78 | - 1.x文档: api/index.html -------------------------------------------------------------------------------- /docs/api/-channel/package-list: -------------------------------------------------------------------------------- 1 | $dokka.format:html-v1 2 | $dokka.linkExtension:html 3 | $dokka.location:com.drake.channel////PointingToDeclaration/-channel/com.drake.channel/index.html 4 | $dokka.location:com.drake.channel//receiveEvent/androidx.lifecycle.LifecycleOwner#kotlin.Array[kotlin.String?]#androidx.lifecycle.Lifecycle.Event#kotlin.coroutines.SuspendFunction2[kotlinx.coroutines.CoroutineScope,TypeParam(bounds=[kotlin.Any?]),kotlin.Unit]/PointingToDeclaration/-channel/com.drake.channel/receive-event.html 5 | $dokka.location:com.drake.channel//receiveEventHandler/#kotlin.Array[kotlin.String?]#kotlin.coroutines.SuspendFunction2[kotlinx.coroutines.CoroutineScope,TypeParam(bounds=[kotlin.Any?]),kotlin.Unit]/PointingToDeclaration/-channel/com.drake.channel/receive-event-handler.html 6 | $dokka.location:com.drake.channel//receiveEventLive/androidx.lifecycle.LifecycleOwner#kotlin.Array[kotlin.String?]#androidx.lifecycle.Lifecycle.Event#kotlin.coroutines.SuspendFunction2[kotlinx.coroutines.CoroutineScope,TypeParam(bounds=[kotlin.Any?]),kotlin.Unit]/PointingToDeclaration/-channel/com.drake.channel/receive-event-live.html 7 | $dokka.location:com.drake.channel//receiveTag/androidx.lifecycle.LifecycleOwner#kotlin.Array[kotlin.String?]#androidx.lifecycle.Lifecycle.Event#kotlin.coroutines.SuspendFunction2[kotlinx.coroutines.CoroutineScope,kotlin.String,kotlin.Unit]/PointingToDeclaration/-channel/com.drake.channel/receive-tag.html 8 | $dokka.location:com.drake.channel//receiveTagHandler/#kotlin.Array[kotlin.String?]#kotlin.coroutines.SuspendFunction2[kotlinx.coroutines.CoroutineScope,kotlin.String,kotlin.Unit]/PointingToDeclaration/-channel/com.drake.channel/receive-tag-handler.html 9 | $dokka.location:com.drake.channel//receiveTagLive/androidx.lifecycle.LifecycleOwner#kotlin.Array[kotlin.String?]#androidx.lifecycle.Lifecycle.Event#kotlin.coroutines.SuspendFunction2[kotlinx.coroutines.CoroutineScope,kotlin.String,kotlin.Unit]/PointingToDeclaration/-channel/com.drake.channel/receive-tag-live.html 10 | $dokka.location:com.drake.channel//sendEvent/#kotlin.Any#kotlin.String?/PointingToDeclaration/-channel/com.drake.channel/send-event.html 11 | $dokka.location:com.drake.channel//sendTag/#kotlin.String?/PointingToDeclaration/-channel/com.drake.channel/send-tag.html 12 | com.drake.channel 13 | 14 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Drake, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'com.android.application' 18 | apply plugin: 'kotlin-android' 19 | apply plugin: 'kotlin-kapt' 20 | 21 | android { 22 | compileSdkVersion 33 23 | defaultConfig { 24 | applicationId "com.drake.channel.exmple" 25 | minSdkVersion 19 26 | targetSdkVersion 33 27 | versionCode 1 28 | versionName "1.0" 29 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 30 | } 31 | buildTypes { 32 | release { 33 | minifyEnabled false 34 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 35 | } 36 | } 37 | compileOptions { 38 | sourceCompatibility "1.8" 39 | targetCompatibility "1.8" 40 | } 41 | buildFeatures.dataBinding = true 42 | } 43 | 44 | dependencies { 45 | implementation fileTree(dir: 'libs', include: ['*.jar']) 46 | implementation 'androidx.appcompat:appcompat:1.6.1' 47 | implementation 'androidx.core:core-ktx:1.10.1' 48 | implementation 'com.google.android.material:material:1.9.0' 49 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 50 | testImplementation 'junit:junit:4.13.2' 51 | androidTestImplementation 'androidx.test.ext:junit:1.1.2' 52 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 53 | 54 | implementation 'com.github.liangjingkanji:debugkit:1.3.0' 55 | implementation 'com.github.liangjingkanji:Engine:0.0.74' 56 | 57 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version" 58 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version" 59 | implementation project(path: ':channel') 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_test.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | 26 | 27 | 36 | 37 | 28 |
29 |

Functions

30 |
31 |
32 |
33 |
receiveEvent 34 |
Link copied to clipboard
35 |
36 |
37 |
38 | 39 |
40 |
inline fun <T> LifecycleOwner.receiveEvent(vararg tags: String? = emptyArray(), lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY, noinline block: suspend CoroutineScope.(T) -> Unit): Job
41 |
42 |
接收事件
43 |
44 |
45 |
46 |
47 | 48 |
49 |
50 |
receiveEventHandler 51 |
Link copied to clipboard
52 |
53 |
54 |
55 | 56 |
57 |
inline fun <T> receiveEventHandler(vararg tags: String? = arrayOf(), noinline block: suspend CoroutineScope.(T) -> Unit): Job
58 |
59 |
接收事件, 此事件要求执行kotlinx.coroutines.cancel手动注销
60 |
61 |
62 |
63 |
64 | 65 |
66 |
67 |
receiveEventLive 68 |
Link copied to clipboard
69 |
70 |
71 |
72 | 73 |
74 |
inline fun <T> LifecycleOwner.receiveEventLive(vararg tags: String? = arrayOf(), lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY, noinline block: suspend CoroutineScope.(T) -> Unit): Job
75 |
76 |
使用LiveData将消息延迟到前台接收
77 |
78 |
79 |
80 |
81 | 82 |
83 |
84 |
receiveTag 85 |
Link copied to clipboard
86 |
87 |
88 |
89 | 90 |
91 |
fun LifecycleOwner.receiveTag(vararg tags: String?, lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY, block: suspend CoroutineScope.(tag: String) -> Unit): Job
92 |
93 |
接收标签, 和receiveEvent不同之处在于该函数仅支持标签, 不支持事件+标签
94 |
95 |
96 |
97 |
98 | 99 |
100 |
101 |
receiveTagHandler 102 |
Link copied to clipboard
103 |
104 |
105 |
106 | 107 |
108 |
fun receiveTagHandler(vararg tags: String?, block: suspend CoroutineScope.(tag: String) -> Unit): Job
109 |
110 |
接收标签, 和receiveEvent不同之处在于该函数仅支持标签, 不支持事件+标签, 此事件要求执行kotlinx.coroutines.cancel手动注销
111 |
112 |
113 |
114 |
115 | 116 |
117 |
118 |
receiveTagLive 119 |
Link copied to clipboard
120 |
121 |
122 |
123 | 124 |
125 |
fun LifecycleOwner.receiveTagLive(vararg tags: String?, lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY, block: suspend CoroutineScope.(tag: String) -> Unit): Job
126 |
127 |
使用LiveData将消息延迟到前台接收
128 |
129 |
130 |
131 |
132 | 133 |
134 |
135 |
sendEvent 136 |
Link copied to clipboard
137 |
138 |
139 |
140 | 141 |
142 |
fun sendEvent(event: Any, tag: String? = null): Job
143 |
144 |
发送事件
145 |
146 |
147 |
148 |
149 | 150 |
151 |
152 |
sendTag 153 |
Link copied to clipboard
154 |
155 |
156 |
157 | 158 |
159 |
fun sendTag(tag: String?): Job
160 |
161 |
发送标签
162 |
163 |
164 |
165 |
166 |
167 |
168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /docs/api/styles/style.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); 2 | @import url('https://rsms.me/inter/inter.css'); 3 | @import url('jetbrains-mono.css'); 4 | 5 | :root { 6 | --breadcrumb-font-color: #637282; 7 | --hover-link-color: #5B5DEF; 8 | --average-color: #637282; 9 | --footer-height: 64px; 10 | --footer-padding-top: 48px; 11 | --horizontal-spacing-for-content: 42px; 12 | --mobile-horizontal-spacing-for-content: 8px; 13 | --bottom-spacing: 16px; 14 | --color-scrollbar: rgba(39, 40, 44, 0.40); 15 | --color-scrollbar-track: #f4f4f4; 16 | } 17 | 18 | html { 19 | height: 100%; 20 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 21 | scrollbar-color: rgba(39, 40, 44, 0.40) #F4F4F4; 22 | scrollbar-color: var(--color-scrollbar) var(--color-scrollbar-track); 23 | } 24 | 25 | html ::-webkit-scrollbar { 26 | width: 8px; 27 | height: 8px; 28 | } 29 | 30 | html ::-webkit-scrollbar-track { 31 | background-color: var(--color-scrollbar-track); 32 | } 33 | 34 | html ::-webkit-scrollbar-thumb { 35 | width: 8px; 36 | border-radius: 6px; 37 | background: rgba(39, 40, 44, 0.40); 38 | background: var(--color-scrollbar); 39 | } 40 | 41 | 42 | .main-content { 43 | padding-bottom: var(--bottom-spacing); 44 | z-index: 0; 45 | } 46 | 47 | .main-content>* { 48 | margin-left: var(--horizontal-spacing-for-content); 49 | margin-right: var(--horizontal-spacing-for-content); 50 | } 51 | 52 | .navigation-wrapper { 53 | display: flex; 54 | padding: 24px 0; 55 | flex-wrap: wrap; 56 | position: sticky; 57 | top: 0; 58 | background-color: #f4f4f4; 59 | padding-top: 19px; 60 | padding-bottom: 18px; 61 | z-index: 8; 62 | 63 | /* Reset margin and use padding for border */ 64 | margin-left: 0; 65 | margin-right: 0; 66 | padding-left: var(--horizontal-spacing-for-content); 67 | padding-right: var(--horizontal-spacing-for-content); 68 | } 69 | 70 | .navigation-wrapper.sticky-navigation { 71 | border-bottom: 1px solid #DADFE6; 72 | } 73 | 74 | .breadcrumbs { 75 | color: var(--breadcrumb-font-color); 76 | overflow-wrap: break-word; 77 | } 78 | 79 | .breadcrumbs a { 80 | color: var(--breadcrumb-font-color) 81 | } 82 | 83 | .breadcrumbs a:hover { 84 | color: var(--hover-link-color) 85 | } 86 | 87 | .tabs-section > .section-tab:first-child { 88 | margin-left: 0; 89 | } 90 | 91 | .section-tab { 92 | border: 0; 93 | cursor: pointer; 94 | background-color: transparent; 95 | border-bottom: 1px solid #DADFE6; 96 | padding: 11px 3px; 97 | font-size: 12px; 98 | color: var(--average-color); 99 | outline: none; 100 | margin: 0 8px; 101 | font-family: "Iosevka", "HYZhengYuan"; 102 | } 103 | 104 | .breadcrumbs { 105 | font-family: "Iosevka", "HYZhengYuan"; 106 | } 107 | 108 | .section-tab:hover { 109 | color: #282E34; 110 | border-bottom: 2px solid var(--hover-link-color); 111 | } 112 | 113 | .section-tab[data-active=''] { 114 | color: #282E34; 115 | border-bottom: 2px solid var(--hover-link-color); 116 | } 117 | 118 | .tabs-section-body { 119 | background-color: white; 120 | } 121 | 122 | .tabs-section-body > div { 123 | margin-top: 12px; 124 | } 125 | 126 | .tabs-section-body .with-platform-tabs > div { 127 | margin: 0 12px; 128 | } 129 | 130 | .tabs-section-body .table .with-platform-tabs > div { 131 | margin: 0; 132 | } 133 | 134 | .tabs-section-body .with-platform-tabs { 135 | padding-top: 12px; 136 | padding-bottom: 12px; 137 | } 138 | 139 | .tabs-section-body .with-platform-tabs .sourceset-depenent-content .table-row { 140 | background-color: #f4f4f4; 141 | border-bottom: 2px solid white; 142 | } 143 | 144 | .cover > .platform-hinted { 145 | padding-top: 12px; 146 | margin-top: 12px; 147 | padding-bottom: 12px; 148 | } 149 | 150 | .cover { 151 | display: flex; 152 | flex-direction: column; 153 | } 154 | 155 | .cover .platform-hinted .sourceset-depenent-content > .symbol, 156 | .cover > .symbol { 157 | background-color: white; 158 | } 159 | 160 | .cover .platform-hinted.with-platform-tabs .sourceset-depenent-content > .symbol { 161 | background-color: #f4f4f4; 162 | } 163 | 164 | .cover .platform-hinted.with-platform-tabs .sourceset-depenent-content > .block ~ .symbol { 165 | padding-top: 16px; 166 | padding-left: 0; 167 | } 168 | 169 | .cover .sourceset-depenent-content > .block { 170 | padding: 16px 0; 171 | font-size: 18px; 172 | line-height: 28px; 173 | } 174 | 175 | .cover .platform-hinted.with-platform-tabs .sourceset-depenent-content > .block { 176 | padding: 0; 177 | font-size: 14px; 178 | } 179 | 180 | .cover ~ .divergent-group { 181 | margin-top: 24px; 182 | padding: 24px 8px 8px 8px; 183 | } 184 | 185 | .cover ~ .divergent-group .main-subrow .symbol { 186 | width: 100%; 187 | } 188 | 189 | .cover p.paragraph { 190 | margin-top: 4px; 191 | } 192 | 193 | .divergent-group { 194 | background-color: white; 195 | padding: 8px 0px 8px 0; 196 | margin-bottom: 2px; 197 | } 198 | 199 | .divergent-group .table-row { 200 | background-color: #F4F4F4; 201 | border-bottom: 2px solid white; 202 | } 203 | 204 | .title > .divergent-group:first-of-type { 205 | padding-top: 0; 206 | } 207 | 208 | #container { 209 | display: flex; 210 | flex-direction: row; 211 | min-height: 100%; 212 | height: 100%; 213 | } 214 | 215 | #main { 216 | width: 100%; 217 | max-width: calc(100% - 280px); 218 | display: flex; 219 | flex-direction: column; 220 | height: auto; 221 | overflow: auto; 222 | } 223 | 224 | #leftColumn { 225 | width: 280px; 226 | border-right: 1px solid #DADFE6; 227 | display: flex; 228 | flex-direction: column; 229 | } 230 | 231 | #sideMenu { 232 | padding-top: 16px; 233 | position: relative; 234 | max-height: calc(100% - 140px); 235 | height: 100%; 236 | overflow-y: auto; 237 | } 238 | 239 | #sideMenu img { 240 | margin: 1em 0.25em; 241 | } 242 | 243 | #sideMenu hr { 244 | background: #DADFE6; 245 | } 246 | 247 | #logo { 248 | background-size: 125px 26px; 249 | border-bottom: 1px solid #DADFE6; 250 | background-repeat: no-repeat; 251 | background-origin: content-box; 252 | padding-left: 24px; 253 | padding-top: 24px; 254 | height: 48px; 255 | cursor: pointer; 256 | } 257 | 258 | .monospace, 259 | .code { 260 | font-family: monospace; 261 | } 262 | 263 | .sample-container, div.CodeMirror { 264 | display: flex; 265 | flex-direction: column; 266 | } 267 | 268 | code.paragraph { 269 | display: block; 270 | } 271 | 272 | .overview > .navButton { 273 | align-items: center; 274 | display: flex; 275 | justify-content: flex-end; 276 | padding: 10px; 277 | margin-right: 14px; 278 | cursor: pointer; 279 | } 280 | 281 | .strikethrough { 282 | text-decoration: line-through; 283 | } 284 | 285 | .symbol:empty { 286 | padding: 0; 287 | } 288 | 289 | .symbol { 290 | background-color: #F4F4F4; 291 | align-items: center; 292 | display: block; 293 | padding: 8px 32px 8px 8px; 294 | box-sizing: border-box; 295 | white-space: pre-wrap; 296 | font-weight: normal; 297 | position: relative; 298 | line-height: 24px; 299 | font-family: "Iosevka", HYZhengYuan, Bitstream Vera Sans Mono, Lucida Console, Terminal; 300 | font-size: 12px; 301 | min-height: 43px; 302 | } 303 | 304 | .symbol > a { 305 | color: var(--hover-link-color); 306 | } 307 | 308 | .copy-icon { 309 | cursor: pointer; 310 | } 311 | 312 | .symbol span.copy-icon::before { 313 | width: 24px; 314 | height: 24px; 315 | display: inline-block; 316 | content: ''; 317 | /* masks are required if you want to change color of the icon dynamically instead of using those provided with the SVG */ 318 | -webkit-mask: url("../images/copy-icon.svg") no-repeat 50% 50%; 319 | mask: url("../images/copy-icon.svg") no-repeat 50% 50%; 320 | -webkit-mask-size: cover; 321 | mask-size: cover; 322 | background-color: var(--average-color); 323 | } 324 | 325 | .symbol span.copy-icon:hover::before { 326 | background-color: black; 327 | } 328 | 329 | .copy-popup-wrapper { 330 | display: none; 331 | align-items: center; 332 | position: absolute; 333 | z-index: 1000; 334 | background: white; 335 | font-weight: normal; 336 | font-family: 'Inter', "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 337 | width: max-content; 338 | font-size: 14px; 339 | cursor: default; 340 | border: 1px solid #D8DCE1; 341 | box-sizing: border-box; 342 | box-shadow: 0px 5px 10px var(--ring-popup-shadow-color); 343 | border-radius: 3px; 344 | } 345 | 346 | .copy-popup-wrapper > .copy-popup-icon::before { 347 | content: url("../images/copy-successful-icon.svg"); 348 | padding: 8px; 349 | } 350 | 351 | .copy-popup-wrapper > .copy-popup-icon { 352 | position: relative; 353 | top: 3px; 354 | } 355 | 356 | .copy-popup-wrapper.popup-to-left { 357 | /* since it is in position absolute we can just move it to the left to make it always appear on the left side of the icon */ 358 | left: -15em; 359 | } 360 | 361 | .copy-popup-wrapper.active-popup { 362 | display: flex !important; 363 | } 364 | 365 | .copy-popup-wrapper:hover { 366 | font-weight: normal; 367 | } 368 | 369 | .copy-popup-wrapper > span:last-child { 370 | padding-right: 14px; 371 | } 372 | 373 | .symbol .top-right-position { 374 | /* it is important for a parent to have a position: relative */ 375 | position: absolute; 376 | top: 8px; 377 | right: 8px; 378 | } 379 | 380 | .sideMenuPart > .overview { 381 | display: flex; 382 | align-items: center; 383 | position: relative; 384 | user-select: none; /* there's a weird bug with text selection */ 385 | padding: 8px 0; 386 | font-family: "Iosevka", "HYZhengYuan"; 387 | } 388 | 389 | .sideMenuPart a { 390 | display: block; 391 | align-items: center; 392 | color: var(--average-color); 393 | overflow: hidden; 394 | } 395 | 396 | 397 | .sideMenuPart a:hover { 398 | text-decoration: none; 399 | color: var(--average-color); 400 | } 401 | 402 | .sideMenuPart > .overview:before { 403 | box-sizing: border-box; 404 | content: ''; 405 | top: 0; 406 | width: 280px; 407 | right: 0; 408 | bottom: 0; 409 | position: absolute; 410 | z-index: -1; 411 | } 412 | 413 | .overview:hover:before { 414 | background-color: #DADFE5; 415 | } 416 | 417 | #nav-submenu { 418 | padding-left: 24px; 419 | } 420 | 421 | .sideMenuPart { 422 | padding-left: 12px; 423 | box-sizing: border-box; 424 | } 425 | 426 | .sideMenuPart.hidden > .overview .navButtonContent::before { 427 | transform: rotate(0deg); 428 | } 429 | 430 | .sideMenuPart > .overview .navButtonContent::before { 431 | content: url("../images/arrow_down.svg"); 432 | display: flex; 433 | flex-direction: row; 434 | align-items: center; 435 | justify-content: center; 436 | transform: rotate(180deg); 437 | } 438 | 439 | .sideMenuPart.hidden > .navButton .navButtonContent::after { 440 | content: '\02192'; 441 | } 442 | 443 | .sideMenuPart.hidden > .sideMenuPart { 444 | height: 0; 445 | visibility: hidden; 446 | } 447 | 448 | .filtered > a, .filtered > .navButton { 449 | display: none; 450 | } 451 | 452 | body, table { 453 | font-family: "Iosevka", "HYZhengYuan", "Helvetica Neue", Helvetica, Arial, sans-serif; 454 | background: #F4F4F4; 455 | font-style: normal; 456 | font-weight: normal; 457 | font-size: 12px; 458 | line-height: 24px; 459 | margin: 0; 460 | } 461 | 462 | table { 463 | width: 100%; 464 | border-collapse: collapse; 465 | background-color: #ffffff; 466 | padding: 5px; 467 | } 468 | 469 | tbody > tr { 470 | border-bottom: 2px solid #F4F4F4; 471 | min-height: 56px; 472 | } 473 | 474 | td:first-child { 475 | width: 20vw; 476 | } 477 | 478 | .keyword { 479 | color: black; 480 | font-family: "Iosevka", Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; 481 | font-size: 12px; 482 | } 483 | 484 | .identifier { 485 | color: darkblue; 486 | font-size: 12px; 487 | font-family: "Iosevka", Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; 488 | } 489 | 490 | .brief { 491 | white-space: pre-wrap; 492 | overflow: hidden; 493 | } 494 | 495 | h1, h2, h3, h4, h5, h6 { 496 | color: #222; 497 | font-weight: bold; 498 | } 499 | 500 | p, ul, ol, table, pre, dl { 501 | margin: 0; 502 | } 503 | 504 | h1 { 505 | font-weight: bold; 506 | font-size: 40px; 507 | line-height: 48px; 508 | letter-spacing: -1px; 509 | } 510 | 511 | 512 | h1.cover { 513 | font-size: 32px; 514 | line-height: 64px; 515 | letter-spacing: -1.5px; 516 | 517 | border-bottom: 1px solid #DADFE6; 518 | 519 | margin-bottom: 0; 520 | padding-bottom: 32px; 521 | display: block; 522 | } 523 | 524 | h2 { 525 | color: #393939; 526 | font-size: 20px; 527 | line-height: 40px; 528 | letter-spacing: -0.5px; 529 | } 530 | 531 | h3 { 532 | font-size: 20px; 533 | line-height: 28px; 534 | letter-spacing: -0.2px; 535 | } 536 | 537 | h4 { 538 | margin: 0; 539 | } 540 | 541 | h3, h4, h5, h6 { 542 | color: #494949; 543 | } 544 | 545 | .UnderCoverText { 546 | font-size: 16px; 547 | line-height: 28px; 548 | } 549 | 550 | .UnderCoverText code { 551 | font-size: inherit; 552 | } 553 | 554 | .UnderCoverText table { 555 | margin: 8px 0 8px 0; 556 | word-break: break-word; 557 | } 558 | 559 | 560 | a { 561 | color: #5B5DEF; 562 | font-weight: 400; 563 | text-decoration: none; 564 | } 565 | 566 | a:hover { 567 | color: #5B5DEF; 568 | text-decoration: underline; 569 | } 570 | 571 | a small { 572 | font-size: 11px; 573 | color: #555; 574 | margin-top: -0.6em; 575 | display: block; 576 | } 577 | 578 | .wrapper { 579 | width: 860px; 580 | margin: 0 auto; 581 | } 582 | 583 | blockquote { 584 | border-left: 1px solid #e5e5e5; 585 | margin: 0; 586 | padding: 0 0 0 20px; 587 | font-style: italic; 588 | } 589 | 590 | code, pre { 591 | color: #333; 592 | font-size: 14px; 593 | } 594 | 595 | pre { 596 | display: block; 597 | overflow-x: auto; 598 | } 599 | 600 | th, td { 601 | text-align: left; 602 | vertical-align: top; 603 | padding: 5px 10px; 604 | } 605 | 606 | dt { 607 | color: #444; 608 | font-weight: 700; 609 | } 610 | 611 | th { 612 | color: #444; 613 | } 614 | 615 | p.paragraph img { 616 | display: block; 617 | } 618 | 619 | img { 620 | max-width: 100%; 621 | } 622 | 623 | header { 624 | width: 270px; 625 | float: left; 626 | position: fixed; 627 | } 628 | 629 | header ul { 630 | list-style: none; 631 | height: 40px; 632 | 633 | padding: 0; 634 | 635 | background: #eee; 636 | background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); 637 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); 638 | background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); 639 | background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); 640 | background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); 641 | background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); 642 | 643 | border-radius: 5px; 644 | border: 1px solid #d2d2d2; 645 | box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; 646 | width: 270px; 647 | } 648 | 649 | header li { 650 | width: 89px; 651 | float: left; 652 | border-right: 1px solid #d2d2d2; 653 | height: 40px; 654 | } 655 | 656 | header ul a { 657 | line-height: 1; 658 | font-size: 11px; 659 | color: #999; 660 | display: block; 661 | text-align: center; 662 | padding-top: 6px; 663 | height: 40px; 664 | } 665 | 666 | strong { 667 | color: #222; 668 | font-weight: 700; 669 | } 670 | 671 | header ul li + li { 672 | width: 88px; 673 | border-left: 1px solid #fff; 674 | } 675 | 676 | header ul li + li + li { 677 | border-right: none; 678 | width: 89px; 679 | } 680 | 681 | header ul a strong { 682 | font-size: 14px; 683 | display: block; 684 | color: #222; 685 | } 686 | 687 | section { 688 | width: 500px; 689 | float: right; 690 | padding-bottom: 50px; 691 | } 692 | 693 | small { 694 | font-size: 11px; 695 | } 696 | 697 | hr { 698 | border: 0; 699 | background: #e5e5e5; 700 | height: 1px; 701 | margin: 0 0 20px; 702 | } 703 | 704 | footer { 705 | width: 270px; 706 | float: left; 707 | position: fixed; 708 | bottom: 50px; 709 | } 710 | 711 | .platform-tag { 712 | display: flex; 713 | flex-direction: row; 714 | padding: 4px 8px; 715 | height: 24px; 716 | border-radius: 100px; 717 | box-sizing: border-box; 718 | border: 1px solid transparent; 719 | margin: 2px; 720 | font-family: Inter, Arial, sans-serif; 721 | font-size: 12px; 722 | font-weight: 400; 723 | font-style: normal; 724 | font-stretch: normal; 725 | line-height: normal; 726 | letter-spacing: normal; 727 | text-align: center; 728 | outline: none; 729 | color: #fff 730 | } 731 | 732 | .platform-tags { 733 | display: flex; 734 | flex-wrap: wrap; 735 | padding-bottom: 8px; 736 | } 737 | 738 | .platform-tags > .platform-tag { 739 | align-self: center; 740 | } 741 | 742 | .platform-tags > .platform-tag:first-of-type { 743 | margin-left: auto; 744 | } 745 | 746 | .platform-tag.jvm-like { 747 | background-color: #4DBB5F; 748 | color: white; 749 | } 750 | 751 | .platform-tag.js-like { 752 | background-color: #FED236; 753 | color: white; 754 | } 755 | 756 | .platform-tag.native-like { 757 | background-color: #CD74F6; 758 | color: white; 759 | } 760 | 761 | .platform-tag.common-like { 762 | background-color: #A6AFBA; 763 | color: white; 764 | } 765 | 766 | .filter-section { 767 | display: flex; 768 | flex-direction: row; 769 | align-self: flex-end; 770 | min-height: 30px; 771 | z-index: 0; 772 | } 773 | 774 | .platform-selector:hover { 775 | border: 1px solid #A6AFBA !important; 776 | } 777 | 778 | [data-filterable-current=''] { 779 | display: none !important; 780 | } 781 | 782 | .platform-selector:not([data-active]) { 783 | border: 1px solid #DADFE6; 784 | background-color: transparent; 785 | color: var(--average-color); 786 | } 787 | 788 | td.content { 789 | padding-left: 24px; 790 | padding-top: 16px; 791 | display: flex; 792 | flex-direction: column; 793 | } 794 | 795 | .main-subrow { 796 | display: flex; 797 | flex-direction: row; 798 | padding: 0; 799 | flex-wrap: wrap; 800 | } 801 | 802 | .main-subrow > div > span { 803 | display: flex; 804 | position: relative; 805 | } 806 | 807 | .main-subrow > div > span > a, 808 | .main-subrow > div > span > span[data-unresolved-link] { 809 | text-decoration: none; 810 | font-style: normal; 811 | font-weight: 600; 812 | font-size: 12px; 813 | color: #282E34; 814 | } 815 | 816 | .main-subrow > div > span > a:hover { 817 | color: var(--hover-link-color); 818 | } 819 | 820 | .main-subrow:hover .anchor-icon { 821 | opacity: 1; 822 | transition: 0.2s; 823 | } 824 | 825 | .main-subrow .anchor-icon { 826 | padding: 0 8px; 827 | opacity: 0; 828 | transition: 0.2s 0.5s; 829 | } 830 | 831 | .main-subrow .anchor-icon::before { 832 | content: url("../images/anchor-copy-button.svg"); 833 | } 834 | 835 | .main-subrow .anchor-icon:hover { 836 | cursor: pointer; 837 | } 838 | 839 | .main-subrow .anchor-icon:hover > svg path { 840 | fill: var(--hover-link-color); 841 | } 842 | 843 | .main-subrow .anchor-wrapper { 844 | position: relative; 845 | } 846 | 847 | .inline-flex { 848 | display: inline-flex; 849 | } 850 | 851 | .platform-hinted { 852 | flex: auto; 853 | display: block; 854 | margin-bottom: 5px; 855 | } 856 | 857 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark { 858 | min-width: 64px; 859 | height: 36px; 860 | border: 2px solid white; 861 | background: white; 862 | outline: none; 863 | flex: none; 864 | order: 5; 865 | align-self: flex-start; 866 | margin: 0; 867 | } 868 | 869 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark.jvm-like:hover { 870 | border-top: 2px solid rgba(77, 187, 95, 0.3); 871 | } 872 | 873 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark.js-like:hover { 874 | border-top: 2px solid rgba(254, 175, 54, 0.3); 875 | } 876 | 877 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark.native-like:hover { 878 | border-top: 2px solid rgba(105, 118, 249, 0.3); 879 | } 880 | 881 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark.common-like:hover { 882 | border-top: 2px solid rgba(161, 170, 180, 0.3); 883 | } 884 | 885 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark.jvm-like[data-active=''] { 886 | border: 2px solid #F4F4F4; 887 | border-top: 2px solid #4DBB5F; 888 | 889 | background: #F4F4F4; 890 | } 891 | 892 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark.js-like[data-active=''] { 893 | border: 2px solid #F4F4F4; 894 | border-top: 2px solid #FED236; 895 | 896 | background: #F4F4F4; 897 | } 898 | 899 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark.native-like[data-active=''] { 900 | border: 2px solid #F4F4F4; 901 | border-top: 2px solid #CD74F6; 902 | 903 | background: #F4F4F4; 904 | } 905 | 906 | .platform-hinted > .platform-bookmarks-row > .platform-bookmark.common-like[data-active=''] { 907 | border: 2px solid #F4F4F4; 908 | border-top: 2px solid #A6AFBA; 909 | 910 | background: #F4F4F4; 911 | } 912 | 913 | .platform-hinted > .content:not([data-active]), 914 | .tabs-section-body > *:not([data-active]) { 915 | display: none; 916 | } 917 | 918 | /*Work around an issue: https://github.com/JetBrains/kotlin-playground/issues/91*/ 919 | .platform-hinted[data-togglable="Samples"] > .content:not([data-active]), 920 | .tabs-section-body > *[data-togglable="Samples"]:not([data-active]) { 921 | display: block !important; 922 | visibility: hidden; 923 | height: 0; 924 | position: fixed; 925 | top: 0; 926 | } 927 | 928 | .with-platform-tags { 929 | display: flex; 930 | } 931 | 932 | .with-platform-tags ~ .main-subrow { 933 | padding-top: 8px; 934 | } 935 | 936 | .cover .with-platform-tabs { 937 | background-color: white; 938 | font-size: 14px; 939 | } 940 | 941 | .cover > .with-platform-tabs .platform-bookmarks-row { 942 | margin: 0 16px; 943 | } 944 | 945 | .cover > .with-platform-tabs > .content { 946 | margin: 0 16px; 947 | background-color: #f4f4f4; 948 | padding: 8px 16px; 949 | } 950 | 951 | .cover > .block { 952 | padding-top: 48px; 953 | padding-bottom: 24px; 954 | font-size: 18px; 955 | line-height: 28px; 956 | } 957 | 958 | .cover > .block:empty { 959 | padding-bottom: 0; 960 | } 961 | 962 | .table-row .with-platform-tabs .sourceset-depenent-content .brief { 963 | padding: 8px; 964 | background-color: #f4f4f4; 965 | } 966 | 967 | .sideMenuPart[data-active] > .overview:before { 968 | border-left: 4px solid var(--hover-link-color); 969 | background: rgba(91, 93, 239, 0.15); 970 | } 971 | 972 | .table { 973 | display: flex; 974 | flex-direction: column; 975 | } 976 | 977 | .table-row { 978 | display: flex; 979 | flex-direction: column; 980 | background: white; 981 | border-bottom: 2px solid #f4f4f4; 982 | padding: 16px 24px 16px 24px; 983 | } 984 | 985 | .table-row .brief-comment { 986 | color: var(--average-color); 987 | } 988 | 989 | .platform-dependent-row { 990 | display: grid; 991 | padding-top: 8px; 992 | } 993 | 994 | .title-row { 995 | display: grid; 996 | grid-template-columns: auto auto 7em; 997 | width: 100%; 998 | } 999 | 1000 | .keyValue { 1001 | display: grid; 1002 | } 1003 | 1004 | @media print, screen and (min-width: 960px) { 1005 | .keyValue { 1006 | grid-template-columns: 20% 80%; 1007 | } 1008 | 1009 | .title-row { 1010 | grid-template-columns: 20% auto 7em; 1011 | } 1012 | } 1013 | 1014 | @media print, screen and (max-width: 960px) { 1015 | 1016 | div.wrapper { 1017 | width: auto; 1018 | margin: 0; 1019 | } 1020 | 1021 | header, section, footer { 1022 | float: none; 1023 | position: static; 1024 | width: auto; 1025 | } 1026 | 1027 | header { 1028 | padding-right: 320px; 1029 | } 1030 | 1031 | section { 1032 | border: 1px solid #e5e5e5; 1033 | border-width: 1px 0; 1034 | padding: 20px 0; 1035 | margin: 0 0 20px; 1036 | } 1037 | 1038 | header a small { 1039 | display: inline; 1040 | } 1041 | 1042 | header ul { 1043 | position: absolute; 1044 | right: 50px; 1045 | top: 52px; 1046 | } 1047 | } 1048 | 1049 | @media print, screen and (max-width: 720px) { 1050 | body { 1051 | word-wrap: break-word; 1052 | } 1053 | 1054 | header { 1055 | padding: 0; 1056 | } 1057 | 1058 | header ul, header p.view { 1059 | position: static; 1060 | } 1061 | 1062 | pre, code { 1063 | word-wrap: normal; 1064 | } 1065 | } 1066 | 1067 | @media print, screen and (max-width: 480px) { 1068 | header ul { 1069 | display: none; 1070 | } 1071 | } 1072 | 1073 | @media print { 1074 | body { 1075 | padding: 0.4in; 1076 | font-size: 12pt; 1077 | color: #444; 1078 | } 1079 | } 1080 | 1081 | .footer { 1082 | clear: both; 1083 | display: flex; 1084 | align-items: center; 1085 | position: relative; 1086 | min-height: var(--footer-height); 1087 | border-top: 1px solid #DADFE6; 1088 | font-size: 12px; 1089 | line-height: 16px; 1090 | letter-spacing: 0.2px; 1091 | color: var(--breadcrumb-font-color); 1092 | margin-top:auto; 1093 | } 1094 | 1095 | .footer span.go-to-top-icon { 1096 | border-radius: 2em; 1097 | padding: 11px 10px !important; 1098 | background-color: white; 1099 | } 1100 | 1101 | .footer span.go-to-top-icon > a::before { 1102 | content: url("../images/go-to-top-icon.svg"); 1103 | } 1104 | 1105 | .footer > span:first-child { 1106 | margin-left: var(--horizontal-spacing-for-content); 1107 | padding-left: 0; 1108 | } 1109 | 1110 | .footer > span:last-child { 1111 | margin-right: var(--horizontal-spacing-for-content); 1112 | padding-right: 0; 1113 | } 1114 | 1115 | .footer > span { 1116 | padding: 0 16px; 1117 | font-family: "Iosevka", "HYZhengYuan"; 1118 | } 1119 | 1120 | .footer a { 1121 | color: var(--breadcrumb-font-color); 1122 | } 1123 | 1124 | .footer .padded-icon { 1125 | padding-left: 0.5em; 1126 | } 1127 | 1128 | .footer .padded-icon::before { 1129 | content: url("../images/footer-go-to-link.svg"); 1130 | } 1131 | 1132 | .pull-right { 1133 | float: right; 1134 | margin-left: auto 1135 | } 1136 | 1137 | div.runnablesample { 1138 | height: fit-content; 1139 | } 1140 | 1141 | .anchor-highlight { 1142 | border: 1px solid var(--hover-link-color) !important; 1143 | box-shadow: 0 0 0 0.2em #c8e1ff; 1144 | margin-top: 0.2em; 1145 | margin-bottom: 0.2em; 1146 | } 1147 | 1148 | .w-100 { 1149 | width: 100%; 1150 | } 1151 | 1152 | .no-gutters { 1153 | margin: 0; 1154 | padding: 0; 1155 | } 1156 | 1157 | .d-flex { 1158 | display: flex; 1159 | } 1160 | 1161 | @media screen and (max-width: 1119px) { 1162 | h1.cover { 1163 | font-size: 32px; 1164 | line-height: 48px; 1165 | padding-bottom: 8px; 1166 | } 1167 | } 1168 | 1169 | @media screen and (max-width: 759px) { 1170 | #main { 1171 | max-width: 100%; 1172 | } 1173 | #leftColumn { 1174 | position: fixed; 1175 | margin-left: -280px; 1176 | transition: margin .2s ease-out; 1177 | z-index: 4; 1178 | background: white; 1179 | height: 100%; 1180 | } 1181 | #leftColumn.open { 1182 | margin-left: 0; 1183 | } 1184 | #leftColumn.open ~ #main #searchBar { 1185 | display: none; 1186 | } 1187 | #leftToggler { 1188 | display: unset; 1189 | position: fixed; 1190 | top: 50%; 1191 | transform: translateY(-50%); 1192 | z-index: 5; 1193 | font-size: 20px; 1194 | transition: margin .2s ease-out; 1195 | 1196 | color: var(--average-color); 1197 | border: 1px solid var(--average-color); 1198 | border-left: 0; 1199 | border-top-right-radius: 1em; 1200 | border-bottom-right-radius: 1em; 1201 | padding: 8px 4px 8px 8px; 1202 | background-color: white; 1203 | } 1204 | #leftToggler .icon-toggler:hover { 1205 | cursor: pointer; 1206 | } 1207 | #leftColumn.open ~ #main #leftToggler { 1208 | margin-left: 280px; 1209 | } 1210 | .icon-toggler::before { 1211 | content: "\232A"; 1212 | } 1213 | #leftColumn.open ~ #main .icon-toggler::before { 1214 | content: "\2329"; 1215 | padding-right: 0.5em; 1216 | margin-left: -0.5em; 1217 | } 1218 | .main-content > * { 1219 | margin-left: var(--mobile-horizontal-spacing-for-content); 1220 | margin-right: var(--mobile-horizontal-spacing-for-content); 1221 | } 1222 | 1223 | .navigation-wrapper { 1224 | padding-left: var(--mobile-horizontal-spacing-for-content); 1225 | padding-right: var(--mobile-horizontal-spacing-for-content); 1226 | } 1227 | 1228 | #sideMenu { 1229 | padding-bottom: 16px; 1230 | overflow: auto; 1231 | } 1232 | h1.cover { 1233 | font-size: 32px; 1234 | line-height: 32px; 1235 | } 1236 | } 1237 | --------------------------------------------------------------------------------