├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── dictionaries
│ └── Luke.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE
├── README.md
├── build.gradle
├── compiler
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── guet
│ └── flexbox
│ └── compiler
│ ├── Compiler.kt
│ ├── JsonCompiler.kt
│ ├── Main.kt
│ └── NodeFactory.kt
├── core
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── guet
│ │ └── flexbox
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ ├── com
│ │ └── guet
│ │ │ └── flexbox
│ │ │ ├── TemplateNode.kt
│ │ │ ├── build
│ │ │ ├── AbsText.kt
│ │ │ ├── Banner.kt
│ │ │ ├── BuildKit.kt
│ │ │ ├── BuildTool.kt
│ │ │ ├── CommonDefine.kt
│ │ │ ├── DataBinder.kt
│ │ │ ├── DataBinding.kt
│ │ │ ├── Definition.kt
│ │ │ ├── Empty.kt
│ │ │ ├── Flex.kt
│ │ │ ├── For.kt
│ │ │ ├── ForEach.kt
│ │ │ ├── Graphic.kt
│ │ │ ├── If.kt
│ │ │ ├── Image.kt
│ │ │ ├── RenderNodeFactory.kt
│ │ │ ├── Scroller.kt
│ │ │ ├── Text.kt
│ │ │ ├── TextInput.kt
│ │ │ ├── ToWidget.kt
│ │ │ ├── UrlType.kt
│ │ │ ├── Utils.kt
│ │ │ ├── When.kt
│ │ │ └── Widget.kt
│ │ │ ├── context
│ │ │ ├── PageTransaction.kt
│ │ │ ├── PropsContext.kt
│ │ │ └── ScopeContext.kt
│ │ │ ├── enums
│ │ │ ├── FlexAlign.kt
│ │ │ ├── FlexDirection.kt
│ │ │ ├── FlexJustify.kt
│ │ │ ├── FlexWrap.kt
│ │ │ ├── Horizontal.kt
│ │ │ ├── Orientation.kt
│ │ │ ├── ScaleType.kt
│ │ │ ├── TextStyle.kt
│ │ │ ├── Vertical.kt
│ │ │ └── Visibility.kt
│ │ │ ├── eventsystem
│ │ │ ├── ClickUrlEventReceiver.kt
│ │ │ ├── EventBus.kt
│ │ │ ├── EventDispatcher.kt
│ │ │ ├── EventHandler.kt
│ │ │ ├── EventTarget.kt
│ │ │ ├── ExternalEventReceiver.kt
│ │ │ ├── ReceiveEventToExpr.kt
│ │ │ └── event
│ │ │ │ ├── ClickEvent.kt
│ │ │ │ ├── ClickExprEvent.kt
│ │ │ │ ├── ClickUrlEvent.kt
│ │ │ │ ├── HasExprEvent.kt
│ │ │ │ ├── HttpRequestEvent.kt
│ │ │ │ ├── RefreshPageEvent.kt
│ │ │ │ ├── SendObjectsEvent.kt
│ │ │ │ ├── TemplateEvent.kt
│ │ │ │ ├── TextChangedEvent.kt
│ │ │ │ └── VisibleEvent.kt
│ │ │ ├── http
│ │ │ ├── CallbackImpl.kt
│ │ │ └── HttpRequest.kt
│ │ │ └── log
│ │ │ └── AndroidLog.kt
│ │ └── org
│ │ └── apache
│ │ └── commons
│ │ └── logging
│ │ ├── Log.java
│ │ └── LogFactory.java
│ └── test
│ └── java
│ └── com
│ └── guet
│ └── flexbox
│ └── ExampleUnitTest.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── handshake
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── kotlin
│ └── com
│ │ └── guet
│ │ └── flexbox
│ │ └── handshake
│ │ ├── AppConfiguration.kt
│ │ ├── HomepageController.kt
│ │ ├── Main.kt
│ │ ├── MockApplication.kt
│ │ ├── NetworkChangedEvent.kt
│ │ ├── NetworkWatcher.kt
│ │ ├── lan
│ │ ├── LANAddressProvider.kt
│ │ ├── MacOsLANAddressProvider.kt
│ │ └── OtherLANAddressProvider.kt
│ │ └── ui
│ │ ├── ImageView.kt
│ │ ├── QrcodeForm.kt
│ │ ├── QrcodeFormManager.kt
│ │ └── QrcodeImageUtils.kt
│ └── resources
│ ├── application.properties
│ ├── logback.xml
│ └── static
│ ├── app.css
│ ├── app.js
│ ├── background.html
│ ├── background.js
│ ├── fire.png
│ ├── format-json.js
│ ├── icon-big.png
│ ├── icon.png
│ ├── index.html
│ ├── jquery.min.js
│ ├── jquery.toast.min.js
│ ├── json.png
│ ├── prism.css
│ ├── prism.js
│ ├── qrcode.js
│ ├── qrcode_loading.jpg
│ ├── three.min.js
│ ├── toastr.min.css
│ └── toastr.min.js
├── intellij-plugin
├── .gitignore
├── .idea
│ ├── .gitignore
│ ├── codeStyles
│ ├── dictionaries
│ │ └── Luke.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── jarRepositories.xml
│ ├── misc.xml
│ ├── uiDesigner.xml
│ └── vcs.xml
├── README.md
├── build.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── guet
│ │ └── flexbox
│ │ └── intellij
│ │ └── ui
│ │ ├── CompileSettingFormBase.form
│ │ ├── CompileSettingFormBase.java
│ │ ├── MockSettingFormBase.form
│ │ └── MockSettingFormBase.java
│ ├── kotlin
│ └── com
│ │ └── guet
│ │ └── flexbox
│ │ └── intellij
│ │ ├── Utils.kt
│ │ ├── action
│ │ ├── NewFlexmlAction.kt
│ │ └── NewPackageAction.kt
│ │ ├── completion
│ │ ├── FlexmlCompletionContributor.kt
│ │ └── FlexmlComponentNameProvider.kt
│ │ ├── configuration
│ │ ├── CompileRunConfiguration.kt
│ │ ├── MockRunConfiguration.kt
│ │ ├── options
│ │ │ ├── CompileOptions.kt
│ │ │ └── MockOptions.kt
│ │ ├── producer
│ │ │ ├── CompileRunConfigurationProducer.kt
│ │ │ └── MockRunConfigurationProducer.kt
│ │ └── type
│ │ │ ├── CompileConfigurationType.kt
│ │ │ └── MockConfigurationType.kt
│ │ ├── fileType
│ │ ├── FlexmlFileType.kt
│ │ └── FlexmlFileTypeFactory.kt
│ │ ├── lineMarker
│ │ ├── CompileRunLineMarkerContributor.kt
│ │ └── MockRunLineMarkerContributor.kt
│ │ ├── res
│ │ ├── AttributeInfo.kt
│ │ ├── ComponentGroup.kt
│ │ ├── ComponentInfo.kt
│ │ ├── ComponentInfoBundle.kt
│ │ ├── Icons.kt
│ │ └── SupportType.kt
│ │ ├── service
│ │ ├── JarStartupManager.kt
│ │ └── impl
│ │ │ └── JarStartupManagerImpl.kt
│ │ └── ui
│ │ ├── CompileSettingForm.kt
│ │ └── MockSettingForm.kt
│ └── resources
│ ├── META-INF
│ └── plugin.xml
│ ├── fileTemplates
│ └── internal
│ │ ├── flexml-file.flexml.ft
│ │ └── package.json.ft
│ ├── flexml-components
│ ├── abs-text.json
│ ├── banner.json
│ ├── common.json
│ ├── empty.json
│ ├── flex.json
│ ├── for-each.json
│ ├── for.json
│ ├── if.json
│ ├── image.json
│ ├── package.json
│ ├── scroller.json
│ ├── stack.json
│ ├── text-input.json
│ ├── text.json
│ └── when.json
│ └── icons
│ ├── icon_tag.png
│ └── icon_type.png
├── litho
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── guet
│ │ └── flexbox
│ │ └── litho
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── guet
│ │ │ └── flexbox
│ │ │ └── litho
│ │ │ ├── HostingView.kt
│ │ │ ├── LithoBuildTool.kt
│ │ │ ├── LithoEventHandler.kt
│ │ │ ├── TemplatePage.kt
│ │ │ ├── ThreadPool.kt
│ │ │ ├── TreeManager.kt
│ │ │ ├── Utils.kt
│ │ │ ├── YogaNodeManager.kt
│ │ │ ├── drawable
│ │ │ ├── BitmapDrawable.kt
│ │ │ ├── ColorBorderDrawable.java
│ │ │ ├── ColorDrawable.java
│ │ │ ├── ComparableLayerDrawable.kt
│ │ │ ├── DrawableWrapper.kt
│ │ │ ├── GradientDrawable.java
│ │ │ ├── LazyDrawableLoader.kt
│ │ │ ├── LazyImageDrawable.kt
│ │ │ ├── NoOpDrawable.kt
│ │ │ └── load
│ │ │ │ ├── BitmapDrawableResource.kt
│ │ │ │ ├── BitmapDrawableTranscoder.kt
│ │ │ │ ├── CornerRadius.kt
│ │ │ │ ├── DelegateTarget.kt
│ │ │ │ ├── DrawableLoaderGlideModule.kt
│ │ │ │ ├── DrawableLoaderModule.kt
│ │ │ │ └── FileBufferLoader.kt
│ │ │ ├── factories
│ │ │ ├── CommonProps.kt
│ │ │ ├── ToBanner.kt
│ │ │ ├── ToComponent.kt
│ │ │ ├── ToDynamicImage.kt
│ │ │ ├── ToEmpty.kt
│ │ │ ├── ToFlex.kt
│ │ │ ├── ToImage.kt
│ │ │ ├── ToScroller.kt
│ │ │ ├── ToStack.kt
│ │ │ ├── ToText.kt
│ │ │ ├── ToTextInput.kt
│ │ │ └── filler
│ │ │ │ ├── ClickUrlFiller.kt
│ │ │ │ ├── EnumMappings.kt
│ │ │ │ ├── FillViewportFiller.kt
│ │ │ │ ├── GlideModelFiller.kt
│ │ │ │ ├── PropFiller.kt
│ │ │ │ ├── PropsFiller.kt
│ │ │ │ ├── ScrollBarEnableFiller.kt
│ │ │ │ ├── TextColorFiller.kt
│ │ │ │ └── TextFiller.kt
│ │ │ ├── transforms
│ │ │ └── FastBlur.kt
│ │ │ └── widget
│ │ │ ├── BannerSpec.kt
│ │ │ ├── ComponentTreePool.kt
│ │ │ ├── DynamicImageSpec.kt
│ │ │ ├── HorizontalScrollSpec.java
│ │ │ ├── LithoViewHolder.kt
│ │ │ ├── LithoViewsAdapter.kt
│ │ │ ├── StackSpec.kt
│ │ │ └── ThreadCheckerSpec.kt
│ └── res
│ │ └── drawable
│ │ ├── indicator_black.xml
│ │ └── indicator_light.xml
│ └── test
│ └── java
│ └── com
│ └── guet
│ └── flexbox
│ └── litho
│ └── ExampleUnitTest.kt
├── playground
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── guet
│ │ └── flexbox
│ │ ├── ExampleInstrumentedTest.java
│ │ └── TimePickerFragment.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── layout
│ │ │ ├── homepage
│ │ │ ├── banner.flexml
│ │ │ ├── banner.json
│ │ │ ├── feeds
│ │ │ │ ├── multi_images.flexml
│ │ │ │ └── three_entries.flexml
│ │ │ ├── function.flexml
│ │ │ └── function.json
│ │ │ ├── http
│ │ │ ├── data.json
│ │ │ ├── package.json
│ │ │ └── template.flexml
│ │ │ ├── introduction
│ │ │ ├── data.json
│ │ │ ├── package.json
│ │ │ └── template.flexml
│ │ │ ├── logo
│ │ │ ├── data.json
│ │ │ ├── package.json
│ │ │ └── template.flexml
│ │ │ ├── resume
│ │ │ ├── data.json
│ │ │ ├── package.json
│ │ │ └── template.flexml
│ │ │ └── search
│ │ │ └── history_list.flexml
│ ├── java
│ │ └── com
│ │ │ └── guet
│ │ │ └── flexbox
│ │ │ └── playground
│ │ │ ├── AboutFragment.kt
│ │ │ ├── FastStartupActivity.kt
│ │ │ ├── HomepageFragment.kt
│ │ │ ├── IntroductionFragment.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── OverviewActivity.kt
│ │ │ ├── PlaygroundApplication.kt
│ │ │ ├── SearchActivity.kt
│ │ │ ├── StartupActivity.kt
│ │ │ ├── Utils.kt
│ │ │ ├── model
│ │ │ ├── ACGImage.kt
│ │ │ ├── AppBundle.kt
│ │ │ ├── AppLoader.kt
│ │ │ ├── Homepage.kt
│ │ │ ├── ImageService.kt
│ │ │ ├── MockService.kt
│ │ │ ├── TemplateCompiler.kt
│ │ │ └── TextProvider.java
│ │ │ ├── test
│ │ │ ├── TestActivity.kt
│ │ │ └── TestView.kt
│ │ │ └── widget
│ │ │ ├── BlurLayout.kt
│ │ │ ├── CornerOutlineProvider.kt
│ │ │ ├── FlexBoxAdapter.kt
│ │ │ ├── MarqueeText.kt
│ │ │ ├── MyRefreshViewImpl.kt
│ │ │ ├── QuickHandler.kt
│ │ │ ├── StatusBarPadding.kt
│ │ │ └── TransformRootLayout.kt
│ └── res
│ │ ├── drawable
│ │ ├── banner_test.jpg
│ │ ├── console_background.xml
│ │ ├── glide.png
│ │ ├── go_back.png
│ │ ├── gpu.jpg
│ │ ├── ic_01.png
│ │ ├── ic_02.png
│ │ ├── ic_03.png
│ │ ├── ic_04.png
│ │ ├── ic_05.png
│ │ ├── ic_06.png
│ │ ├── ic_07.png
│ │ ├── ic_08.png
│ │ ├── ic_about.png
│ │ ├── ic_arrow_down.png
│ │ ├── ic_background_transition.xml
│ │ ├── ic_background_transition2.xml
│ │ ├── ic_gcta.png
│ │ ├── ic_info.png
│ │ ├── ic_jianjie.png
│ │ ├── ic_launcher.png
│ │ ├── ic_mian.png
│ │ ├── ic_photo2.jpg
│ │ ├── ic_qrcode.png
│ │ ├── ic_saoma.png
│ │ ├── ic_search_background.xml
│ │ ├── ic_startup.jpg
│ │ ├── ic_tomcat.png
│ │ ├── ic_zan_black.png
│ │ ├── ic_zan_w.png
│ │ ├── idea.png
│ │ ├── json.png
│ │ ├── kt.jpg
│ │ ├── litho.png
│ │ ├── phone.png
│ │ ├── slide_bar.xml
│ │ ├── succeed.png
│ │ ├── title_bg.xml
│ │ └── view.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_overview.xml
│ │ ├── activity_search.xml
│ │ ├── activity_test.xml
│ │ ├── banner_item.xml
│ │ ├── console_item.xml
│ │ ├── feed_item.xml
│ │ ├── fragment_code.xml
│ │ ├── fragment_homepage.xml
│ │ ├── idea_popup_window.xml
│ │ ├── load_more.xml
│ │ └── text_popup_window.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ ├── styleable.xml
│ │ ├── styles.xml
│ │ └── values.xml
│ │ └── xml
│ │ └── network_security_config.xml
│ └── test
│ └── java
│ └── com
│ └── guet
│ └── flexbox
│ └── ExampleUnitTest.kt
└── settings.gradle
/.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 |
--------------------------------------------------------------------------------
/.idea/dictionaries/Luke.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | cors
5 | datasource
6 | gson
7 | litho
8 | qrcode
9 | rewinder
10 | spliterator
11 | transcoder
12 | unselect
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | ext {
6 | kotlinVersion = '1.3.61'
7 | }
8 |
9 | repositories {
10 | // 阿里云防墙
11 | maven { url "https://maven.aliyun.com/repository/google"}
12 | maven { url "https://maven.aliyun.com/repository/public" }
13 | maven { url "https://maven.aliyun.com/repository/jcenter" }
14 | maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
15 | google()
16 | jcenter()
17 | mavenCentral()
18 | }
19 | dependencies {
20 | classpath 'com.android.tools.build:gradle:3.4.2'
21 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
22 |
23 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"
24 | }
25 | }
26 |
27 | allprojects {
28 | repositories {
29 | // 阿里云防墙
30 | maven { url "https://maven.aliyun.com/repository/google"}
31 | maven { url "https://maven.aliyun.com/repository/public" }
32 | maven { url "https://maven.aliyun.com/repository/jcenter" }
33 | maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
34 | maven { url "http://repository.atricore.org/m2-release-repository" }
35 | google()
36 | jcenter()
37 | mavenCentral()
38 | maven { url "https://jitpack.io" }
39 | }
40 | }
41 |
42 | task clean(type: Delete) {
43 | delete rootProject.buildDir
44 | }
45 |
46 | tasks.withType(JavaCompile) {
47 | options.encoding = "UTF-8"
48 | }
49 |
--------------------------------------------------------------------------------
/compiler/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/compiler/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | parent.repositories.forEach({ repository ->
4 | if (repository instanceof MavenArtifactRepository) {
5 | maven {
6 | url repository.url.toString()
7 | }
8 | }
9 | })
10 | }
11 | dependencies {
12 | classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0"
13 | }
14 | }
15 |
16 | apply plugin: 'com.github.johnrengelman.shadow'
17 | apply plugin: 'java'
18 | apply plugin: 'kotlin'
19 |
20 | dependencies {
21 | implementation fileTree(dir: 'libs', include: ['*.jar'])
22 | implementation "commons-cli:commons-cli:1.4"
23 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${kotlinVersion}"
24 | implementation 'org.dom4j:dom4j:2.1.1'
25 | implementation 'com.google.code.gson:gson:2.8.6'
26 | }
27 |
28 | sourceCompatibility = JavaVersion.VERSION_1_8
29 | targetCompatibility = JavaVersion.VERSION_1_8
30 |
31 | shadowJar {
32 | manifestContentCharset 'utf-8'
33 | metadataCharset 'utf-8'
34 | archiveName = 'flexmlc.jar'
35 | manifest {
36 | attributes "Manifest-Version": 1.0,
37 | 'Main-Class': 'com.guet.flexbox.compiler.Main'
38 | }
39 | }
--------------------------------------------------------------------------------
/compiler/src/main/java/com/guet/flexbox/compiler/Compiler.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.compiler
2 |
3 | import org.dom4j.Element
4 | import org.dom4j.io.SAXReader
5 | import java.io.File
6 | import java.io.StringReader
7 |
8 | open class Compiler(
9 | private val factory: NodeFactory
10 | ) {
11 |
12 | fun compile(layout: File): T {
13 | return transform(get().read(layout).rootElement)
14 | }
15 |
16 | fun compile(layout: String): T {
17 | return transform(get().read(StringReader(layout)).rootElement)
18 | }
19 |
20 | private fun transform(element: Element): T {
21 | return factory.createNode(
22 | element.name,
23 | element.attributes().map {
24 | it.name to it.value
25 | }.toMap(), element.elements().map {
26 | transform(it)
27 | })
28 | }
29 |
30 | private companion object SAX : ThreadLocal() {
31 | override fun initialValue(): SAXReader {
32 | return SAXReader()
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/compiler/src/main/java/com/guet/flexbox/compiler/JsonCompiler.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.compiler
2 |
3 | import com.google.gson.JsonArray
4 | import com.google.gson.JsonObject
5 |
6 | object JsonCompiler : Compiler(object : NodeFactory {
7 | override fun createNode(
8 | type: String,
9 | attrs: Map,
10 | children: List
11 | ): JsonObject {
12 | val obj = JsonObject()
13 | obj.addProperty("type", type)
14 | if (attrs.isNotEmpty()) {
15 | val objAttrs = JsonObject()
16 | obj.add("attrs", objAttrs)
17 | attrs.forEach {
18 | objAttrs.addProperty(it.key, it.value)
19 | }
20 | }
21 | if (children.isNotEmpty()) {
22 | val objChildren = JsonArray()
23 | obj.add("children", objChildren)
24 | children.forEach {
25 | objChildren.add(it)
26 | }
27 | }
28 | return obj
29 | }
30 | })
--------------------------------------------------------------------------------
/compiler/src/main/java/com/guet/flexbox/compiler/Main.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("Main")
2 | package com.guet.flexbox.compiler
3 |
4 | import com.google.gson.internal.Streams
5 | import com.google.gson.stream.JsonWriter
6 | import org.apache.commons.cli.DefaultParser
7 | import org.apache.commons.cli.Options
8 | import java.io.File
9 | import kotlin.system.exitProcess
10 |
11 | fun main(args: Array) {
12 | val parser = DefaultParser()
13 | val options = Options().apply {
14 | addOption("i", "input", true, "布局源文件")
15 | addOption("o", "output", true, "输出文件")
16 | }
17 | val commandLine = parser.parse(options, args)
18 | var input: File? = null
19 | var output: File? = null
20 | if (commandLine.hasOption("i")) {
21 | input = File(commandLine.getOptionValue("i"))
22 | }
23 | if (commandLine.hasOption("o")) {
24 | output = File(commandLine.getOptionValue("o"))
25 | }
26 | if (input != null && output != null) {
27 | val iex = input.extension
28 | if ((iex != "flexml") && (iex != "xml")) {
29 | System.err.println("输入文件后缀不合规范(应该为.flexml或.xml)")
30 | exitProcess(-2)
31 | }
32 | val oex = output.extension
33 | if (oex != "json") {
34 | System.err.println("输出文件后缀不合规范(应该为.json)")
35 | exitProcess(-3)
36 | }
37 | if (output.exists()) {
38 | output.delete()
39 | }
40 | output.createNewFile()
41 | JsonWriter(output.writer().buffered()).apply {
42 | isLenient = true
43 | }.use { writer ->
44 | val jsonObject = JsonCompiler.compile(input)
45 | Streams.write(jsonObject, writer)
46 | }
47 | println("编译完成,在:${input.absolutePath}")
48 | exitProcess(0)
49 | } else {
50 | System.err.println("没有输出或输出文件的参数")
51 | exitProcess(-1)
52 | }
53 | }
--------------------------------------------------------------------------------
/compiler/src/main/java/com/guet/flexbox/compiler/NodeFactory.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.compiler
2 |
3 | interface NodeFactory {
4 | fun createNode(
5 | type: String,
6 | attrs: Map,
7 | children: List
8 | ): T
9 | }
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/core/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 | group = 'com.guet.flexbox'
5 |
6 |
7 | android {
8 | compileSdkVersion 28
9 |
10 | defaultConfig {
11 | minSdkVersion 19
12 | targetSdkVersion 28
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 |
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 |
27 | compileOptions {
28 | sourceCompatibility JavaVersion.VERSION_1_8
29 | targetCompatibility JavaVersion.VERSION_1_8
30 | }
31 | }
32 |
33 |
34 | dependencies {
35 | implementation fileTree(dir: 'libs', include: ['*.jar'])
36 |
37 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${kotlinVersion}"
38 | implementation('org.apache.commons:commons-jexl3:3.1') {
39 | exclude group: 'commons-logging', module: 'commons-logging'
40 | }
41 | api 'androidx.annotation:annotation:1.1.0'
42 |
43 | testImplementation 'junit:junit:4.12'
44 | androidTestImplementation 'androidx.test:runner:1.2.0'
45 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/core/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 buildLayout.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 type 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 type.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/core/src/androidTest/java/com/guet/flexbox/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.InstrumentationRegistry;
6 | import androidx.test.runner.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.getTargetContext();
24 |
25 | assertEquals("com.guet.flexbox.test", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/TemplateNode.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox
2 |
3 | class TemplateNode(
4 | val type: String,
5 | val attrs: Map?,
6 | val children: List?
7 | )
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/AbsText.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import android.text.TextUtils
4 | import com.guet.flexbox.enums.Horizontal
5 | import com.guet.flexbox.enums.TextStyle
6 | import com.guet.flexbox.enums.Vertical
7 |
8 | internal object AbsText : Widget() {
9 |
10 | override val dataBinding by DataBinding
11 | .create(CommonDefine) {
12 | enum("verticalGravity", mapOf(
13 | "top" to Vertical.TOP,
14 | "bottom" to Vertical.BOTTOM,
15 | "center" to Vertical.CENTER
16 | ))
17 | enum("horizontalGravity", mapOf(
18 | "left" to Horizontal.LEFT,
19 | "right" to Horizontal.RIGHT,
20 | "center" to Horizontal.CENTER
21 | ))
22 | enum("ellipsize", mapOf(
23 | "start" to TextUtils.TruncateAt.START,
24 | "end" to TextUtils.TruncateAt.END,
25 | "middle" to TextUtils.TruncateAt.MIDDLE,
26 | "marquee" to TextUtils.TruncateAt.MARQUEE
27 | ))
28 | value("maxLines", fallback = Int.MAX_VALUE.toFloat())
29 | value("minLines", fallback = Int.MIN_VALUE.toFloat())
30 | value("textSize", fallback = 13.0f)
31 | enum("textStyle", mapOf(
32 | "normal" to TextStyle.NORMAL,
33 | "bold" to TextStyle.BOLD
34 | ))
35 | }
36 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/Banner.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.enums.Orientation
5 |
6 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
7 | object Banner : Widget() {
8 | override val dataBinding by DataBinding
9 | .create(CommonDefine) {
10 | bool("isCircular")
11 | value("timeSpan", fallback = 3000.0f)
12 | enum("orientation", mapOf(
13 | "vertical" to Orientation.VERTICAL,
14 | "horizontal" to Orientation.HORIZONTAL
15 | ))
16 | bool("indicatorEnable")
17 | value("indicatorSize")
18 | value("indicatorHeight", fallback = 5.0f)
19 | text("indicatorSelected")
20 | text("indicatorUnselected")
21 | }
22 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/BuildKit.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import android.content.Context
4 |
5 | interface BuildKit {
6 | fun init(c: Context)
7 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/CommonDefine.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.enums.FlexAlign
5 | import com.guet.flexbox.eventsystem.ClickUrlEventReceiver
6 | import com.guet.flexbox.eventsystem.event.ClickExprEvent
7 | import com.guet.flexbox.eventsystem.event.VisibleEvent
8 |
9 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
10 | object CommonDefine : Widget() {
11 |
12 | override val dataBinding by DataBinding.create {
13 | value("width")
14 | value("height")
15 | value("flexGrow")
16 | value("flexShrink")
17 | value("minWidth")
18 | value("maxWidth")
19 | value("minHeight")
20 | value("maxHeight")
21 | enum("alignSelf", mapOf(
22 | "auto" to FlexAlign.AUTO,
23 | "flexStart" to FlexAlign.FLEX_START,
24 | "flexEnd" to FlexAlign.FLEX_END,
25 | "center" to FlexAlign.CENTER,
26 | "baseline" to FlexAlign.BASELINE,
27 | "stretch" to FlexAlign.STRETCH
28 | ))
29 | value("margin")
30 | value("padding")
31 | color("borderColor")
32 | value("borderRadius")
33 | for (lr in arrayOf("Left", "Right")) {
34 | for (tb in arrayOf("Top", "Bottom")) {
35 | value("border${lr}${tb}Radius")
36 | }
37 | }
38 | value("borderWidth")
39 | value("shadowElevation")
40 | text("background")
41 | for (edge in arrayOf("Left", "Right", "Top", "Bottom")) {
42 | value("margin$edge")
43 | value("padding$edge")
44 | }
45 | typed("clickUrl", ClickUrlEventReceiver.Covertor)
46 | event("onClick", ClickExprEvent.Factory)
47 | event("onVisible", VisibleEvent.Factory)
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/DataBinder.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import com.guet.flexbox.eventsystem.EventTarget
4 | import org.apache.commons.jexl3.JexlContext
5 | import org.apache.commons.jexl3.JexlEngine
6 |
7 | internal interface DataBinder{
8 | fun cast(
9 | engine: JexlEngine,
10 | dataContext: JexlContext,
11 | eventDispatcher: EventTarget,
12 | raw: String
13 | ): T?
14 | }
15 |
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/Definition.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import com.guet.flexbox.TemplateNode
4 | import com.guet.flexbox.eventsystem.EventTarget
5 | import org.apache.commons.jexl3.JexlContext
6 | import org.apache.commons.jexl3.JexlEngine
7 |
8 | abstract class Definition {
9 |
10 | internal abstract val dataBinding: DataBinding
11 |
12 | internal abstract fun onBuildWidget(
13 | buildTool: BuildTool,
14 | rawProps: Map,
15 | children: List,
16 | factory: RenderNodeFactory<*>?,
17 | engine: JexlEngine,
18 | dataContext: JexlContext,
19 | eventDispatcher: EventTarget,
20 | other: Any?,
21 | upperDisplay: Boolean = true
22 | ): List
23 |
24 | fun bindProps(
25 | rawAttrs: Map,
26 | engine: JexlEngine,
27 | dataContext: JexlContext,
28 | eventDispatcher: EventTarget
29 | ): PropSet {
30 | return dataBinding.bind(
31 | engine,
32 | dataContext,
33 | eventDispatcher,
34 | rawAttrs
35 | )
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/Empty.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.TemplateNode
5 | import com.guet.flexbox.eventsystem.EventTarget
6 | import org.apache.commons.jexl3.JexlContext
7 | import org.apache.commons.jexl3.JexlEngine
8 |
9 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
10 | object Empty : Widget() {
11 |
12 | override val dataBinding: DataBinding
13 | get() = CommonDefine.dataBinding
14 |
15 | override fun onBuildWidget(
16 | buildTool: BuildTool,
17 | rawProps: Map,
18 | children: List,
19 | factory: RenderNodeFactory<*>?,
20 | engine: JexlEngine,
21 | dataContext: JexlContext,
22 | eventDispatcher: EventTarget,
23 | other: Any?,
24 | upperDisplay: Boolean
25 | ): List {
26 | return super.onBuildWidget(
27 | buildTool,
28 | rawProps,
29 | children,
30 | factory,
31 | engine,
32 | dataContext,
33 | eventDispatcher,
34 | other,
35 | false
36 | )
37 | }
38 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/For.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.TemplateNode
5 | import com.guet.flexbox.context.ScopeContext
6 | import com.guet.flexbox.eventsystem.EventTarget
7 | import org.apache.commons.jexl3.JexlContext
8 | import org.apache.commons.jexl3.JexlEngine
9 | import java.util.*
10 |
11 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
12 | object For : Definition() {
13 |
14 | override val dataBinding by DataBinding
15 | .create {
16 | text("var")
17 | value("from")
18 | value("to")
19 | }
20 |
21 | override fun onBuildWidget(
22 | buildTool: BuildTool,
23 | rawProps: Map,
24 | children: List,
25 | factory: RenderNodeFactory<*>?,
26 | engine: JexlEngine,
27 | dataContext: JexlContext,
28 | eventDispatcher: EventTarget,
29 | other: Any?,
30 | upperDisplay: Boolean
31 | ): List {
32 | val attrs = bindProps(rawProps, engine, dataContext, eventDispatcher)
33 | val name = attrs.getValue("var") as String
34 | val from = (attrs.getValue("from") as Float).toInt()
35 | val to = (attrs.getValue("to") as Float).toInt()
36 | val list = LinkedList()
37 | for (index in from..to) {
38 | val scope = ScopeContext(mapOf(name to index), dataContext)
39 | val subList = buildTool.buildAll(
40 | children,
41 | engine,
42 | scope,
43 | eventDispatcher,
44 | other,
45 | upperDisplay
46 | )
47 | list.addAll(subList)
48 | }
49 | return list
50 | }
51 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/Graphic.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import com.guet.flexbox.enums.ScaleType
4 |
5 | internal object Graphic : Widget() {
6 | override val dataBinding by DataBinding
7 | .create(CommonDefine) {
8 | enum("scaleType", mapOf(
9 | "center" to ScaleType.CENTER,
10 | "fitCenter" to ScaleType.FIT_CENTER,
11 | "fitXY" to ScaleType.FIT_XY,
12 | "fitStart" to ScaleType.FIT_START,
13 | "fitEnd" to ScaleType.FIT_END,
14 | "centerInside" to ScaleType.CENTER_INSIDE,
15 | "centerCrop" to ScaleType.CENTER_CROP
16 | ))
17 | text("src")
18 | value("aspectRatio")
19 | }
20 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/If.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.TemplateNode
5 | import com.guet.flexbox.eventsystem.EventTarget
6 | import org.apache.commons.jexl3.JexlContext
7 | import org.apache.commons.jexl3.JexlEngine
8 |
9 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
10 | object If : Definition() {
11 |
12 | override val dataBinding by DataBinding
13 | .create {
14 | bool("test")
15 | }
16 |
17 | override fun onBuildWidget(
18 | buildTool: BuildTool,
19 | rawProps: Map,
20 | children: List,
21 | factory: RenderNodeFactory<*>?,
22 | engine: JexlEngine,
23 | dataContext: JexlContext,
24 | eventDispatcher: EventTarget,
25 | other: Any?,
26 | upperDisplay: Boolean
27 | ): List {
28 | val attrs = bindProps(rawProps, engine, dataContext, eventDispatcher)
29 | return if (attrs.getValue("test") as? Boolean != true) {
30 | emptyList()
31 | } else {
32 | buildTool.buildAll(
33 | children,
34 | engine,
35 | dataContext,
36 | eventDispatcher,
37 | other,
38 | upperDisplay
39 | )
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/Image.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 |
5 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
6 | object Image : Widget() {
7 | override val dataBinding by DataBinding
8 | .create(Graphic) {
9 | value("blurRadius")
10 | value("blurSampling")
11 | }
12 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/RenderNodeFactory.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | interface RenderNodeFactory {
4 | fun create(
5 | display: Boolean,
6 | attrs: PropSet,
7 | children: List,
8 | other: Any?
9 | ): T
10 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/Scroller.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.enums.Orientation
5 |
6 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
7 | object Scroller : Widget() {
8 | override val dataBinding: DataBinding by DataBinding
9 | .create(CommonDefine) {
10 | bool("scrollBarEnable")
11 | enum("orientation", mapOf(
12 | "vertical" to Orientation.VERTICAL,
13 | "horizontal" to Orientation.HORIZONTAL
14 | ))
15 | bool("fillViewport")
16 | }
17 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/Text.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 |
5 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
6 | object Text : Widget() {
7 | override val dataBinding by DataBinding
8 | .create(AbsText) {
9 | text("text")
10 | bool("clipToBounds")
11 | color("textColor")
12 | }
13 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/TextInput.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.eventsystem.event.TextChangedEvent
5 |
6 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
7 | object TextInput : Widget() {
8 | override val dataBinding by DataBinding
9 | .create(CommonDefine) {
10 | event("onTextChanged", TextChangedEvent.Factory)
11 | }
12 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/ToWidget.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.TemplateNode
5 | import com.guet.flexbox.eventsystem.EventTarget
6 | import org.apache.commons.jexl3.JexlContext
7 | import org.apache.commons.jexl3.JexlEngine
8 |
9 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
10 | class ToWidget(
11 | private val definition: Definition,
12 | private val factory: RenderNodeFactory<*>?
13 | ) {
14 | fun toWidget(
15 | bindings: BuildTool,
16 | template: TemplateNode,
17 | engine: JexlEngine,
18 | dataContext: JexlContext,
19 | eventDispatcher: EventTarget,
20 | other: Any?,
21 | upperDisplay: Boolean = true
22 | ): List {
23 | return definition.onBuildWidget(
24 | bindings,
25 | template.attrs ?: emptyMap(),
26 | template.children ?: emptyList(),
27 | factory,
28 | engine,
29 | dataContext,
30 | eventDispatcher,
31 | other,
32 | upperDisplay
33 | )
34 | }
35 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/build/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.build
2 |
3 | typealias PropSet = Map
4 |
5 | inline val String.isExpr: Boolean
6 | get() {
7 | val trim = trim()
8 | return trim.startsWith("\${") && trim.endsWith("}")
9 | }
10 |
11 | inline val String.innerExpr: String
12 | get() {
13 | return trim().substring(2, length - 1)
14 | }
15 |
16 |
17 |
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/context/ScopeContext.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.context
2 |
3 | import org.apache.commons.jexl3.JexlContext
4 | import org.apache.commons.jexl3.MapContext
5 |
6 | class ScopeContext(
7 | scope: Map,
8 | private val inner: JexlContext
9 | ) : MapContext(scope), JexlContext.NamespaceResolver {
10 |
11 | override fun has(name: String?): Boolean {
12 | var h = super.has(name)
13 | if (!h) {
14 | h = inner.has(name)
15 | }
16 | return h
17 | }
18 |
19 | override fun get(name: String?): Any? {
20 | val h = super.has(name)
21 | return if (h) {
22 | super.get(name)
23 | } else {
24 | inner.get(name)
25 | }
26 | }
27 |
28 | override fun set(name: String?, value: Any?) {
29 | val h = super.has(name)
30 | if (!h) {
31 | inner.set(name, value)
32 | } else {
33 | throw IllegalArgumentException()
34 | }
35 | }
36 |
37 | override fun resolveNamespace(name: String?): Any? {
38 | return if (
39 | !name.isNullOrEmpty()
40 | && inner is JexlContext.NamespaceResolver
41 | ) {
42 | inner.resolveNamespace(name)
43 | } else {
44 | null
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/FlexAlign.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class FlexAlign {
4 | AUTO,
5 | FLEX_START,
6 | CENTER,
7 | FLEX_END,
8 | STRETCH,
9 | BASELINE,
10 | SPACE_BETWEEN,
11 | SPACE_AROUND;
12 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/FlexDirection.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class FlexDirection {
4 | COLUMN,
5 | COLUMN_REVERSE,
6 | ROW,
7 | ROW_REVERSE;
8 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/FlexJustify.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class FlexJustify {
4 | FLEX_START,
5 | CENTER,
6 | FLEX_END,
7 | SPACE_BETWEEN,
8 | SPACE_AROUND,
9 | SPACE_EVENLY;
10 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/FlexWrap.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class FlexWrap {
4 | NO_WRAP,
5 | WRAP,
6 | WRAP_REVERSE;
7 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/Horizontal.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class Horizontal {
4 | LEFT, CENTER, RIGHT
5 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/Orientation.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class Orientation(val value:Int) {
4 | HORIZONTAL(0),
5 | VERTICAL(1),
6 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/ScaleType.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class ScaleType {
4 | FIT_XY,
5 | FIT_START,
6 | FIT_CENTER,
7 | FIT_END,
8 | CENTER,
9 | CENTER_CROP,
10 | CENTER_INSIDE;
11 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/TextStyle.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class TextStyle {
4 | NORMAL, BOLD
5 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/Vertical.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class Vertical {
4 | TOP, CENTER, BOTTOM
5 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/enums/Visibility.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.enums
2 |
3 | enum class Visibility {
4 | VISIBLE,
5 | INVISIBLE,
6 | GONE,
7 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/ClickUrlEventReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem
2 |
3 | import android.view.View
4 | import com.guet.flexbox.build.DataBinder
5 | import com.guet.flexbox.build.innerExpr
6 | import com.guet.flexbox.build.isExpr
7 | import com.guet.flexbox.eventsystem.event.ClickUrlEvent
8 | import org.apache.commons.jexl3.JexlContext
9 | import org.apache.commons.jexl3.JexlEngine
10 |
11 | internal class ClickUrlEventReceiver(
12 | private val eventDispatcher: EventTarget,
13 | private val url: String
14 | ) : ExternalEventReceiver {
15 |
16 | override fun receive(v: View?, args: Array?) {
17 | eventDispatcher.dispatchEvent(
18 | ClickUrlEvent(v!!, url)
19 | )
20 | }
21 |
22 | companion object Covertor : DataBinder {
23 | override fun cast(
24 | engine: JexlEngine,
25 | dataContext: JexlContext,
26 | eventDispatcher: EventTarget,
27 | raw: String
28 | ): ClickUrlEventReceiver? {
29 | val url = if (raw.isExpr) {
30 | engine.createExpression(raw.innerExpr)
31 | .evaluate(dataContext) as? String ?: ""
32 | } else {
33 | raw
34 | }
35 | return ClickUrlEventReceiver(eventDispatcher, url)
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/EventBus.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.eventsystem.event.TemplateEvent
5 | import java.lang.reflect.Modifier
6 | import java.lang.reflect.ParameterizedType
7 |
8 | class EventBus : EventTarget {
9 |
10 | private val handlers = HashMap, EventHandler<*>>()
11 |
12 | fun > subscribe(h: EventHandler): EventHandler? {
13 | val eventType = getEventType(h)
14 | if (Modifier.isAbstract(eventType.modifiers)) {
15 | throw IllegalArgumentException()
16 | }
17 | return synchronized(handlers) {
18 | @Suppress("UNCHECKED_CAST")
19 | handlers.put(eventType, h) as? EventHandler
20 | }
21 | }
22 |
23 | fun unsubscribe(h: EventHandler<*>) {
24 | val eventType = getEventType(h)
25 | synchronized(handlers) {
26 | val oldH = handlers[eventType]
27 | if (oldH == h) {
28 | handlers.remove(eventType)
29 | }
30 | }
31 | }
32 |
33 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
34 | override fun dispatchEvent(e: TemplateEvent<*>): Boolean {
35 | val eventType = e.javaClass
36 | synchronized(handlers) {
37 | @Suppress("UNCHECKED_CAST")
38 | return (handlers[eventType] as? EventHandler>)
39 | ?.handleEvent(e) ?: false
40 | }
41 | }
42 |
43 | private companion object {
44 | private fun getEventType(h: EventHandler<*>): Class<*> {
45 | return try {
46 | (h.javaClass.genericInterfaces.find {
47 | (it as? ParameterizedType)?.rawType == EventHandler::class.java
48 | } as ParameterizedType).actualTypeArguments[0] as Class<*>
49 | } catch (e: Throwable) {
50 | throw IllegalArgumentException(e)
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/EventDispatcher.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem
2 |
3 | import android.util.Log
4 | import androidx.annotation.RestrictTo
5 | import com.guet.flexbox.eventsystem.event.HasExprEvent
6 | import com.guet.flexbox.eventsystem.event.TemplateEvent
7 | import java.lang.ref.WeakReference
8 |
9 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
10 | class EventDispatcher : EventTarget {
11 |
12 | private var targetRef: WeakReference? = null
13 |
14 | var target: EventTarget?
15 | set(value) {
16 | targetRef = if (value != null) {
17 | val t = target
18 | if (t != null && t != value) {
19 | Log.e("EventDispatcher",
20 | "This Page is set to two HostingView. " +
21 | "This is not support.")
22 | }
23 | WeakReference(value)
24 | } else {
25 | null
26 | }
27 | }
28 | get() {
29 | return targetRef?.get()
30 | }
31 |
32 | override fun dispatchEvent(e: TemplateEvent<*>): Boolean {
33 | val result = target?.dispatchEvent(e) ?: false
34 | if (!result && e is HasExprEvent) {
35 | e.expr.call()
36 | return true
37 | }
38 | return false
39 | }
40 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/EventHandler.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem
2 |
3 | import com.guet.flexbox.eventsystem.event.TemplateEvent
4 | import java.util.*
5 |
6 | interface EventHandler> : EventListener {
7 | fun handleEvent(e: E): Boolean
8 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/EventTarget.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem
2 |
3 | import androidx.annotation.RestrictTo
4 | import com.guet.flexbox.eventsystem.event.TemplateEvent
5 |
6 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
7 | interface EventTarget {
8 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
9 | fun dispatchEvent(e: TemplateEvent<*>): Boolean
10 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/ExternalEventReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem
2 |
3 | import android.view.View
4 | import androidx.annotation.RestrictTo
5 |
6 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
7 | interface ExternalEventReceiver {
8 | fun receive(v: View?, args: Array?)
9 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/ReceiveEventToExpr.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem
2 |
3 | import android.view.View
4 | import com.guet.flexbox.eventsystem.event.TemplateEvent
5 | import org.apache.commons.jexl3.JexlContext
6 | import org.apache.commons.jexl3.JexlScript
7 |
8 | internal class ReceiveEventToExpr(
9 | private val factory: TemplateEvent.Factory,
10 | private val dataContext: JexlContext,
11 | private val eventDispatcher: EventTarget,
12 | private val script: JexlScript
13 | ) : ExternalEventReceiver {
14 | override fun receive(v: View?, args: Array?) {
15 | eventDispatcher.dispatchEvent(factory
16 | .create(v, args, dataContext, script)
17 | )
18 | }
19 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/ClickEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import android.view.View
4 |
5 | abstract class ClickEvent(
6 | source: View
7 | ) : TemplateEvent(source)
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/ClickExprEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import android.view.View
4 | import org.apache.commons.jexl3.JexlContext
5 | import org.apache.commons.jexl3.JexlScript
6 | import java.util.concurrent.Callable
7 |
8 | class ClickExprEvent(
9 | source: View,
10 | context: JexlContext,
11 | script: JexlScript
12 | ) : ClickEvent(source), HasExprEvent {
13 | override val expr: Callable = script.callable(context)
14 |
15 | companion object Factory : TemplateEvent.Factory {
16 | override fun create(
17 | source: View?,
18 | args: Array?,
19 | dataContext: JexlContext,
20 | script: JexlScript
21 | ): TemplateEvent<*> {
22 | return ClickExprEvent(source!!, dataContext, script)
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/ClickUrlEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import android.view.View
4 | import org.apache.commons.jexl3.JexlContext
5 | import org.apache.commons.jexl3.JexlScript
6 |
7 | class ClickUrlEvent(
8 | source: View,
9 | val url: String
10 | ) : ClickEvent(source) {
11 |
12 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/HasExprEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import java.util.concurrent.Callable
4 |
5 | interface HasExprEvent {
6 | val expr: Callable
7 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/HttpRequestEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import com.guet.flexbox.http.HttpRequest
4 |
5 | class HttpRequestEvent(
6 | val httpRequest: HttpRequest
7 | ) : TemplateEvent(Unit)
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/RefreshPageEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import androidx.annotation.RestrictTo
4 |
5 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
6 | class RefreshPageEvent : TemplateEvent(Unit)
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/SendObjectsEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | class SendObjectsEvent(
4 | val values: Array
5 | ) : TemplateEvent(Unit)
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/TemplateEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import android.view.View
4 | import org.apache.commons.jexl3.JexlContext
5 | import org.apache.commons.jexl3.JexlScript
6 | import java.util.*
7 |
8 | abstract class TemplateEvent(
9 | source: T
10 | ) : EventObject(source) {
11 | override fun getSource(): T {
12 | @Suppress("UNCHECKED_CAST")
13 | return super.getSource() as T
14 | }
15 |
16 | interface Factory {
17 | fun create(
18 | source: View?,
19 | args: Array?,
20 | dataContext: JexlContext,
21 | script: JexlScript
22 | ): TemplateEvent<*>
23 | }
24 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/TextChangedEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import android.view.View
4 | import android.widget.EditText
5 | import org.apache.commons.jexl3.JexlContext
6 | import org.apache.commons.jexl3.JexlScript
7 | import java.util.concurrent.Callable
8 |
9 | class TextChangedEvent(
10 | source: EditText,
11 | val text: String?,
12 | context: JexlContext,
13 | script: JexlScript
14 | ) : TemplateEvent(
15 | source
16 | ), HasExprEvent {
17 | override val expr: Callable = script.callable(context)
18 |
19 | companion object Factory : TemplateEvent.Factory {
20 | override fun create(
21 | source: View?,
22 | args: Array?,
23 | dataContext: JexlContext,
24 | script: JexlScript
25 | ): TemplateEvent<*> {
26 | return TextChangedEvent(
27 | source as EditText,
28 | args?.get(0) as? String,
29 | dataContext,
30 | script
31 | )
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/eventsystem/event/VisibleEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.eventsystem.event
2 |
3 | import android.view.View
4 | import org.apache.commons.jexl3.JexlContext
5 | import org.apache.commons.jexl3.JexlScript
6 | import java.util.concurrent.Callable
7 |
8 | class VisibleEvent(
9 | context: JexlContext,
10 | script: JexlScript
11 | ) : TemplateEvent(Unit), HasExprEvent {
12 | override val expr: Callable = script.callable(context)
13 | companion object Factory : TemplateEvent.Factory {
14 | override fun create(
15 | source: View?,
16 | args: Array?,
17 | dataContext: JexlContext,
18 | script: JexlScript
19 | ): TemplateEvent<*> {
20 | return VisibleEvent(dataContext, script)
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/http/CallbackImpl.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.http
2 |
3 | import android.os.Handler
4 | import android.os.Looper
5 | import org.apache.commons.jexl3.JexlContext
6 | import org.apache.commons.jexl3.JexlScript
7 |
8 | internal class CallbackImpl(
9 | private val dataContext: JexlContext,
10 | private val success: JexlScript?,
11 | private val error: JexlScript?
12 | ) : HttpRequest.Callback {
13 |
14 | override fun onError() {
15 | if (error != null) {
16 | if (Looper.myLooper() == mainLooper) {
17 | error.execute(dataContext)
18 | } else {
19 | mainThread.post {
20 | error.execute(dataContext)
21 | }
22 | }
23 | }
24 | }
25 |
26 | override fun onResponse(data: String?) {
27 | if (success != null) {
28 | if (Looper.myLooper() == mainLooper) {
29 | success.execute(dataContext, data)
30 | } else {
31 | mainThread.post {
32 | success.execute(dataContext, data)
33 | }
34 | }
35 | }
36 | }
37 |
38 | private companion object {
39 | private val mainLooper = Looper.getMainLooper()
40 | private val mainThread = Handler(mainLooper)
41 | }
42 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/guet/flexbox/http/HttpRequest.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.http
2 |
3 | class HttpRequest(
4 | val url: String,
5 | val method: String,
6 | val body: Map,
7 | val callback: Callback
8 | ) {
9 | interface Callback {
10 | fun onResponse(data: String?)
11 |
12 | fun onError()
13 | }
14 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/apache/commons/logging/LogFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package org.apache.commons.logging;
19 |
20 | import com.guet.flexbox.log.AndroidLog;
21 |
22 | @SuppressWarnings("WeakerAccess")
23 | public abstract class LogFactory {
24 |
25 | public static Log getLog(Class clazz) {
26 | return getLog(clazz.getSimpleName());
27 | }
28 |
29 | public static Log getLog(String name) {
30 | return AndroidLog.getLog(name);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/core/src/test/java/com/guet/flexbox/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox
2 |
3 | import com.guet.flexbox.context.ELProcessor
4 | import com.guet.flexbox.context.LambdaExpression
5 | import com.guet.flexbox.event.ActionBridge
6 | import org.junit.Assert
7 | import org.junit.Test
8 |
9 | /**
10 | * Example local unit test, which will execute on the development machine (host).
11 | *
12 | * @see [Testing documentation](http://d.android.com/tools/testing)
13 | */
14 | class ExampleUnitTest {
15 | @Test
16 | fun addition_isCorrect2() {
17 | val p = ELProcessor()
18 | val impl = ActionBridge().newPageContext()
19 | p.defineBean("pageContext", impl.newWrapper())
20 | p.defineBean("xxx","xxx")
21 | val x2 = p.eval("()->{System.out.println(xxx)}") as LambdaExpression
22 | x2.invoke()
23 | val x = p.eval("()->{pageContext.refresh().commit()}") as LambdaExpression
24 | x.invoke()
25 | Assert.assertEquals(4, (2 + 2).toLong())
26 | }
27 | }
--------------------------------------------------------------------------------
/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 |
21 | kapt.incremental.apt = false
22 |
23 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jan 27 16:03:45 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/handshake/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/handshake/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 |
3 | ext {
4 | springIOVersion = '2.2.4.RELEASE'
5 | springPluginVersion = '1.0.9.RELEASE'
6 | }
7 |
8 | repositories {
9 | parent.repositories.forEach({ repository ->
10 | if (repository instanceof MavenArtifactRepository) {
11 | maven {
12 | url repository.url.toString()
13 | }
14 | }
15 | })
16 | maven { url "http://repo.spring.io/release" }
17 | maven { url "http://repo.spring.io/milestone" }
18 | maven { url "http://repo.spring.io/snapshot" }
19 | maven { url "https://plugins.gradle.org/m2/" }
20 | }
21 | dependencies {
22 | classpath "io.spring.gradle:dependency-management-plugin:${springPluginVersion}"
23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${springIOVersion}"
24 | }
25 | }
26 |
27 | apply plugin: 'java'
28 | apply plugin: 'kotlin'
29 | apply plugin: 'org.springframework.boot'
30 | apply plugin: 'io.spring.dependency-management'
31 |
32 | compileKotlin {
33 | kotlinOptions.jvmTarget = "1.8"
34 | }
35 | compileTestKotlin {
36 | kotlinOptions.jvmTarget = "1.8"
37 | }
38 |
39 | dependencies {
40 | implementation fileTree(dir: 'libs', include: ['*.jar'])
41 | implementation('com.google.code.gson:gson:2.8.6')
42 | implementation project(':compiler')
43 | implementation('com.google.zxing:core:3.4.0')
44 | implementation("org.springframework.boot:spring-boot-starter:${springIOVersion}")
45 | implementation("org.springframework.boot:spring-boot-starter-web:${springIOVersion}"){
46 | exclude group: "org.springframework.boot", module: "spring-boot-starter-json"
47 | }
48 | implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
49 | implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
50 | testImplementation("org.springframework.boot:spring-boot-starter-test:${springIOVersion}") {
51 | exclude group: "org.junit.vintage", module: "junit-vintage-engine"
52 | }
53 | }
54 |
55 | sourceCompatibility = 1.8
56 | targetCompatibility = 1.8
57 |
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/Main.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("Main")
2 |
3 | package com.guet.flexbox.handshake
4 |
5 | import org.springframework.boot.runApplication
6 |
7 | fun main(args: Array) {
8 | runApplication(*args)
9 | }
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/MockApplication.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.handshake
2 |
3 | import org.slf4j.LoggerFactory
4 | import org.springframework.beans.factory.annotation.Autowired
5 | import org.springframework.boot.ApplicationArguments
6 | import org.springframework.boot.ApplicationRunner
7 | import org.springframework.boot.autoconfigure.SpringBootApplication
8 | import org.springframework.context.annotation.Configuration
9 | import java.util.concurrent.ConcurrentHashMap
10 |
11 | @Configuration
12 | @SpringBootApplication
13 | open class MockApplication : ApplicationRunner {
14 |
15 | private val logger = LoggerFactory.getLogger(MockApplication::class.java)
16 |
17 | @Autowired
18 | private lateinit var attributes: ConcurrentHashMap
19 |
20 | override fun run(args: ApplicationArguments) {
21 | if (args.containsOption("package.focus")) {
22 | val focus = args.getOptionValues("package.focus").first()
23 | attributes["focus"] = focus
24 | logger.info("focus=$focus")
25 | }
26 | }
27 |
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/NetworkChangedEvent.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.handshake
2 |
3 | import org.springframework.context.ApplicationEvent
4 |
5 | class NetworkChangedEvent(
6 | source: Any,
7 | val host: String
8 | ) : ApplicationEvent(source)
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/NetworkWatcher.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.handshake
2 |
3 | import com.guet.flexbox.handshake.lan.LANAddressProvider
4 | import org.slf4j.LoggerFactory
5 | import org.springframework.beans.factory.annotation.Autowired
6 | import org.springframework.boot.web.context.WebServerInitializedEvent
7 | import org.springframework.context.ApplicationContext
8 | import org.springframework.context.event.EventListener
9 | import org.springframework.stereotype.Component
10 | import java.util.concurrent.ConcurrentHashMap
11 |
12 | /***
13 | * 要在Java中跨平台的获取真正的首选出站ip,只能用这种极其恶心的写法
14 | */
15 | @Component
16 | class NetworkWatcher : Thread() {
17 |
18 | private val logger = LoggerFactory.getLogger(NetworkWatcher::class.java)
19 |
20 | @Autowired
21 | private lateinit var addressProvider: LANAddressProvider
22 |
23 | @Autowired
24 | private lateinit var context: ApplicationContext
25 |
26 | @Autowired
27 | private lateinit var attributes: ConcurrentHashMap
28 |
29 | private var last: String? = null
30 |
31 | override fun run() {
32 | while (true) {
33 | val host = addressProvider.get()?.hostAddress
34 | if (host.isNullOrEmpty()) {
35 | logger.error("No suitable \"host\" address was found, please check your LAN connection or use ifconfig / ipconfig to retrieve a useful local IP address.")
36 | } else {
37 | if (host != attributes["host"]) {
38 | attributes["host"] = host
39 | logger.info("now host:${host}")
40 | context.publishEvent(NetworkChangedEvent(this, host))
41 | }
42 | }
43 | sleep(1000)
44 | }
45 | }
46 |
47 | @EventListener
48 | fun onInitialized(event: WebServerInitializedEvent) {
49 | start()
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/lan/LANAddressProvider.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.handshake.lan
2 |
3 | import java.net.InetAddress
4 |
5 | interface LANAddressProvider {
6 | fun get(): InetAddress?
7 | }
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/lan/OtherLANAddressProvider.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.handshake.lan
2 |
3 | import java.net.DatagramSocket
4 | import java.net.InetAddress
5 |
6 | class OtherLANAddressProvider : LANAddressProvider {
7 | override fun get(): InetAddress? {
8 | return DatagramSocket().use {
9 | it.connect(InetAddress.getByName("8.8.8.8"), 10086)
10 | it.localAddress
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/ui/ImageView.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.handshake.ui
2 |
3 | import java.awt.Graphics
4 | import java.awt.image.BufferedImage
5 | import javax.swing.JComponent
6 |
7 | class ImageView : JComponent() {
8 |
9 | var image: BufferedImage? = null
10 | set(value) {
11 | field = value
12 | repaint()
13 | }
14 |
15 | override fun paintComponent(g: Graphics) {
16 | image.let {
17 | g.drawImage(image, 0, 0, width, height, null)
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/ui/QrcodeFormManager.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.handshake.ui
2 |
3 | import com.guet.flexbox.handshake.NetworkChangedEvent
4 | import org.springframework.beans.factory.annotation.Autowired
5 | import org.springframework.boot.web.context.WebServerInitializedEvent
6 | import org.springframework.context.event.EventListener
7 | import org.springframework.stereotype.Component
8 | import java.awt.EventQueue
9 |
10 | @Component
11 | class QrcodeFormManager {
12 |
13 | @Autowired
14 | private var qrcodeForm: QrcodeForm? = null
15 |
16 | @EventListener
17 | fun onInitialized(event: WebServerInitializedEvent) {
18 | qrcodeForm?.start()
19 | }
20 |
21 | @EventListener
22 | fun onNetworkChanged(event: NetworkChangedEvent) {
23 | EventQueue.invokeLater {
24 | qrcodeForm?.notifyChanged(event.host)
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/handshake/src/main/kotlin/com/guet/flexbox/handshake/ui/QrcodeImageUtils.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.handshake.ui
2 |
3 | import com.google.zxing.BarcodeFormat
4 | import com.google.zxing.EncodeHintType
5 | import com.google.zxing.WriterException
6 | import com.google.zxing.qrcode.QRCodeWriter
7 | import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
8 | import java.awt.Color
9 | import java.awt.Graphics2D
10 | import java.awt.image.BufferedImage
11 |
12 | object QrcodeImageUtils {
13 | fun buildImage(
14 | content: String,
15 | size: Int
16 | ): BufferedImage {
17 | try {
18 | val hintMap = HashMap()
19 | hintMap[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L
20 | val qrCodeWriter = QRCodeWriter()
21 | val byteMatrix = qrCodeWriter.encode(
22 | content,
23 | BarcodeFormat.QR_CODE, size, size, hintMap
24 | )
25 | val width = byteMatrix.width
26 | val image = BufferedImage(
27 | width,
28 | width,
29 | BufferedImage.TYPE_INT_RGB
30 | )
31 | val graphics = image.createGraphics() as Graphics2D
32 | graphics.color = Color.WHITE
33 | graphics.fillRect(0, 0, width, width)
34 | graphics.color = Color.BLACK
35 |
36 | for (i in 0 until width) {
37 | for (j in 0 until width) {
38 | if (byteMatrix.get(i, j)) {
39 | graphics.fillRect(i, j, 1, 1)
40 | }
41 | }
42 | }
43 | return image
44 | } catch (e: WriterException) {
45 | throw RuntimeException(e)
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/handshake/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.tomcat.max-threads=10
2 | server.address=0.0.0.0
3 | spring.http.converters.preferred-json-mapper=gson
--------------------------------------------------------------------------------
/handshake/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%logger{32}] %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/handshake/src/main/resources/static/background.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | background
7 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/handshake/src/main/resources/static/fire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/handshake/src/main/resources/static/fire.png
--------------------------------------------------------------------------------
/handshake/src/main/resources/static/icon-big.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/handshake/src/main/resources/static/icon-big.png
--------------------------------------------------------------------------------
/handshake/src/main/resources/static/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/handshake/src/main/resources/static/icon.png
--------------------------------------------------------------------------------
/handshake/src/main/resources/static/json.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/handshake/src/main/resources/static/json.png
--------------------------------------------------------------------------------
/handshake/src/main/resources/static/qrcode_loading.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/handshake/src/main/resources/static/qrcode_loading.jpg
--------------------------------------------------------------------------------
/intellij-plugin/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/intellij-plugin/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /workspace.xml
--------------------------------------------------------------------------------
/intellij-plugin/.idea/codeStyles:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/intellij-plugin/.idea/dictionaries/Luke.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | flexml
5 |
6 |
7 |
--------------------------------------------------------------------------------
/intellij-plugin/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/intellij-plugin/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/intellij-plugin/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/intellij-plugin/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/intellij-plugin/README.md:
--------------------------------------------------------------------------------
1 | ## intellij 插件
2 | ### 1 这是什么?
3 | 这是Flexml的intellij平台插件,适用于Android Studio和IDEA。
4 |
5 | ### 2 我要你的代码
6 | 如果需要修改源码和自行编译,请用IDEA打开(否则编译不了不要怪我😂)。Jetbrains还没有开放在Android Studio上编写intellij平台插件的功能。
7 | ### 3 我想直接使用
8 | 请看[wiki](https://github.com/sanyuankexie/Flexml/wiki/环境配置)。
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/intellij-plugin/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | kotlinVersion = '1.3.61'
4 | }
5 | repositories {
6 | google()
7 | jcenter()
8 | mavenCentral()
9 | maven { url "https://jitpack.io" }
10 | maven { url "https://plugins.gradle.org/m2/" }
11 | }
12 | dependencies {
13 | classpath 'org.jetbrains.intellij:org.jetbrains.intellij.gradle.plugin:0.4.15'
14 |
15 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"
16 |
17 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
18 |
19 | }
20 | }
21 |
22 | allprojects {
23 | repositories {
24 | google()
25 | jcenter()
26 | mavenCentral()
27 | maven { url "https://jitpack.io" }
28 | }
29 | }
30 |
31 |
32 | apply plugin: 'java'
33 | apply plugin: 'kotlin'
34 | apply plugin: 'org.jetbrains.intellij'
35 |
36 |
37 | group = 'com.guet.flexbox'
38 |
39 | def taskOutput(String name, String task) {
40 | project(name).getTasksByName(task, false)
41 | .first()
42 | .outputs
43 | .files
44 | }
45 |
46 | dependencies {
47 | implementation fileTree(dir: 'libs', include: ['*.jar'])
48 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${kotlinVersion}"
49 | implementation taskOutput(":compiler", "shadowJar")
50 | implementation taskOutput(":handshake", "bootJar")
51 | testImplementation group: 'junit', name: 'junit', version: '4.12'
52 | }
53 |
54 | sourceCompatibility = JavaVersion.VERSION_1_8
55 | targetCompatibility = JavaVersion.VERSION_1_8
56 |
57 | compileKotlin {
58 | kotlinOptions.jvmTarget = "1.8"
59 | }
60 | compileTestKotlin {
61 | kotlinOptions.jvmTarget = "1.8"
62 | }
63 |
64 |
65 | intellij {
66 | version '2018.3.1'
67 | updateSinceUntilBuild false
68 | //plugins = ['java']
69 | }
70 |
--------------------------------------------------------------------------------
/intellij-plugin/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/intellij-plugin/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/intellij-plugin/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/intellij-plugin/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "intellij-plugin"
2 | void external(String... names) {
3 | names.toList().forEach({ name ->
4 | String pName = ':' + name
5 | include(pName)
6 | project(pName).projectDir = new File(settingsDir, '../' + name)
7 | })
8 | }
9 |
10 | external 'compiler', 'beans', 'handshake'
11 |
12 |
--------------------------------------------------------------------------------
/intellij-plugin/src/main/java/com/guet/flexbox/intellij/ui/CompileSettingFormBase.java:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.ui;
2 |
3 | import com.guet.flexbox.intellij.configuration.CompileRunConfiguration;
4 | import com.intellij.openapi.options.SettingsEditor;
5 |
6 | import javax.swing.JPanel;
7 | import javax.swing.JTextField;
8 |
9 | public abstract class CompileSettingFormBase extends SettingsEditor
10 | {
11 | public JPanel wrapPanel;
12 | public JTextField template;
13 | public JTextField output;
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/intellij-plugin/src/main/java/com/guet/flexbox/intellij/ui/MockSettingFormBase.java:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.ui;
2 |
3 | import com.guet.flexbox.intellij.configuration.MockRunConfiguration;
4 | import com.intellij.openapi.options.SettingsEditor;
5 |
6 | import javax.swing.*;
7 |
8 | public abstract class MockSettingFormBase extends SettingsEditor
9 | {
10 | public JPanel wrapPanel;
11 | public JTextField port;
12 | public JTextField packageJson;
13 |
14 | public MockSettingFormBase(){
15 | port.setInputVerifier(new InputVerifier() {
16 | @Override
17 | public boolean verify(JComponent input) {
18 | try {
19 | Integer.parseInt(port.getText());
20 | return true;
21 | }catch (Exception e){
22 | return false;
23 | }
24 | }
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij
2 |
3 | import com.guet.flexbox.intellij.fileType.FlexmlFileType
4 | import com.intellij.psi.PsiElement
5 | import java.util.regex.Pattern
6 |
7 | val PsiElement.isOnFlexmlFile: Boolean
8 | get() {
9 | return if (this.containingFile != null) {
10 | this.containingFile.name
11 | .endsWith("." + FlexmlFileType.defaultExtension,
12 | ignoreCase = true
13 | )
14 | } else {
15 | false
16 | }
17 | }
18 |
19 | private val pattern = Pattern.compile(
20 | "http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?"
21 | )
22 |
23 | val String.isUrl: Boolean
24 | get() {
25 | return pattern.matcher(this).matches()
26 | }
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/action/NewFlexmlAction.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.action
2 |
3 | import com.guet.flexbox.intellij.res.Icons
4 | import com.guet.flexbox.intellij.fileType.FlexmlFileType
5 | import com.intellij.CommonBundle
6 | import com.intellij.ide.actions.CreateElementActionBase
7 | import com.intellij.ide.fileTemplates.FileTemplateManager
8 | import com.intellij.openapi.project.Project
9 | import com.intellij.openapi.ui.Messages
10 | import com.intellij.psi.PsiDirectory
11 | import com.intellij.psi.PsiElement
12 | import com.intellij.psi.PsiFileFactory
13 | import com.intellij.psi.codeStyle.CodeStyleManager
14 |
15 | class NewFlexmlAction : CreateElementActionBase("", "", Icons.typeIcon) {
16 |
17 | override fun invokeDialog(project: Project?, directory: PsiDirectory?): Array {
18 | val inputValidator = this.MyInputValidator(project, directory)
19 | Messages.showInputDialog(
20 | project,
21 | "New a flexml dsl file",
22 | "New a flexml dsl file",
23 | null,
24 | "",
25 | inputValidator
26 | )
27 | return inputValidator.createdElements
28 | }
29 |
30 | override fun create(newName: String, directory: PsiDirectory): Array {
31 | val ext = ".${FlexmlFileType.defaultExtension}"
32 | val filename = if (newName.endsWith(ext)) {
33 | newName
34 | } else {
35 | newName + ext
36 | }
37 | val template = FileTemplateManager.getInstance(directory.project)
38 | .getInternalTemplate("flexml-file")
39 | val text = template.text
40 | val factory = PsiFileFactory.getInstance(directory.project)
41 | val file = factory.createFileFromText(filename, FlexmlFileType, text)
42 | CodeStyleManager.getInstance(directory.project).reformat(file)
43 | directory.add(file)
44 | return arrayOf(file)
45 | }
46 |
47 | override fun getActionName(directory: PsiDirectory?, newName: String?): String = "Flexml File"
48 |
49 | override fun getCommandName(): String = "Create Flexml File"
50 |
51 | override fun getErrorTitle(): String = CommonBundle.getErrorTitle()
52 |
53 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/completion/FlexmlComponentNameProvider.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.completion
2 |
3 | import com.guet.flexbox.intellij.res.ComponentInfoBundle
4 | import com.guet.flexbox.intellij.res.Icons
5 | import com.guet.flexbox.intellij.isOnFlexmlFile
6 | import com.intellij.codeInsight.completion.XmlTagInsertHandler
7 | import com.intellij.codeInsight.lookup.LookupElement
8 | import com.intellij.codeInsight.lookup.LookupElementBuilder
9 | import com.intellij.psi.impl.source.xml.DefaultXmlTagNameProvider
10 | import com.intellij.psi.xml.XmlTag
11 |
12 | class FlexmlComponentNameProvider : DefaultXmlTagNameProvider() {
13 |
14 | private val allTags = ComponentInfoBundle.allComponentNames.map {
15 | LookupElementBuilder.create(it)
16 | .withInsertHandler(XmlTagInsertHandler.INSTANCE)
17 | .withBoldness(true)
18 | .withIcon(Icons.tagIcon)
19 | .withTypeText("flexml component")
20 | }
21 |
22 | override fun addTagNameVariants(
23 | elements: MutableList,
24 | tag: XmlTag,
25 | prefix: String?
26 | ) {
27 | super.addTagNameVariants(elements, tag, prefix)
28 | if (!tag.isOnFlexmlFile) {
29 | return
30 | }
31 | if (tag.parentTag?.name == "when") {
32 | elements.addAll(
33 | listOf(
34 | LookupElementBuilder.create("case")
35 | .withInsertHandler(XmlTagInsertHandler.INSTANCE)
36 | .withBoldness(true)
37 | .withIcon(Icons.tagIcon)
38 | .withTypeText("flexml component"),
39 | LookupElementBuilder.create("else")
40 | .withInsertHandler(XmlTagInsertHandler.INSTANCE)
41 | .withBoldness(true)
42 | .withIcon(Icons.tagIcon)
43 | .withTypeText("flexml component")
44 | )
45 | )
46 | } else {
47 | elements.addAll(allTags)
48 | }
49 | }
50 | }
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/configuration/CompileRunConfiguration.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.configuration
2 |
3 | import com.guet.flexbox.intellij.configuration.options.CompileOptions
4 | import com.guet.flexbox.intellij.service.JarStartupManager
5 | import com.guet.flexbox.intellij.ui.CompileSettingForm
6 | import com.intellij.execution.Executor
7 | import com.intellij.execution.configurations.*
8 | import com.intellij.execution.runners.ExecutionEnvironment
9 | import com.intellij.openapi.options.SettingsEditor
10 | import com.intellij.openapi.project.Project
11 |
12 | class CompileRunConfiguration(
13 | project: Project,
14 | factory: ConfigurationFactory
15 | ) : LocatableConfigurationBase(
16 | project,
17 | factory,
18 | "Compile this template"
19 | ) {
20 | override fun getConfigurationEditor(): SettingsEditor = CompileSettingForm()
21 | override fun getState(
22 | executor: Executor,
23 | environment: ExecutionEnvironment
24 | ): RunProfileState? {
25 | val input = state!!.template!!
26 | val output = state!!.output!!
27 | return JarStartupManager.getInstance(project)
28 | .runCompiler(environment, input, output)
29 | }
30 |
31 | override fun getOptionsClass(): Class? {
32 | return CompileOptions::class.java
33 | }
34 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/configuration/MockRunConfiguration.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.configuration
2 |
3 | import com.guet.flexbox.intellij.configuration.options.MockOptions
4 | import com.guet.flexbox.intellij.service.JarStartupManager
5 | import com.guet.flexbox.intellij.ui.MockSettingForm
6 | import com.intellij.execution.Executor
7 | import com.intellij.execution.configurations.*
8 | import com.intellij.execution.runners.ExecutionEnvironment
9 | import com.intellij.openapi.options.SettingsEditor
10 | import com.intellij.openapi.project.Project
11 |
12 | class MockRunConfiguration(project: Project, factory: ConfigurationFactory) :
13 | LocatableConfigurationBase(project, factory, "Mock this package") {
14 |
15 | override fun getConfigurationEditor(): SettingsEditor = MockSettingForm()
16 |
17 | override fun getState(
18 | executor: Executor,
19 | environment: ExecutionEnvironment
20 | ): RunProfileState? {
21 | val port = state!!.port
22 | val focus = state!!.packageJson!!
23 | return JarStartupManager.getInstance(project)
24 | .runMockServer(environment, focus, port)
25 | }
26 |
27 | override fun getOptionsClass(): Class? {
28 | return MockOptions::class.java
29 | }
30 |
31 |
32 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/configuration/options/CompileOptions.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.configuration.options
2 |
3 | import com.intellij.execution.configurations.LocatableRunConfigurationOptions
4 |
5 | class CompileOptions : LocatableRunConfigurationOptions() {
6 | var template: String? by string()
7 | var output: String? by string()
8 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/configuration/options/MockOptions.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.configuration.options
2 |
3 | import com.intellij.execution.configurations.LocatableRunConfigurationOptions
4 |
5 | class MockOptions : LocatableRunConfigurationOptions() {
6 |
7 | var port: Int by property(defaultValue = 8080)
8 |
9 | var packageJson: String? by string()
10 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/configuration/type/CompileConfigurationType.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.configuration.type
2 |
3 | import com.guet.flexbox.intellij.res.Icons
4 | import com.guet.flexbox.intellij.configuration.CompileRunConfiguration
5 | import com.intellij.execution.configurations.RunConfiguration
6 | import com.intellij.execution.configurations.SimpleConfigurationType
7 | import com.intellij.openapi.project.Project
8 | import com.intellij.openapi.util.NotNullLazyValue
9 |
10 | class CompileConfigurationType : SimpleConfigurationType(
11 | "FlexmlCompile",
12 | "Flexml compile",
13 | "begin run flexml compile task",
14 | NotNullLazyValue.createValue {
15 | Icons.typeIcon
16 | }
17 | ) {
18 | override fun createTemplateConfiguration(
19 | project: Project
20 | ): RunConfiguration {
21 | return CompileRunConfiguration(project, this)
22 | }
23 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/configuration/type/MockConfigurationType.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.configuration.type
2 |
3 | import com.guet.flexbox.intellij.res.Icons
4 | import com.guet.flexbox.intellij.configuration.MockRunConfiguration
5 | import com.intellij.execution.configurations.RunConfiguration
6 | import com.intellij.execution.configurations.SimpleConfigurationType
7 | import com.intellij.openapi.project.Project
8 | import com.intellij.openapi.util.NotNullLazyValue
9 |
10 | class MockConfigurationType : SimpleConfigurationType(
11 | "FlexmlMock",
12 | "Flexml mock",
13 | "begin run flexml mock task",
14 | NotNullLazyValue.createValue {
15 | Icons.typeIcon
16 | }
17 | ) {
18 |
19 | override fun createTemplateConfiguration(
20 | project: Project
21 | ): RunConfiguration {
22 | return MockRunConfiguration(project, this)
23 | }
24 |
25 |
26 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/fileType/FlexmlFileType.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.fileType
2 |
3 | import com.guet.flexbox.intellij.res.Icons
4 | import com.intellij.ide.highlighter.XmlLikeFileType
5 | import com.intellij.lang.xml.XMLLanguage
6 | import javax.swing.Icon
7 |
8 | object FlexmlFileType : XmlLikeFileType(XMLLanguage.INSTANCE) {
9 |
10 | override fun getIcon(): Icon = Icons.typeIcon
11 |
12 | override fun getName(): String = "flexml dsl"
13 |
14 | override fun getDefaultExtension(): String = "flexml"
15 |
16 | override fun getDescription(): String = "flexml style dsl file"
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/fileType/FlexmlFileTypeFactory.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.fileType
2 |
3 | import com.intellij.openapi.fileTypes.FileTypeConsumer
4 | import com.intellij.openapi.fileTypes.FileTypeFactory
5 |
6 | class FlexmlFileTypeFactory : FileTypeFactory() {
7 | override fun createFileTypes(consumer: FileTypeConsumer) {
8 | consumer.consume(FlexmlFileType)
9 | }
10 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/lineMarker/CompileRunLineMarkerContributor.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.lineMarker
2 |
3 | import com.guet.flexbox.intellij.isOnFlexmlFile
4 | import com.intellij.execution.lineMarker.ExecutorAction
5 | import com.intellij.execution.lineMarker.RunLineMarkerContributor
6 | import com.intellij.icons.AllIcons
7 | import com.intellij.openapi.actionSystem.AnAction
8 | import com.intellij.openapi.util.text.StringUtil
9 | import com.intellij.psi.PsiElement
10 | import com.intellij.psi.xml.XmlFile
11 | import com.intellij.util.containers.ContainerUtil
12 |
13 | class CompileRunLineMarkerContributor : RunLineMarkerContributor() {
14 | override fun getInfo(element: PsiElement): Info? {
15 | if (!element.isOnFlexmlFile) {
16 | return null
17 | }
18 | val file = element.containingFile
19 | if (file is XmlFile) {
20 | if (file.document == element) {
21 | val actions = ExecutorAction.getActions()
22 | return Info(
23 | AllIcons.RunConfigurations.TestState.Run,
24 | actions
25 | ) { e ->
26 | StringUtil.join(ContainerUtil.mapNotNull(actions) { action ->
27 | getText(
28 | action,
29 | e
30 | )
31 | }, "\n")
32 |
33 | }
34 | }
35 | }
36 | return null
37 | }
38 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/lineMarker/MockRunLineMarkerContributor.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.lineMarker
2 |
3 | import com.guet.flexbox.intellij.isOnFlexmlFile
4 | import com.intellij.execution.lineMarker.ExecutorAction
5 | import com.intellij.execution.lineMarker.RunLineMarkerContributor
6 | import com.intellij.icons.AllIcons
7 | import com.intellij.json.psi.JsonFile
8 | import com.intellij.json.psi.JsonObject
9 | import com.intellij.json.psi.JsonStringLiteral
10 | import com.intellij.openapi.actionSystem.AnAction
11 | import com.intellij.openapi.util.text.StringUtil
12 | import com.intellij.psi.PsiElement
13 | import com.intellij.util.containers.ContainerUtil
14 |
15 | class MockRunLineMarkerContributor : RunLineMarkerContributor() {
16 |
17 | override fun getInfo(element: PsiElement): Info? {
18 | val file = element.containingFile?.let { it as? JsonFile }
19 | val obj = file?.topLevelValue?.let { it as? JsonObject }
20 | if (file?.name != "package.json") {
21 | return null
22 | }
23 | val template = obj?.findProperty("template")
24 | ?: return null
25 | if (template != element) {
26 | return null
27 | }
28 | if (template.value?.let { it as? JsonStringLiteral }
29 | ?.value?.let { file.parent?.findFile(it) }
30 | ?.isOnFlexmlFile == true) {
31 | val actions = ExecutorAction.getActions()
32 | return Info(
33 | AllIcons.RunConfigurations.TestState.Run,
34 | actions
35 | ) { e ->
36 | StringUtil.join(ContainerUtil.mapNotNull(actions) { action ->
37 | getText(
38 | action,
39 | e
40 | )
41 | }, "\n")
42 |
43 | }
44 | }
45 | return null
46 | }
47 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/res/AttributeInfo.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.res
2 |
3 | data class AttributeInfo(
4 | val required: Boolean,
5 | val support: List?,
6 | val values: List?
7 | )
8 |
9 |
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/res/ComponentGroup.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.res
2 |
3 | data class ComponentGroup(
4 | val components: List
5 | )
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/res/ComponentInfo.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.res
2 |
3 | data class ComponentInfo(
4 | val abstract: Boolean,
5 | val parent: String?,
6 | val name: String,
7 | val attrs: Map?
8 | )
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/res/ComponentInfoBundle.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.res
2 |
3 | import com.google.gson.Gson
4 |
5 | object ComponentInfoBundle {
6 |
7 | private val components: Map?>
8 |
9 | init {
10 | val gson = Gson()
11 | val classLoader = javaClass.classLoader
12 | val group = classLoader.getResourceAsStream(
13 | "flexml-components/package.json"
14 | )!!.reader()
15 | val arr = gson.fromJson(
16 | group, ComponentGroup::class.java
17 | ).components
18 | group.close()
19 | val componentInfoArray = arr.map {
20 | val input = classLoader.getResourceAsStream(it)!!.reader()
21 | val r = gson.fromJson(input, ComponentInfo::class.java)
22 | input.close()
23 | return@map r
24 | }
25 |
26 | fun loadAttribute(
27 | result: HashMap,
28 | com: ComponentInfo
29 | ) {
30 | com.attrs?.let {
31 | result.putAll(it)
32 | }
33 | val parent = com.parent?.let { name ->
34 | componentInfoArray.first {
35 | name == it.name
36 | }
37 | }
38 | if (parent == null) {
39 | return
40 | } else {
41 | loadAttribute(result, parent)
42 | }
43 | }
44 | components = componentInfoArray.filter { !it.abstract }
45 | .map {
46 | val map = HashMap()
47 | loadAttribute(map, it)
48 | it.name to map
49 | }.toMap()
50 | }
51 |
52 | val allComponentNames: Set
53 | get() = components.keys
54 |
55 | fun getAttributeInfoByComponentName(name: String): Map {
56 | return components[name] ?: emptyMap()
57 | }
58 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/res/Icons.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.res
2 |
3 | import com.intellij.openapi.util.IconLoader
4 |
5 | object Icons {
6 |
7 | val typeIcon by lazy {
8 | IconLoader.getIcon("/icons/icon_type.png")
9 | }
10 |
11 | val tagIcon by lazy {
12 | IconLoader.getIcon("/icons/icon_tag.png")
13 | }
14 |
15 | val colors: Map by lazy {
16 | HashMap().apply {
17 | this["black"] = 0xFF000000.toInt()
18 | this["darkgray"] = 0xFF444444.toInt()
19 | this["gray"] = 0xFF888888.toInt()
20 | this["lightgray"] = 0xFFCCCCCC.toInt()
21 | this["white"] = 0xFFFFFFFF.toInt()
22 | this["red"] = 0xFFFF0000.toInt()
23 | this["green"] = 0xFF00FF00.toInt()
24 | this["blue"] = 0xFF0000FF.toInt()
25 | this["yellow"] = 0xFFFFFF00.toInt()
26 | this["cyan"] = 0xFF00FFFF.toInt()
27 | this["magenta"] = 0xFFFF00FF.toInt()
28 | this["aqua"] = 0xFF00FFFF.toInt()
29 | this["fuchsia"] = 0xFFFF00FF.toInt()
30 | this["lime"] = 0xFF00FF00.toInt()
31 | this["maroon"] = 0xFF800000.toInt()
32 | this["navy"] = 0xFF000080.toInt()
33 | this["olive"] = 0xFF808000.toInt()
34 | this["purple"] = 0xFF800080.toInt()
35 | this["silver"] = 0xFFC0C0C0.toInt()
36 | this["teal"] = 0xFF008080.toInt()
37 | }
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/res/SupportType.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.res
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | enum class SupportType {
6 | @SerializedName("colors")
7 | COLORS,
8 | @SerializedName("url")
9 | URL,
10 | @SerializedName("values")
11 | VALUES,
12 | @SerializedName("bool")
13 | BOOL
14 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/service/JarStartupManager.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.service
2 |
3 | import com.intellij.execution.configurations.RunProfileState
4 | import com.intellij.execution.runners.ExecutionEnvironment
5 | import com.intellij.openapi.components.ServiceManager
6 | import com.intellij.openapi.project.Project
7 |
8 | interface JarStartupManager {
9 |
10 | fun runCompiler(
11 | environment: ExecutionEnvironment,
12 | input: String,
13 | output: String
14 | ): RunProfileState
15 |
16 | fun runMockServer(
17 | environment: ExecutionEnvironment,
18 | focus: String,
19 | port: Int
20 | ): RunProfileState
21 |
22 | companion object {
23 | fun getInstance(project: Project): JarStartupManager {
24 | return ServiceManager.getService(project, JarStartupManager::class.java)
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/ui/CompileSettingForm.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.ui
2 |
3 | import com.guet.flexbox.intellij.configuration.CompileRunConfiguration
4 | import javax.swing.JComponent
5 |
6 | class CompileSettingForm : CompileSettingFormBase() {
7 | override fun resetEditorFrom(s: CompileRunConfiguration) {
8 | template.text = s.state?.template
9 | output.text = s.state?.output
10 | }
11 |
12 | override fun createEditor(): JComponent {
13 | return wrapPanel
14 | }
15 |
16 | override fun applyEditorTo(s: CompileRunConfiguration) {
17 | s.state?.template = template.text
18 | s.state?.output = output.text
19 | }
20 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/kotlin/com/guet/flexbox/intellij/ui/MockSettingForm.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.intellij.ui
2 |
3 | import com.guet.flexbox.intellij.configuration.MockRunConfiguration
4 | import javax.swing.JComponent
5 |
6 | class MockSettingForm : MockSettingFormBase() {
7 |
8 | override fun resetEditorFrom(s: MockRunConfiguration) {
9 | this.port.text = s.state?.port.toString()
10 | this.packageJson.text = s.state?.packageJson
11 | }
12 |
13 | override fun createEditor(): JComponent {
14 | return this.wrapPanel
15 | }
16 |
17 | override fun applyEditorTo(s: MockRunConfiguration) {
18 | s.state?.port = this.port.text.toInt()
19 | s.state?.packageJson = this.packageJson.text
20 | }
21 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/fileTemplates/internal/flexml-file.flexml.ft:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/fileTemplates/internal/package.json.ft:
--------------------------------------------------------------------------------
1 | {
2 | "template": "template.flexml",
3 | "data": "data.json"
4 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/abs-text.json:
--------------------------------------------------------------------------------
1 | {
2 | "abstract": true,
3 | "parent": "Common",
4 | "name": "AbstractText",
5 | "attrs": {
6 | "verticalGravity": {
7 | "support": [
8 | "values"
9 | ],
10 | "values": [
11 | "top",
12 | "bottom",
13 | "center"
14 | ]
15 | },
16 | "horizontalGravity": {
17 | "support": [
18 | "values"
19 | ],
20 | "values": [
21 | "left",
22 | "right",
23 | "center"
24 | ]
25 | },
26 | "ellipsize": {
27 | "support": [
28 | "values"
29 | ],
30 | "values": [
31 | "start",
32 | "end",
33 | "middle",
34 | "marquee"
35 | ]
36 | },
37 | "maxLines": null,
38 | "minLines": null,
39 | "textStyle": {
40 | "support": [
41 | "values"
42 | ],
43 | "values": [
44 | "normal",
45 | "bold"
46 | ]
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/banner.json:
--------------------------------------------------------------------------------
1 | {
2 | "parent": "Common",
3 | "name": "Banner",
4 | "attrs": {
5 | "isCircular": {
6 | "support": [
7 | "bool"
8 | ]
9 | },
10 | "timeSpan": null,
11 | "orientation": {
12 | "support": [
13 | "values"
14 | ],
15 | "values": [
16 | "vertical",
17 | "horizontal"
18 | ]
19 | },
20 | "indicatorEnable": {
21 | "support": [
22 | "bool"
23 | ]
24 | },
25 | "indicatorHeight": null,
26 | "indicatorSize": null,
27 | "indicatorSelected": {
28 | "support": [
29 | "colors"
30 | ]
31 | },
32 | "indicatorUnselected": {
33 | "support": [
34 | "colors"
35 | ]
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/common.json:
--------------------------------------------------------------------------------
1 | {
2 | "abstract": true,
3 | "name": "Common",
4 | "attrs": {
5 | "visibility": {
6 | "support": [
7 | "values"
8 | ],
9 | "values": [
10 | "visible",
11 | "invisible",
12 | "gone"
13 | ]
14 | },
15 | "width": null,
16 | "height": null,
17 | "minWidth": null,
18 | "maxWidth": null,
19 | "minHeight": null,
20 | "maxHeight": null,
21 | "flexGrow": null,
22 | "flexShrink": null,
23 | "alignSelf": {
24 | "support": [
25 | "values"
26 | ],
27 | "values": [
28 | "auto",
29 | "flexStart",
30 | "flexEnd",
31 | "center",
32 | "baseline",
33 | "stretch"
34 | ]
35 | },
36 | "margin": null,
37 | "marginTop": null,
38 | "marginLeft": null,
39 | "marginRight": null,
40 | "marginBottom": null,
41 | "padding": null,
42 | "paddingTop": null,
43 | "paddingLeft": null,
44 | "paddingRight": null,
45 | "paddingBottom": null,
46 | "borderColor": {
47 | "support": [
48 | "colors"
49 | ]
50 | },
51 | "borderRadius": null,
52 | "borderLeftTopRadius": null,
53 | "borderRightTopRadius": null,
54 | "borderLeftBottomRadius": null,
55 | "borderRightBottomRadius": null,
56 | "borderWidth": null,
57 | "background": {
58 | "support": [
59 | "colors",
60 | "url"
61 | ]
62 | },
63 | "clickUrl": {
64 | "support": [
65 | "url"
66 | ]
67 | },
68 | "onClick": null,
69 | "onView": null
70 | }
71 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "parent": "Common",
3 | "name": "Empty"
4 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/flex.json:
--------------------------------------------------------------------------------
1 | {
2 | "parent": "Common",
3 | "name": "Flex",
4 | "attrs": {
5 | "flexWrap": {
6 | "support": [
7 | "values"
8 | ],
9 | "values": [
10 | "wrap",
11 | "noWrap",
12 | "wrapReverse"
13 | ]
14 | },
15 | "justifyContent": {
16 | "support": [
17 | "values"
18 | ],
19 | "values": [
20 | "flexStart",
21 | "flexEnd",
22 | "center",
23 | "spaceBetween",
24 | "spaceAround"
25 | ]
26 | },
27 | "alignItems": {
28 | "support": [
29 | "values"
30 | ],
31 | "values": [
32 | "auto",
33 | "flexStart",
34 | "flexEnd",
35 | "center",
36 | "baseline",
37 | "stretch"
38 | ]
39 | },
40 | "alignContent": {
41 | "support": [
42 | "values"
43 | ],
44 | "values": [
45 | "auto",
46 | "flexStart",
47 | "flexEnd",
48 | "center",
49 | "baseline",
50 | "stretch"
51 | ]
52 | },
53 | "flexDirection": {
54 | "support": [
55 | "values"
56 | ],
57 | "values": [
58 | "row",
59 | "column",
60 | "rowReverse",
61 | "columnReverse"
62 | ]
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/for-each.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "foreach",
3 | "attrs": {
4 | "var": null,
5 | "items": {
6 | "required": true
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/for.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "for",
3 | "attrs": {
4 | "var": null,
5 | "from": {
6 | "required": true
7 | },
8 | "to": {
9 | "required": true
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/if.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "if",
3 | "attrs": {
4 | "test": {
5 | "required": true
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/image.json:
--------------------------------------------------------------------------------
1 | {
2 | "parent": "Common",
3 | "name": "Image",
4 | "attrs": {
5 | "scaleType": {
6 | "support": [
7 | "values"
8 | ],
9 | "values": [
10 | "center",
11 | "fitCenter",
12 | "fitXY",
13 | "fitStart",
14 | "fitEnd",
15 | "centerInside",
16 | "centerCrop"
17 | ]
18 | },
19 | "blurRadius": null,
20 | "blurSampling": null,
21 | "src": {
22 | "required": true
23 | },
24 | "aspectRatio": null
25 | }
26 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "components": [
3 | "flexml-components/common.json",
4 | "flexml-components/abs-text.json",
5 | "flexml-components/text.json",
6 | "flexml-components/text-input.json",
7 | "flexml-components/empty.json",
8 | "flexml-components/flex.json",
9 | "flexml-components/when.json",
10 | "flexml-components/for.json",
11 | "flexml-components/for-each.json",
12 | "flexml-components/stack.json",
13 | "flexml-components/image.json",
14 | "flexml-components/banner.json",
15 | "flexml-components/scroller.json",
16 | "flexml-components/if.json"
17 | ]
18 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/scroller.json:
--------------------------------------------------------------------------------
1 | {
2 | "parent": "Common",
3 | "name": "Scroller",
4 | "attrs": {
5 | "scrollBarEnable": {
6 | "support": ["bool"]
7 | },
8 | "orientation": {
9 | "support": ["values"],
10 | "values": [
11 | "vertical",
12 | "horizontal"
13 | ]
14 | },
15 | "fillViewport": {
16 | "support": ["bool"]
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/stack.json:
--------------------------------------------------------------------------------
1 | {
2 | "parent": "Common",
3 | "name": "Stack"
4 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/text-input.json:
--------------------------------------------------------------------------------
1 | {
2 | "parent": "AbstractText",
3 | "name": "TextInput"
4 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/text.json:
--------------------------------------------------------------------------------
1 | {
2 | "parent": "AbstractText",
3 | "name": "Text",
4 | "attrs": {
5 | "text": {
6 | "required": true
7 | },
8 | "clipToBounds": {
9 | "support": [
10 | "bool"
11 | ]
12 | },
13 | "textColor": {
14 | "support": [
15 | "colors"
16 | ]
17 | },
18 | "textSize": null
19 | }
20 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/flexml-components/when.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "when"
3 | }
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/icons/icon_tag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/intellij-plugin/src/main/resources/icons/icon_tag.png
--------------------------------------------------------------------------------
/intellij-plugin/src/main/resources/icons/icon_type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/intellij-plugin/src/main/resources/icons/icon_type.png
--------------------------------------------------------------------------------
/litho/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/litho/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-kapt'
4 | apply plugin: 'com.github.dcendents.android-maven'
5 | group = 'com.guet.flexbox'
6 |
7 | ext {
8 | lithoVersion = '0.33.0'
9 | }
10 |
11 | android {
12 |
13 | compileSdkVersion 28
14 |
15 | defaultConfig {
16 | minSdkVersion 19
17 | targetSdkVersion 28
18 | versionCode 1
19 | versionName "1.0"
20 |
21 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
22 |
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 |
32 | compileOptions {
33 | sourceCompatibility JavaVersion.VERSION_1_7
34 | targetCompatibility JavaVersion.VERSION_1_7
35 | }
36 |
37 | }
38 |
39 |
40 | dependencies {
41 | implementation fileTree(dir: 'libs', include: ['*.jar'])
42 |
43 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${kotlinVersion}"
44 | //implementation 'androidx.appcompat:appcompat:1.1.0'
45 | implementation 'androidx.recyclerview:recyclerview:1.1.0'
46 | implementation 'androidx.viewpager2:viewpager2:1.0.0'
47 | implementation 'com.github.bumptech.glide:glide:4.11.0'
48 |
49 | //implementation 'com.yqritc:android-scalablevideoview:1.0.4'
50 |
51 | implementation 'com.facebook.yoga:yoga:1.16.0'
52 | implementation 'com.facebook.yoga:proguard-annotations:1.16.0'
53 | api "com.facebook.litho:litho-core:${lithoVersion}"
54 | api "com.facebook.litho:litho-widget:${lithoVersion}"
55 | implementation 'com.facebook.soloader:soloader:0.5.1'
56 |
57 | api project(':core')
58 |
59 | kapt 'com.facebook.litho:litho-processor:0.33.0'
60 | kapt 'com.github.bumptech.glide:compiler:4.11.0'
61 |
62 | testImplementation 'junit:junit:4.12'
63 | androidTestImplementation 'androidx.test:runner:1.2.0'
64 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
65 | }
66 |
--------------------------------------------------------------------------------
/litho/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 |
--------------------------------------------------------------------------------
/litho/src/androidTest/java/com/guet/flexbox/litho/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho;
2 |
3 | import android.content.Context;
4 | import android.os.MemoryFile;
5 | import android.os.SharedMemory;
6 |
7 | import androidx.test.InstrumentationRegistry;
8 | import androidx.test.runner.AndroidJUnit4;
9 |
10 | import org.junit.Test;
11 | import org.junit.runner.RunWith;
12 |
13 | import static org.junit.Assert.*;
14 |
15 | /**
16 | * Instrumented test, which will execute on an Android device.
17 | *
18 | * @see Testing documentation
19 | */
20 | @RunWith(AndroidJUnit4.class)
21 | public class ExampleInstrumentedTest {
22 | @Test
23 | public void useAppContext() {
24 |
25 | // Context of the app under test.
26 | Context appContext = InstrumentationRegistry.getTargetContext();
27 |
28 | assertEquals("com.guet.flexbox.litho.test", appContext.getPackageName());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/litho/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/LithoBuildTool.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho
2 |
3 | import android.content.Context
4 | import android.util.ArrayMap
5 | import com.facebook.yoga.YogaNodeManager
6 | import com.guet.flexbox.build.*
7 | import com.guet.flexbox.litho.drawable.load.DrawableLoaderModule
8 | import com.guet.flexbox.litho.factories.*
9 | import com.guet.flexbox.litho.widget.ComponentTreePool
10 |
11 | object LithoBuildTool : BuildTool() {
12 |
13 | override val widgets: Map by lazy {
14 | val arr = arrayOf(
15 | "Empty" to ToWidget(Empty, ToEmpty),
16 | "Flex" to ToWidget(Flex, ToFlex),
17 | "Banner" to ToWidget(Banner, ToBanner),
18 | "Image" to ToWidget(Image, ToImage),
19 | "Scroller" to ToWidget(Scroller, ToScroller),
20 | "TextInput" to ToWidget(TextInput, ToTextInput),
21 | "Text" to ToWidget(Text, ToText),
22 | "Stack" to ToWidget(CommonDefine, ToStack),
23 | "for" to ToWidget(For, null),
24 | "foreach" to ToWidget(ForEach, null),
25 | "when" to ToWidget(When, null),
26 | "if" to ToWidget(If, null)
27 | )
28 | arr.toMap(ArrayMap(arr.size))
29 | }
30 |
31 | override val kits: List by lazy {
32 | return@lazy listOf(
33 | YogaNodeManager,
34 | DrawableLoaderModule,
35 | ComponentTreePool
36 | )
37 | }
38 |
39 | @JvmStatic
40 | fun init(c: Context) {
41 | install(c)
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/LithoEventHandler.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho
2 |
3 | import com.facebook.litho.*
4 | import com.facebook.litho.widget.TextChangedEvent
5 | import com.guet.flexbox.eventsystem.ExternalEventReceiver
6 |
7 | internal class LithoEventHandler(
8 | private val target: ExternalEventReceiver
9 | ) : EventHandler(LithoEventHandler, 0) {
10 |
11 | override fun dispatchEvent(event: T) {
12 | when (event) {
13 | is ClickEvent -> {
14 | target.receive(event.view, null)
15 | }
16 | is TextChangedEvent -> {
17 | target.receive(event.view, arrayOf(event.text))
18 | }
19 | is VisibleEvent -> {
20 | target.receive(null, null)
21 | }
22 | }
23 | }
24 |
25 | override fun isEquivalentTo(other: EventHandler<*>?): Boolean {
26 | return other is LithoEventHandler && target == other.target
27 | }
28 |
29 | private companion object : HasEventDispatcher, EventDispatcher {
30 |
31 | override fun getEventDispatcher(): EventDispatcher = this
32 |
33 | override fun dispatchOnEvent(eventHandler: EventHandler?, eventState: Any?): Any? {
34 | eventHandler?.dispatchEvent(eventState)
35 | return null
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/ThreadPool.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho
2 |
3 | import android.os.Process
4 | import com.facebook.litho.LithoHandler
5 | import java.util.concurrent.*
6 | import java.util.concurrent.atomic.AtomicInteger
7 | import kotlin.concurrent.thread
8 | import kotlin.math.max
9 |
10 | internal object ThreadPool {
11 |
12 | private val count = AtomicInteger(0)
13 |
14 | private val factory = ThreadFactory {
15 | thread(name = "LayoutThread\$${count.getAndIncrement()}",start = false) {
16 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)
17 | it.run()
18 | }
19 | }
20 |
21 | internal val lithoHandler = object : LithoHandler {
22 | override fun post(runnable: Runnable, tag: String?) {
23 | threadPool.execute(runnable)
24 | }
25 |
26 | override fun postAtFront(runnable: Runnable, tag: String?) {
27 | throw UnsupportedOperationException()
28 | }
29 |
30 | override fun isTracing(): Boolean = false
31 |
32 | override fun remove(runnable: Runnable) {
33 | threadPool.remove(runnable)
34 | }
35 | }
36 |
37 | private val threadPool: ThreadPoolExecutor = kotlin.run {
38 | val nThreads = max(
39 | Runtime.getRuntime().availableProcessors(),
40 | 4
41 | )
42 | ThreadPoolExecutor(
43 | nThreads, nThreads,
44 | 3,
45 | TimeUnit.SECONDS,
46 | LinkedBlockingQueue(),
47 | factory
48 | )
49 | }
50 |
51 | val executor: Executor
52 | get() = threadPool
53 |
54 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/TreeManager.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("PackageDirectoryMismatch")
2 |
3 | package com.facebook.litho
4 |
5 | import androidx.annotation.RestrictTo
6 |
7 | @RestrictTo(RestrictTo.Scope.LIBRARY)
8 | abstract class TreeManager internal constructor(
9 | builder: Builder?
10 | ) : ComponentTree(builder) {
11 |
12 | override fun attach() {
13 | super.attach()
14 | }
15 |
16 | override fun detach() {
17 | super.detach()
18 | }
19 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho
2 |
3 | import android.content.res.Resources
4 | import com.facebook.litho.Component
5 | import com.guet.flexbox.build.PropSet
6 |
7 | val pt = Resources.getSystem().displayMetrics.widthPixels / 360f
8 |
9 | inline fun T.toPx(): Int {
10 | return (this.toFloat() * pt).toInt()
11 | }
12 |
13 | inline fun T.toPxFloat(): Float {
14 | return (this.toFloat() * pt)
15 | }
16 |
17 | internal typealias Widget = Component
18 |
19 | internal fun PropSet.getFloatValue(name: String): Float {
20 | return (this[name] as? Float) ?: 0f
21 | }
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/YogaNodeManager.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("PackageDirectoryMismatch")
2 |
3 | package com.facebook.yoga
4 |
5 | import android.content.Context
6 | import com.facebook.litho.NodeConfig
7 | import com.facebook.soloader.SoLoader
8 | import com.guet.flexbox.build.BuildKit
9 | import java.lang.ref.PhantomReference
10 | import java.lang.ref.ReferenceQueue
11 | import kotlin.concurrent.thread
12 |
13 | internal object YogaNodeManager : BuildKit, NodeConfig.InternalYogaNodeFactory {
14 |
15 | private val queue = ReferenceQueue()
16 | private val entries = HashMap, Long>()
17 |
18 | init {
19 | thread(name = "YogaNodeFree", isDaemon = true) {
20 | while (true) {
21 | val entry = queue.remove()
22 | synchronized(entries) {
23 | val instance = entries.remove(entry) ?: 0
24 | if (instance != 0L) {
25 | YogaNative.jni_YGNodeFree(instance)
26 | }
27 | }
28 | }
29 | }
30 | }
31 |
32 | override fun init(c: Context) {
33 | SoLoader.init(c, false)
34 | NodeConfig.sYogaNodeFactory = this
35 | }
36 |
37 | override fun create(config: YogaConfig): YogaNode {
38 | val node = RefQueueFreeYogaNode(config)
39 | val ref = PhantomReference(node, queue)
40 | synchronized(entries) {
41 | entries[ref] = node.nativeInstance
42 | }
43 | return node
44 | }
45 |
46 | private class RefQueueFreeYogaNode(
47 | config: YogaConfig
48 | ) : YogaNodeJNIBase(config) {
49 | val nativeInstance: Long
50 | get() = mNativePointer
51 | }
52 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/ComparableLayerDrawable.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.graphics.drawable.LayerDrawable
5 | import com.facebook.litho.drawable.ComparableDrawable
6 |
7 | class ComparableLayerDrawable(
8 | vararg layers: Drawable
9 | ) : LayerDrawable(layers), ComparableDrawable {
10 | override fun isEquivalentTo(other: ComparableDrawable?): Boolean {
11 | if (this === other) {
12 | return true
13 | } else if (other is ComparableLayerDrawable
14 | && numberOfLayers == other.numberOfLayers) {
15 | return (0..numberOfLayers).all {
16 | val o1 = getDrawable(it)
17 | val o2 = other.getDrawable(it)
18 | if (o1 is ComparableDrawable && o2 is ComparableDrawable) {
19 | o1.isEquivalentTo(o2)
20 | } else {
21 | o1 == o2
22 | }
23 | }
24 | }
25 | return false
26 | }
27 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/LazyDrawableLoader.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.drawable.Drawable
5 | import android.util.ArrayMap
6 | import com.facebook.litho.drawable.ComparableDrawable
7 | import java.lang.reflect.Field
8 | import java.util.concurrent.atomic.AtomicBoolean
9 |
10 | internal abstract class LazyDrawableLoader
11 | : DrawableWrapper(), ComparableDrawable {
12 |
13 | private val isInit = AtomicBoolean(false)
14 |
15 | override fun draw(canvas: Canvas) {
16 | if (isInit.compareAndSet(false, true)) {
17 | wrappedDrawable = loadDrawable()
18 | }
19 | super.draw(canvas)
20 | }
21 |
22 | protected abstract fun loadDrawable(): Drawable
23 |
24 | override fun isEquivalentTo(other: ComparableDrawable?): Boolean {
25 | if (this === other) {
26 | return true
27 | } else if (other?.javaClass == javaClass) {
28 | val set1 = getFieldObjects(this)
29 | val set2 = getFieldObjects(other)
30 | return set1.contentDeepEquals(set2)
31 | }
32 | return false
33 | }
34 |
35 | companion object {
36 |
37 | private val cache = ArrayMap, Array>()
38 |
39 | private fun getFieldObjects(o: Any): Array {
40 | val clazz = o.javaClass
41 | return synchronized(cache) {
42 | cache.getOrPut(clazz) {
43 | val fields = clazz.declaredFields
44 | fields.forEach {
45 | it.isAccessible = true
46 | }
47 | fields
48 | }
49 | }.map {
50 | it.get(o)
51 | }.toTypedArray()
52 | }
53 |
54 | inline fun from(crossinline onLoad: () -> Drawable): Drawable {
55 | return object : LazyDrawableLoader() {
56 | override fun loadDrawable(): Drawable = onLoad()
57 | }
58 | }
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/NoOpDrawable.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.ColorFilter
5 | import android.graphics.PixelFormat
6 | import android.graphics.Rect
7 | import android.graphics.drawable.Drawable
8 |
9 | class NoOpDrawable : Drawable() {
10 |
11 | init {
12 | super.setBounds(0, 0, 0, 0)
13 | }
14 |
15 | override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {}
16 |
17 | override fun setBounds(bounds: Rect) {}
18 |
19 | override fun draw(canvas: Canvas) {}
20 |
21 | override fun setAlpha(alpha: Int) {}
22 |
23 | override fun getOpacity(): Int {
24 | return PixelFormat.TRANSLUCENT
25 | }
26 |
27 | override fun setColorFilter(colorFilter: ColorFilter?) {}
28 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/load/BitmapDrawableResource.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable.load
2 |
3 | import android.graphics.Bitmap
4 | import android.widget.ImageView.ScaleType
5 | import com.bumptech.glide.load.engine.Initializable
6 | import com.bumptech.glide.load.engine.Resource
7 | import com.guet.flexbox.litho.drawable.BitmapDrawable
8 |
9 | class BitmapDrawableResource(
10 | private val bitmapResource: Resource,
11 | private val scaleType: ScaleType,
12 | private val cornerRadius: CornerRadius
13 | ) : Resource {
14 |
15 | override fun getResourceClass(): Class {
16 | return BitmapDrawable::class.java
17 | }
18 |
19 | override fun get(): BitmapDrawable {
20 | val drawable = BitmapDrawable(bitmapResource.get())
21 | drawable.scaleType = scaleType
22 | if (cornerRadius.hasRadius) {
23 | if (cornerRadius.hasEqualRadius) {
24 | drawable.cornerRadius = cornerRadius.radius
25 | } else {
26 | drawable.cornerRadii = cornerRadius.radii
27 | }
28 | }
29 | return drawable
30 | }
31 |
32 | override fun getSize(): Int {
33 | return bitmapResource.size
34 | }
35 |
36 | override fun recycle() {
37 | if (bitmapResource is Initializable) {
38 | bitmapResource.initialize()
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/load/BitmapDrawableTranscoder.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable.load
2 |
3 | import android.graphics.Bitmap
4 | import android.widget.ImageView
5 | import com.bumptech.glide.load.Options
6 | import com.bumptech.glide.load.engine.Resource
7 | import com.bumptech.glide.load.resource.transcode.ResourceTranscoder
8 | import com.guet.flexbox.litho.drawable.BitmapDrawable
9 |
10 | class BitmapDrawableTranscoder : ResourceTranscoder {
11 |
12 | override fun transcode(
13 | toTranscode: Resource,
14 | options: Options
15 | ): Resource {
16 | var scaleType = options.get(DrawableLoaderModule.scaleType)
17 | if (scaleType == null || scaleType == ImageView.ScaleType.MATRIX) {
18 | scaleType = ImageView.ScaleType.FIT_XY
19 | }
20 | val cornerRadius = options
21 | .get(DrawableLoaderModule.cornerRadius)
22 | ?: CornerRadius.empty
23 | return BitmapDrawableResource(toTranscode, scaleType, cornerRadius)
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/load/CornerRadius.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable.load
2 |
3 | class CornerRadius private constructor(
4 | private val array: FloatArray
5 | ) {
6 |
7 | val hasEqualRadius: Boolean
8 | get() = array.size == 1
9 |
10 | val hasRadius: Boolean
11 | get() = array.isNotEmpty()
12 |
13 | val radii: FloatArray
14 | get() = array
15 |
16 | val radius
17 | get() = array[0]
18 |
19 | override fun hashCode(): Int {
20 | return array.contentHashCode()
21 | }
22 |
23 | override fun equals(other: Any?): Boolean {
24 | return (other === this) || (other is CornerRadius
25 | && array.contentEquals(other.array))
26 | }
27 |
28 | companion object {
29 | operator fun invoke(
30 | leftTop: Float,
31 | rightTop: Float,
32 | rightBottom: Float,
33 | leftBottom: Float
34 | ): CornerRadius {
35 | if (leftTop + rightTop + rightBottom + leftBottom != 0f) {
36 | val array = if (leftTop == rightTop
37 | && leftTop == rightBottom
38 | && leftTop == leftBottom) {
39 | floatArrayOf(leftTop)
40 | } else {
41 | floatArrayOf(
42 | leftTop, leftTop,
43 | rightTop, rightTop,
44 | rightBottom, rightBottom,
45 | leftBottom, leftBottom
46 | )
47 | }
48 | return CornerRadius(array)
49 | } else {
50 | return empty
51 | }
52 | }
53 |
54 | operator fun invoke(
55 | value: Float
56 | ): CornerRadius {
57 | return if (value == 0f) {
58 | empty
59 | } else {
60 | CornerRadius(floatArrayOf(value))
61 | }
62 | }
63 |
64 | val empty = CornerRadius(FloatArray(0))
65 | }
66 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/load/DelegateTarget.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable.load
2 |
3 | import com.bumptech.glide.request.target.BaseTarget
4 | import com.bumptech.glide.request.target.SizeReadyCallback
5 | import com.bumptech.glide.request.transition.Transition
6 |
7 | open class DelegateTarget : BaseTarget() {
8 | override fun getSize(cb: SizeReadyCallback) {
9 | }
10 |
11 | override fun removeCallback(cb: SizeReadyCallback) {
12 | }
13 |
14 | override fun onResourceReady(resource: T, transition: Transition?) {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/load/DrawableLoaderGlideModule.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable.load
2 |
3 | import android.content.Context
4 | import com.bumptech.glide.Glide
5 | import com.bumptech.glide.GlideBuilder
6 | import com.bumptech.glide.Registry
7 | import com.bumptech.glide.module.GlideModule
8 |
9 | @Deprecated("")
10 | class DrawableLoaderGlideModule : GlideModule {
11 |
12 | override fun applyOptions(context: Context, builder: GlideBuilder) {
13 | }
14 |
15 | override fun registerComponents(
16 | context: Context,
17 | glide: Glide,
18 | registry: Registry
19 | ) {
20 | DrawableLoaderModule.init(registry)
21 | }
22 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/drawable/load/DrawableLoaderModule.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.drawable.load
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.widget.ImageView
6 | import com.bumptech.glide.Glide
7 | import com.bumptech.glide.Registry
8 | import com.bumptech.glide.annotation.GlideModule
9 | import com.bumptech.glide.load.Option
10 | import com.bumptech.glide.module.LibraryGlideModule
11 | import com.guet.flexbox.build.BuildKit
12 | import com.guet.flexbox.litho.drawable.BitmapDrawable
13 | import java.io.File
14 | import java.nio.ByteBuffer
15 | import java.util.concurrent.atomic.AtomicBoolean
16 |
17 |
18 | @GlideModule
19 | class DrawableLoaderModule : LibraryGlideModule() {
20 |
21 | companion object : BuildKit {
22 |
23 | val scaleType = Option.memory(
24 | BitmapDrawable::class.java.name + ".scaleType",
25 | ImageView.ScaleType.FIT_XY
26 | )
27 | val cornerRadius = Option.memory(
28 | BitmapDrawable::class.java.name + ".cornerRadius"
29 | )
30 |
31 | private val isInit = AtomicBoolean(false)
32 |
33 | internal fun init(
34 | registry: Registry
35 | ) {
36 | if (!isInit.compareAndSet(false, true)) {
37 | return
38 | }
39 | registry.register(Bitmap::class.java,
40 | BitmapDrawable::class.java,
41 | BitmapDrawableTranscoder()
42 | ).prepend(File::class.java, ByteBuffer::class.java, FileBufferLoader.Factory())
43 | }
44 |
45 | override fun init(c: Context) {
46 | if (isInit.get()) {
47 | return
48 | }
49 | val glide = Glide.get(c)
50 | init(glide.registry)
51 | }
52 | }
53 |
54 | override fun registerComponents(
55 | context: Context,
56 | glide: Glide,
57 | registry: Registry
58 | ) {
59 | init(registry)
60 | }
61 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/CommonProps.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories
2 |
3 | import com.facebook.litho.Component
4 | import com.facebook.litho.ComponentContext
5 | import com.guet.flexbox.build.PropSet
6 | import com.guet.flexbox.litho.factories.filler.ClickUrlFiller
7 | import com.guet.flexbox.litho.factories.filler.PropsFiller
8 |
9 | internal object CommonProps : ToComponent>() {
10 |
11 | override val propsFiller by PropsFiller
12 | .create> {
13 | pt("width", Component.Builder<*>::widthPx)
14 | pt("height", Component.Builder<*>::heightPx)
15 | pt("minWidth", Component.Builder<*>::minWidthPx)
16 | pt("maxWidth", Component.Builder<*>::maxWidthPx)
17 | pt("minHeight", Component.Builder<*>::minHeightPx)
18 | pt("maxHeight", Component.Builder<*>::maxHeightPx)
19 | value("flexGrow", Component.Builder<*>::flexGrow)
20 | value("flexShrink", Component.Builder<*>::flexShrink)
21 | enum("alignSelf", Component.Builder<*>::alignSelf)
22 | event("onClick", Component.Builder<*>::clickHandler)
23 | event("onVisible", Component.Builder<*>::visibleHandler)
24 | register("clickUrl", ClickUrlFiller)
25 | edges("margin", Component.Builder<*>::marginPx)
26 | edges("padding", Component.Builder<*>::paddingPx)
27 | }
28 |
29 | override fun create(
30 | c: ComponentContext,
31 | visibility: Boolean,
32 | attrs: PropSet
33 | ): Component.Builder<*> {
34 | throw UnsupportedOperationException()
35 | }
36 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/ToBanner.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories
2 |
3 | import com.facebook.litho.ComponentContext
4 | import com.guet.flexbox.build.PropSet
5 | import com.guet.flexbox.litho.Widget
6 | import com.guet.flexbox.litho.factories.filler.PropsFiller
7 | import com.guet.flexbox.litho.widget.Banner
8 |
9 | internal object ToBanner : ToComponent() {
10 | override val propsFiller by PropsFiller
11 | .create(CommonProps) {
12 | bool("isCircular", Banner.Builder::isCircular)
13 | bool("indicatorEnable", Banner.Builder::indicatorEnable)
14 | value("timeSpan", Banner.Builder::timeSpan)
15 | enum("orientation", Banner.Builder::orientation)
16 | pt("indicatorSize", Banner.Builder::indicatorSizePx)
17 | pt("indicatorHeight", Banner.Builder::indicatorHeightPx)
18 | text("indicatorSelected", Banner.Builder::indicatorSelected)
19 | text("indicatorUnselected", Banner.Builder::indicatorUnselected)
20 | }
21 |
22 | override fun create(
23 | c: ComponentContext,
24 | visibility: Boolean,
25 | attrs: PropSet
26 | ): Banner.Builder {
27 | return Banner.create(c)
28 | }
29 |
30 | override fun onInstallChildren(
31 | owner: Banner.Builder,
32 | visibility: Boolean,
33 | attrs: PropSet,
34 | children: List
35 | ) {
36 | owner.children(children)
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/ToDynamicImage.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories
2 |
3 | import com.facebook.litho.ComponentContext
4 | import com.guet.flexbox.build.PropSet
5 | import com.guet.flexbox.litho.factories.filler.GlideModelFiller
6 | import com.guet.flexbox.litho.factories.filler.PropsFiller
7 | import com.guet.flexbox.litho.widget.DynamicImage
8 |
9 | internal object ToDynamicImage : ToComponent() {
10 |
11 | override val propsFiller by PropsFiller
12 | .create(CommonProps) {
13 | enum("scaleType", DynamicImage.Builder::scaleType)
14 | value("blurRadius", DynamicImage.Builder::blurRadius)
15 | value("blurSampling", DynamicImage.Builder::blurSampling)
16 | value("aspectRatio", DynamicImage.Builder::imageAspectRatio)
17 | pt("borderLeftTopRadius", DynamicImage.Builder::leftTopRadius)
18 | pt("borderRightTopRadius", DynamicImage.Builder::rightTopRadius)
19 | pt("borderRightBottomRadius", DynamicImage.Builder::rightBottomRadius)
20 | pt("borderLeftBottomRadius", DynamicImage.Builder::leftBottomRadius)
21 | register("src", GlideModelFiller)
22 | }
23 |
24 | override fun create(
25 | c: ComponentContext,
26 | visibility: Boolean,
27 | attrs: PropSet
28 | ): DynamicImage.Builder {
29 | return DynamicImage.create(c)
30 | }
31 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/ToEmpty.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories
2 |
3 | import com.facebook.litho.ComponentContext
4 | import com.facebook.litho.widget.EmptyComponent
5 | import com.guet.flexbox.build.PropSet
6 | import com.guet.flexbox.litho.factories.filler.PropsFiller
7 |
8 | internal object ToEmpty : ToComponent() {
9 | override val propsFiller = PropsFiller
10 | .use(CommonProps)
11 |
12 | override fun create(
13 | c: ComponentContext,
14 | visibility: Boolean,
15 | attrs: PropSet
16 | ): EmptyComponent.Builder {
17 | return EmptyComponent.create(c)
18 | }
19 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/ToFlex.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories
2 |
3 | import com.facebook.litho.Column
4 | import com.facebook.litho.Component
5 | import com.facebook.litho.ComponentContext
6 | import com.facebook.litho.Row
7 | import com.guet.flexbox.build.PropSet
8 | import com.guet.flexbox.enums.FlexDirection
9 | import com.guet.flexbox.litho.Widget
10 | import com.guet.flexbox.litho.factories.filler.PropsFiller
11 |
12 | internal object ToFlex : ToComponent>() {
13 |
14 | override val propsFiller by PropsFiller
15 | .create>(CommonProps) {
16 | enum("flexWrap", Component.ContainerBuilder<*>::wrap)
17 | enum("justifyContent", Component.ContainerBuilder<*>::justifyContent)
18 | enum("alignItems", Component.ContainerBuilder<*>::alignItems)
19 | enum("alignContent", Component.ContainerBuilder<*>::alignContent)
20 | }
21 |
22 | override fun create(
23 | c: ComponentContext,
24 | visibility: Boolean,
25 | attrs: PropSet
26 | ): Component.ContainerBuilder<*> {
27 | val component: Component.ContainerBuilder<*>
28 | when (attrs.getOrElse("flexDirection") { FlexDirection.ROW }) {
29 | FlexDirection.COLUMN -> {
30 | component = Column.create(c)
31 | }
32 | FlexDirection.COLUMN_REVERSE -> {
33 | component = Column.create(c)
34 | .reverse(true)
35 | }
36 | FlexDirection.ROW_REVERSE -> {
37 | component = Row.create(c)
38 | .reverse(true)
39 | }
40 | else -> {
41 | component = Row.create(c)
42 | }
43 | }
44 | return component
45 | }
46 |
47 | override fun onInstallChildren(
48 | owner: Component.ContainerBuilder<*>,
49 | visibility: Boolean,
50 | attrs: PropSet,
51 | children: List
52 | ) {
53 | children.forEach {
54 | owner.child(it)
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/ToStack.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories
2 |
3 | import com.facebook.litho.ComponentContext
4 | import com.guet.flexbox.build.PropSet
5 | import com.guet.flexbox.litho.Widget
6 | import com.guet.flexbox.litho.factories.filler.PropsFiller
7 | import com.guet.flexbox.litho.widget.Stack
8 |
9 | internal object ToStack : ToComponent() {
10 |
11 | override val propsFiller = PropsFiller
12 | .use(CommonProps)
13 |
14 | override fun create(
15 | c: ComponentContext,
16 | visibility: Boolean,
17 | attrs: PropSet
18 | ): Stack.Builder {
19 | return Stack.create(c)
20 | }
21 |
22 | override fun onInstallChildren(
23 | owner: Stack.Builder,
24 | visibility: Boolean,
25 | attrs: PropSet,
26 | children: List
27 | ) {
28 | if (children.isEmpty()) {
29 | return
30 | }
31 | owner.children(children)
32 | }
33 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/ToText.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories
2 |
3 | import com.facebook.litho.ComponentContext
4 | import com.facebook.litho.widget.Text
5 | import com.guet.flexbox.build.PropSet
6 | import com.guet.flexbox.litho.factories.filler.PropsFiller
7 | import com.guet.flexbox.litho.factories.filler.TextColorFiller
8 | import com.guet.flexbox.litho.factories.filler.TextFiller
9 |
10 |
11 | internal object ToText : ToComponent() {
12 |
13 | override val propsFiller by PropsFiller
14 | .create(CommonProps) {
15 | enum("verticalGravity", Text.Builder::verticalGravity)
16 | enum("horizontalGravity", Text.Builder::textAlignment)
17 | bool("clipToBounds", Text.Builder::clipToBounds)
18 | value("maxLines", Text.Builder::maxLines)
19 | value("minLines", Text.Builder::minLines)
20 | pt("textSize", Text.Builder::textSizePx)
21 | enum("ellipsize", Text.Builder::ellipsize)
22 | textStyle("textStyle", Text.Builder::typeface)
23 | register("textColor", TextColorFiller)
24 | register("text", TextFiller)
25 | }
26 |
27 | override fun create(
28 | c: ComponentContext,
29 | visibility: Boolean,
30 | attrs: PropSet
31 | ): Text.Builder {
32 | return Text.create(c)
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/ToTextInput.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories
2 |
3 | import com.facebook.litho.ComponentContext
4 | import com.facebook.litho.widget.TextInput
5 | import com.guet.flexbox.build.PropSet
6 | import com.guet.flexbox.litho.factories.filler.PropsFiller
7 |
8 | internal object ToTextInput : ToComponent() {
9 | override val propsFiller by PropsFiller
10 | .create(CommonProps) {
11 | value("maxLines", TextInput.Builder::maxLines)
12 | value("minLines", TextInput.Builder::minLines)
13 | pt("textSize", TextInput.Builder::textSizePx)
14 | enum("ellipsize", TextInput.Builder::ellipsize)
15 | event("onTextChanged", TextInput.Builder::textChangedEventHandler)
16 | textStyle("textStyle", TextInput.Builder::typeface)
17 | }
18 |
19 | override fun create(
20 | c: ComponentContext,
21 | visibility: Boolean,
22 | attrs: PropSet
23 | ): TextInput.Builder {
24 | return TextInput.create(c)
25 | .inputBackground(null)
26 | }
27 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/filler/ClickUrlFiller.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories.filler
2 |
3 | import com.facebook.litho.ClickEvent
4 | import com.facebook.litho.Component
5 | import com.guet.flexbox.eventsystem.ExternalEventReceiver
6 | import com.guet.flexbox.litho.LithoEventHandler
7 |
8 | internal object ClickUrlFiller : PropFiller, ExternalEventReceiver> {
9 | override fun fill(
10 | c: Component.Builder<*>,
11 | display: Boolean,
12 | other: Map,
13 | value: ExternalEventReceiver
14 | ) {
15 | if (!other.containsKey("onClick")) {
16 | c.clickHandler(LithoEventHandler(value))
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/filler/FillViewportFiller.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories.filler
2 |
3 | import com.facebook.litho.Component
4 | import com.facebook.litho.widget.VerticalScroll
5 | import com.guet.flexbox.litho.widget.HorizontalScroll
6 |
7 | internal object FillViewportFiller : PropFiller, Boolean> {
8 | override fun fill(
9 | c: Component.Builder<*>,
10 | display: Boolean,
11 | other: Map,
12 | value: Boolean
13 | ) {
14 | if (c is HorizontalScroll.Builder) {
15 | c.fillViewport(value)
16 | } else if (c is VerticalScroll.Builder) {
17 | c.fillViewport(value)
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/filler/GlideModelFiller.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories.filler
2 |
3 | import com.bumptech.glide.Glide
4 | import com.guet.flexbox.litho.widget.DynamicImage
5 |
6 | internal object GlideModelFiller : PropFiller {
7 | override fun fill(
8 | c: DynamicImage.Builder,
9 | display: Boolean,
10 | other: Map,
11 | value: Any
12 | ) {
13 | Glide.with(c.context!!.androidContext)
14 | .load(value)
15 | .preload()
16 | c.model(value)
17 | }
18 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/filler/PropFiller.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories.filler
2 |
3 | import com.facebook.litho.Component
4 |
5 | internal interface PropFiller, V> {
6 | fun fill(c: C, display: Boolean, other: Map, value: V)
7 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/filler/ScrollBarEnableFiller.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories.filler
2 |
3 | import com.facebook.litho.Component
4 | import com.facebook.litho.widget.VerticalScroll
5 | import com.guet.flexbox.litho.widget.HorizontalScroll
6 |
7 |
8 | internal object ScrollBarEnableFiller : PropFiller, Boolean> {
9 | override fun fill(
10 | c: Component.Builder<*>,
11 | display: Boolean,
12 | other: Map,
13 | value: Boolean
14 | ) {
15 | if (c is HorizontalScroll.Builder) {
16 | c.scrollbarEnabled(value)
17 | } else if (c is VerticalScroll.Builder) {
18 | c.scrollbarEnabled(value)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/filler/TextColorFiller.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories.filler
2 |
3 | import android.content.res.ColorStateList
4 | import android.graphics.Color
5 | import com.facebook.litho.widget.Text
6 |
7 | internal object TextColorFiller : PropFiller {
8 |
9 | private val invisibleColor = ColorStateList.valueOf(Color.TRANSPARENT)
10 |
11 | override fun fill(
12 | c: Text.Builder,
13 | display: Boolean,
14 | other: Map,
15 | value: Int
16 | ) {
17 | if (display) {
18 | c.textColor(value)
19 | } else {
20 | c.textColor(Color.TRANSPARENT)
21 | c.textColorStateList(invisibleColor)
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/factories/filler/TextFiller.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.factories.filler
2 |
3 | import android.content.res.ColorStateList
4 | import android.graphics.Color
5 | import androidx.core.text.HtmlCompat
6 | import com.facebook.litho.widget.Text
7 | import java.util.regex.Pattern
8 |
9 | internal object TextFiller : PropFiller {
10 |
11 | private val invisibleColor = ColorStateList.valueOf(Color.TRANSPARENT)
12 |
13 | private val htmlTester = Pattern.compile(".*<(.*)>.*")
14 |
15 | override fun fill(
16 | c: Text.Builder,
17 | display: Boolean,
18 | other: Map,
19 | value: String
20 | ) {
21 | val htmlText = if (htmlTester.matcher(value).find()) {
22 | try {
23 | HtmlCompat.fromHtml(
24 | value,
25 | HtmlCompat.FROM_HTML_MODE_COMPACT,
26 | null,
27 | null
28 | )
29 | } catch (e: Throwable) {
30 | value
31 | }
32 | } else {
33 | value
34 | }
35 | c.text(htmlText)
36 | if (!display) {
37 | c.textColor(Color.TRANSPARENT)
38 | c.textColorStateList(invisibleColor)
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/widget/LithoViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.widget
2 |
3 | import android.content.Context
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.facebook.litho.LithoView
6 |
7 | internal class LithoViewHolder(
8 | c: Context
9 | ) : RecyclerView.ViewHolder(LithoView(c).apply {
10 | layoutParams = RecyclerView.LayoutParams(-1, -1)
11 | }) {
12 | val lithoView: LithoView
13 | get() = itemView as LithoView
14 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/widget/LithoViewsAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.widget
2 |
3 | import android.view.ViewGroup
4 | import androidx.recyclerview.widget.RecyclerView
5 |
6 | internal abstract class LithoViewsAdapter : RecyclerView.Adapter() {
7 | final override fun onCreateViewHolder(
8 | parent: ViewGroup,
9 | viewType: Int
10 | ): LithoViewHolder {
11 | return LithoViewHolder(parent.context)
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/litho/src/main/java/com/guet/flexbox/litho/widget/ThreadCheckerSpec.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho.widget
2 |
3 | import android.os.Looper
4 | import android.util.Log
5 | import com.facebook.litho.Component
6 | import com.facebook.litho.ComponentContext
7 | import com.facebook.litho.annotations.LayoutSpec
8 | import com.facebook.litho.annotations.OnCreateLayout
9 | import com.facebook.litho.annotations.Prop
10 |
11 | @LayoutSpec
12 | object ThreadCheckerSpec {
13 |
14 | private val mainThread = Looper.getMainLooper()
15 |
16 | @OnCreateLayout
17 | fun onCreateLayout(c: ComponentContext, @Prop component: Component): Component {
18 | if (Looper.myLooper() == mainThread) {
19 | Log.e(ThreadChecker::class.java.simpleName,
20 | "Flexbox layout in main thread"
21 | )
22 | }
23 | return component
24 | }
25 | }
--------------------------------------------------------------------------------
/litho/src/main/res/drawable/indicator_black.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/litho/src/main/res/drawable/indicator_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/litho/src/test/java/com/guet/flexbox/litho/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.litho
2 |
3 | import org.junit.Assert
4 | import org.junit.Test
5 | import java.lang.ref.ReferenceQueue
6 | import java.lang.ref.WeakReference
7 |
8 | /**
9 | * Example local unit test, which will execute on the development machine (host).
10 | *
11 | * @see [Testing documentation](http://d.android.com/tools/testing)
12 | */
13 | class ExampleUnitTest {
14 |
15 | private val queue = ReferenceQueue()
16 |
17 | private val weak = WeakReference(Any(),queue)
18 |
19 | @Test
20 | fun addition_isCorrect() {
21 | System.gc()
22 | val ref= queue.remove(0)
23 | println(ref.get())
24 | Assert.assertEquals(4, 2 + 2.toLong())
25 | }
26 |
27 | fun test() {
28 |
29 | }
30 | }
--------------------------------------------------------------------------------
/playground/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /release
--------------------------------------------------------------------------------
/playground/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 buildLayout.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 type 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 type.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/playground/src/androidTest/java/com/guet/flexbox/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.InstrumentationRegistry;
6 | import androidx.test.runner.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.getTargetContext();
24 |
25 | assertEquals("com.guet.flexbox", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/playground/src/androidTest/java/com/guet/flexbox/TimePickerFragment.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/androidTest/java/com/guet/flexbox/TimePickerFragment.java
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/homepage/banner.flexml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
13 |
15 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/homepage/banner.json:
--------------------------------------------------------------------------------
1 | {
2 | "urls":[
3 | "https://i.loli.net/2020/02/10/pcAUBTo5C4LHby2.jpg",
4 | "https://i.loli.net/2020/02/10/f8zL4Sq5TmwkFed.jpg",
5 | "https://i.loli.net/2020/02/18/OrkiRXtDaewHmBC.jpg"
6 | ]
7 | }
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/homepage/function.flexml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
22 |
23 |
27 |
28 |
33 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/homepage/function.json:
--------------------------------------------------------------------------------
1 | {
2 | "icons": [
3 | "res://drawable?name=ic_01",
4 | "res://drawable?name=ic_02",
5 | "res://drawable?name=ic_03",
6 | "res://drawable?name=ic_04",
7 | "res://drawable?name=ic_05",
8 | "res://drawable?name=ic_06",
9 | "res://drawable?name=ic_07",
10 | "res://drawable?name=ic_08"
11 | ]
12 | }
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/http/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "html":""
3 | }
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/http/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "template": "template.flexml",
3 | "data": "data.json"
4 | }
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/http/template.flexml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/introduction/data.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/introduction/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "template": "template.flexml",
3 | "data": "data.json"
4 | }
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/logo/data.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/logo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "template": "template.flexml",
3 | "data": "data.json"
4 | }
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/logo/template.flexml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
14 |
19 |
20 |
27 |
28 |
35 |
36 |
37 |
42 |
43 |
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/resume/data.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/resume/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "template": "template.flexml",
3 | "data": "data.json"
4 | }
--------------------------------------------------------------------------------
/playground/src/main/assets/layout/search/history_list.flexml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
11 |
12 |
16 |
21 |
22 |
26 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/playground/src/main/java/com/guet/flexbox/playground/PlaygroundApplication.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.playground
2 |
3 | import android.app.Application
4 | import com.orhanobut.logger.AndroidLogAdapter
5 | import com.orhanobut.logger.Logger
6 |
7 | class PlaygroundApplication : Application() {
8 | override fun onCreate() {
9 | super.onCreate()
10 | Logger.addLogAdapter(AndroidLogAdapter())
11 | }
12 | }
--------------------------------------------------------------------------------
/playground/src/main/java/com/guet/flexbox/playground/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.playground
2 |
3 | import android.content.res.Resources
4 | import kotlin.math.ceil
5 |
6 | fun getStatusBarHeight(): Int {
7 | return ceil((25f * Resources.getSystem().displayMetrics.density).toDouble()).toInt()
8 | }
--------------------------------------------------------------------------------
/playground/src/main/java/com/guet/flexbox/playground/model/ACGImage.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.playground.model
2 |
3 | class ACGImage(
4 | val imgurl: String?
5 | )
--------------------------------------------------------------------------------
/playground/src/main/java/com/guet/flexbox/playground/model/Homepage.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.playground.model
2 |
3 | import com.guet.flexbox.litho.TemplatePage
4 |
5 | class Homepage(
6 | val feed: List,
7 | val introduction: TemplatePage
8 | )
--------------------------------------------------------------------------------
/playground/src/main/java/com/guet/flexbox/playground/model/ImageService.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.playground.model
2 |
3 | import okhttp3.OkHttpClient
4 | import retrofit2.Call
5 | import retrofit2.Retrofit
6 | import retrofit2.converter.gson.GsonConverterFactory
7 | import retrofit2.http.GET
8 | import java.util.concurrent.TimeUnit
9 |
10 | interface ImageService {
11 |
12 | @GET("/api/api.php?return=json")
13 | fun get(): Call
14 |
15 | companion object {
16 |
17 | val random: ImageService = Retrofit.Builder()
18 | .baseUrl("https://api.ixiaowai.cn")
19 | .client(OkHttpClient.Builder()
20 | .connectTimeout(1L, TimeUnit.SECONDS)
21 | .build())
22 | .addConverterFactory(GsonConverterFactory.create())
23 | .build()
24 | .create(ImageService::class.java)
25 | }
26 | }
--------------------------------------------------------------------------------
/playground/src/main/java/com/guet/flexbox/playground/model/MockService.kt:
--------------------------------------------------------------------------------
1 | package com.guet.flexbox.playground.model
2 |
3 | import com.guet.flexbox.TemplateNode
4 | import retrofit2.Call
5 | import retrofit2.http.GET
6 |
7 | interface MockService {
8 | @GET("/datasource")
9 | fun data(): Call