├── .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 | 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 | 17 | 18 | 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 | 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> 10 | 11 | @GET("/template") 12 | fun layout(): Call 13 | } -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/model/TemplateCompiler.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.model 2 | 3 | import com.guet.flexbox.TemplateNode 4 | import com.guet.flexbox.compiler.Compiler 5 | import com.guet.flexbox.compiler.NodeFactory 6 | import java.util.* 7 | 8 | object TemplateCompiler : Compiler(object : NodeFactory { 9 | override fun createNode( 10 | type: String, 11 | attrs: Map, 12 | children: List 13 | ): TemplateNode { 14 | return TemplateNode( 15 | type, 16 | Collections.unmodifiableMap(attrs), 17 | Collections.unmodifiableList(children) 18 | ) 19 | } 20 | }) -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/test/TestActivity.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.test 2 | 3 | import android.graphics.drawable.Drawable 4 | import android.os.Build 5 | import android.os.Bundle 6 | import android.os.MemoryFile 7 | import android.util.Log 8 | import androidx.annotation.RequiresApi 9 | import androidx.appcompat.app.AppCompatActivity 10 | import com.bumptech.glide.Glide 11 | import com.bumptech.glide.load.DataSource 12 | import com.bumptech.glide.load.engine.GlideException 13 | import com.bumptech.glide.request.RequestListener 14 | import com.bumptech.glide.request.target.Target 15 | import com.didichuxing.doraemonkit.DoraemonKit 16 | import com.guet.flexbox.playground.R 17 | 18 | class TestActivity : AppCompatActivity() { 19 | 20 | val memoryFiles = ArrayList() 21 | 22 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | 26 | DoraemonKit.install(application) 27 | val path = Glide.get(this) 28 | .registry.getLoadPath( 29 | Int::class.java, 30 | Drawable::class.java, 31 | Drawable::class.java 32 | ) 33 | 34 | 35 | val drawable = Glide.with(this) 36 | .load(R.drawable.ic_background_transition) 37 | .addListener(object : RequestListener { 38 | override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { 39 | return true 40 | } 41 | 42 | override fun onResourceReady(resource: Drawable, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { 43 | Log.d("asdasdasd", resource.toString()) 44 | return true 45 | } 46 | }) 47 | .submit() 48 | 49 | } 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/test/TestView.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.test 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.graphics.* 6 | import android.graphics.drawable.BitmapDrawable 7 | import android.os.Build 8 | import android.util.AttributeSet 9 | import android.view.View 10 | import com.guet.flexbox.playground.R 11 | 12 | @TargetApi(Build.VERSION_CODES.P) 13 | class TestView @JvmOverloads constructor( 14 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 15 | ) : View(context, attrs, defStyleAttr) { 16 | 17 | 18 | private val bitmap = BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.ic_photo2)) 19 | private val paint = Paint().apply { 20 | color = Color.RED 21 | isAntiAlias = true 22 | } 23 | private var index = 0 24 | private val rectF = RectF() 25 | private var xfermode = PorterDuffXfermode(enumValues()[0]) 26 | private val path = Path() 27 | 28 | init { 29 | setOnClickListener { 30 | if (++index >= enumValues().size) { 31 | index = 0 32 | } 33 | println(enumValues()[index].name) 34 | xfermode = PorterDuffXfermode(enumValues()[index]) 35 | invalidate() 36 | requestLayout() 37 | } 38 | } 39 | 40 | override fun onDraw(canvas: Canvas) { 41 | canvas.drawColor(Color.RED) 42 | canvas.save() 43 | canvas.save() 44 | bitmap.bounds = Rect(0, 0, width, height) 45 | bitmap.draw(canvas) 46 | canvas.restore() 47 | paint.reset() 48 | path.reset() 49 | rectF.set(Rect(0, 0, width, height)) 50 | path.apply { 51 | reset() 52 | addRect(rectF, Path.Direction.CW) 53 | addRoundRect(rectF, 100f, 100f, Path.Direction.CCW) 54 | close() 55 | } 56 | paint.xfermode = xfermode 57 | canvas.drawPath(path, paint) 58 | canvas.restore() 59 | 60 | } 61 | } -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/widget/CornerOutlineProvider.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.widget 2 | 3 | import android.graphics.Outline 4 | import android.os.Build 5 | import android.view.View 6 | import android.view.ViewOutlineProvider 7 | import androidx.annotation.Px 8 | import androidx.annotation.RequiresApi 9 | import kotlin.math.max 10 | 11 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 12 | class CornerOutlineProvider( 13 | @Px private val borderRadius: Int 14 | ) : ViewOutlineProvider() { 15 | override fun getOutline(view: View, outline: Outline) { 16 | if (borderRadius >= max(view.width, view.height)) { 17 | outline.setOval( 18 | 0, 19 | 0, 20 | view.width, 21 | view.height 22 | ) 23 | } else { 24 | outline.setRoundRect(0, 25 | 0, 26 | view.width, 27 | view.height, 28 | borderRadius.toFloat() 29 | ) 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/widget/FlexBoxAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.widget 2 | 3 | import android.view.View 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.chad.library.adapter.base.BaseViewHolder 6 | import com.guet.flexbox.eventsystem.EventHandler 7 | import com.guet.flexbox.eventsystem.event.ClickUrlEvent 8 | import com.guet.flexbox.litho.HostingView 9 | import com.guet.flexbox.litho.TemplatePage 10 | import com.guet.flexbox.playground.R 11 | 12 | 13 | class FlexBoxAdapter( 14 | private val onClick: (v: View, url: String) -> Unit 15 | ) : BaseQuickAdapter(R.layout.feed_item) { 16 | 17 | private val callback = object : EventHandler { 18 | override fun handleEvent(e: ClickUrlEvent): Boolean { 19 | onClick(e.source, e.url) 20 | return true 21 | } 22 | } 23 | 24 | 25 | override fun onViewRecycled(holder: BaseViewHolder) { 26 | val lithoView = holder.getView(R.id.litho) 27 | lithoView?.unmountAllItems() 28 | lithoView?.templatePage = null 29 | } 30 | 31 | override fun convert(helper: BaseViewHolder, item: TemplatePage) { 32 | val lithoView = helper.getView(R.id.litho) 33 | lithoView.eventBus.subscribe(callback) 34 | lithoView.templatePage = item 35 | } 36 | } -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/widget/MarqueeText.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.widget 2 | 3 | import android.content.Context 4 | import android.text.TextUtils 5 | import android.util.AttributeSet 6 | import androidx.appcompat.widget.AppCompatTextView 7 | 8 | class MarqueeText @JvmOverloads constructor( 9 | context: Context?, 10 | attrs: AttributeSet? = null, 11 | defStyle: Int = 0 12 | ) : AppCompatTextView(context, attrs, defStyle) { 13 | 14 | init { 15 | isFocusable = true 16 | setSingleLine() 17 | ellipsize = TextUtils.TruncateAt.MARQUEE 18 | marqueeRepeatLimit = Int.MIN_VALUE 19 | } 20 | 21 | override fun isFocused(): Boolean { 22 | return true 23 | } 24 | } -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/widget/MyRefreshViewImpl.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.widget 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.view.Gravity 6 | import android.view.View 7 | import android.widget.TextView 8 | import io.iftech.android.library.refresh.RefreshView 9 | 10 | class MyRefreshViewImpl(context: Context) : RefreshView { 11 | 12 | private val internalView = TextView(context).apply { 13 | gravity = Gravity.CENTER 14 | text = "下拉刷新" 15 | } 16 | private var visibleHeight = 0 17 | private var isLoading = false 18 | set(value) { 19 | field = value 20 | internalView.text = if (value) "正在加载..." else "下拉刷新" 21 | } 22 | private var isRestore = false 23 | 24 | override val view: View 25 | get() = internalView 26 | 27 | override fun canDrag(): Boolean { 28 | return isLoading.not() && isRestore.not() 29 | } 30 | 31 | override fun canRefresh(): Boolean { 32 | return visibleHeight > REFRESH_HEIGHT 33 | } 34 | 35 | override fun isLoading(): Boolean { 36 | return isLoading 37 | } 38 | 39 | override fun isRestore(): Boolean { 40 | return isRestore 41 | } 42 | 43 | @SuppressLint("SetTextI18n") 44 | override fun updateDragging(fraction: Float) { 45 | } 46 | 47 | override fun startLoading() { 48 | isLoading = true 49 | } 50 | 51 | override fun restore() { 52 | if (isLoading) { 53 | isLoading = false 54 | isRestore = true 55 | } 56 | } 57 | 58 | override fun reset() { 59 | isLoading = false 60 | isRestore = false 61 | } 62 | 63 | override fun updateVisibleHeight(height: Int) { 64 | visibleHeight = height 65 | if (isLoading.not()) { 66 | internalView.text = if (canRefresh()) "松手刷新" else "下拉加载" 67 | } 68 | } 69 | 70 | companion object { 71 | const val REFRESH_HEIGHT = 300 72 | } 73 | } -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/widget/QuickHandler.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.widget 2 | 3 | import android.os.Handler 4 | import android.os.HandlerThread 5 | 6 | open class QuickHandler(name: String?) : Handler({ 7 | val handlerThread = HandlerThread(name) 8 | handlerThread.start() 9 | handlerThread.looper 10 | }()) -------------------------------------------------------------------------------- /playground/src/main/java/com/guet/flexbox/playground/widget/StatusBarPadding.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox.playground.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | 7 | 8 | class StatusBarPadding @JvmOverloads constructor( 9 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 10 | ) : View(context, attrs, defStyleAttr) { 11 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 12 | setMeasuredDimension( 13 | getDefaultSize(suggestedMinimumWidth, widthMeasureSpec), 14 | getStatusBarHeight() 15 | ) 16 | } 17 | 18 | private fun getStatusBarHeight(): Int { 19 | val resourceId: Int = resources.getIdentifier("status_bar_height", "dimen", "android") 20 | return resources.getDimensionPixelSize(resourceId) 21 | } 22 | } -------------------------------------------------------------------------------- /playground/src/main/res/drawable/banner_test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/banner_test.jpg -------------------------------------------------------------------------------- /playground/src/main/res/drawable/console_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 9 | 10 | 12 | 13 | -------------------------------------------------------------------------------- /playground/src/main/res/drawable/glide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/glide.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/go_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/go_back.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/gpu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/gpu.jpg -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_01.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_02.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_03.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_04.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_05.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_06.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_07.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_08.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_about.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_arrow_down.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_background_transition.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_background_transition2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_gcta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_gcta.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_info.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_jianjie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_jianjie.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_mian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_mian.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_photo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_photo2.jpg -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_qrcode.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_saoma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_saoma.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_search_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 14 | 15 | 20 | 21 | -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_startup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_startup.jpg -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_tomcat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_tomcat.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_zan_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_zan_black.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/ic_zan_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/ic_zan_w.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/idea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/idea.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/json.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/kt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/kt.jpg -------------------------------------------------------------------------------- /playground/src/main/res/drawable/litho.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/litho.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/phone.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/slide_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /playground/src/main/res/drawable/succeed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/succeed.png -------------------------------------------------------------------------------- /playground/src/main/res/drawable/title_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 9 | 10 | 12 | 13 | -------------------------------------------------------------------------------- /playground/src/main/res/drawable/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanyuankexie/Flexml/f3a76e995184d9d81bb1030484688c7a8e7b7710/playground/src/main/res/drawable/view.png -------------------------------------------------------------------------------- /playground/src/main/res/layout/activity_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 20 | 34 | 43 | 44 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /playground/src/main/res/layout/activity_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 16 | 24 | -------------------------------------------------------------------------------- /playground/src/main/res/layout/banner_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | -------------------------------------------------------------------------------- /playground/src/main/res/layout/console_item.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /playground/src/main/res/layout/feed_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /playground/src/main/res/layout/fragment_code.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | 22 | 27 | 35 | 36 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /playground/src/main/res/layout/idea_popup_window.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 20 | 29 | 30 | -------------------------------------------------------------------------------- /playground/src/main/res/layout/load_more.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 14 | 26 | 32 | 33 | -------------------------------------------------------------------------------- /playground/src/main/res/layout/text_popup_window.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 14 | 19 | 30 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /playground/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Playground 3 | 4 | -------------------------------------------------------------------------------- /playground/src/main/res/values/styleable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /playground/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /playground/src/main/res/values/values.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /playground/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /playground/src/test/java/com/guet/flexbox/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.guet.flexbox 2 | 3 | import okhttp3.OkHttpClient 4 | import okhttp3.Request 5 | import org.junit.Assert 6 | import org.junit.Test 7 | import java.util.concurrent.TimeUnit 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_isCorrect() { 17 | 18 | val okHttpClient = OkHttpClient.Builder() 19 | .connectTimeout(500, TimeUnit.MILLISECONDS) 20 | .build() 21 | val o = okHttpClient.newCall(Request.Builder() 22 | .url("http://localhost:8080/qrcode") 23 | .get() 24 | .build()) 25 | .execute() 26 | println(o) 27 | Assert.assertEquals(4, 2 + 2.toLong()) 28 | } 29 | 30 | 31 | fun findHostAddress(): String? { 32 | 33 | return null 34 | } 35 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':playground', ':core', ':litho', ':compiler', ':handshake' --------------------------------------------------------------------------------