├── .gitignore ├── .idea └── runConfigurations │ └── Android_Studio.xml ├── CHANGELOG.md ├── GOODBYE.md ├── LICENSE ├── README.md ├── anko ├── idea-plugin │ ├── attrs │ │ ├── build.gradle │ │ └── src │ │ │ └── org │ │ │ └── jetbrains │ │ │ └── kotlin │ │ │ └── android │ │ │ └── Attrs.kt │ ├── build.gradle │ ├── idea-runner │ │ └── build.gradle │ ├── intentions │ │ ├── build.gradle │ │ └── src │ │ │ └── org │ │ │ └── jetbrains │ │ │ └── anko │ │ │ └── idea │ │ │ └── intentions │ │ │ ├── AnkoIntention.kt │ │ │ ├── FindViewByIdIntention.kt │ │ │ ├── ReplaceColorGrayOpaqueIntention.kt │ │ │ └── ToastMakeTextShowIntention.kt │ ├── plugin-classpath │ │ └── build.gradle │ ├── preview │ │ ├── build.gradle │ │ ├── resources │ │ │ ├── META-INF │ │ │ │ └── plugin.xml │ │ │ └── intentionDescriptions │ │ │ │ ├── FindViewByIdIntention │ │ │ │ ├── after.kt.template │ │ │ │ ├── before.kt.template │ │ │ │ └── description.html │ │ │ │ ├── ReplaceColorGrayOpaqueIntention │ │ │ │ ├── after.kt.template │ │ │ │ ├── before.kt.template │ │ │ │ └── description.html │ │ │ │ └── ToastMakeTextShowIntention │ │ │ │ ├── after.kt.template │ │ │ │ ├── before.kt.template │ │ │ │ └── description.html │ │ └── src │ │ │ └── org │ │ │ └── jetbrains │ │ │ └── kotlin │ │ │ └── android │ │ │ └── dslpreview │ │ │ ├── AnkoNlPreviewManager.kt │ │ │ ├── AnkoViewLoaderExtension.kt │ │ │ ├── DslPreviewClassResolver.kt │ │ │ ├── LayoutPsiFile.kt │ │ │ ├── PreviewClassDescription.kt │ │ │ ├── SourceFileModificationTracker.kt │ │ │ └── UpdateActivityNameTask.kt │ └── xml-converter │ │ ├── build.gradle │ │ ├── resources │ │ ├── attrs.json │ │ └── views.json │ │ ├── src │ │ └── org │ │ │ └── jetbrains │ │ │ └── kotlin │ │ │ └── android │ │ │ └── xmlconverter │ │ │ ├── AttributeOptimizer.kt │ │ │ ├── AttributeParser.kt │ │ │ ├── ConvertAction.kt │ │ │ ├── LayoutAttributeRenderer.kt │ │ │ ├── Util.kt │ │ │ ├── ViewAttributeRenderer.kt │ │ │ └── XmlConverter.kt │ │ ├── test │ │ └── org │ │ │ └── jetbrains │ │ │ └── kotlin │ │ │ └── android │ │ │ └── xmlconverter │ │ │ ├── BaseXmlConverterTest.java │ │ │ └── XmlConverterTest.kt │ │ └── testData │ │ ├── attributes │ │ ├── layout.kt │ │ └── layout.xml │ │ ├── dimensions │ │ ├── layout.kt │ │ └── layout.xml │ │ ├── linearLayout │ │ ├── layout.kt │ │ └── layout.xml │ │ ├── relativeLayout │ │ ├── layout.kt │ │ └── layout.xml │ │ └── simple │ │ ├── layout.kt │ │ └── layout.xml ├── library │ ├── generated │ │ ├── anko │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ └── AndroidManifest.xml │ │ ├── appcompat-v7-commons │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ └── AndroidManifest.xml │ │ ├── appcompat-v7-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── appcompat-v7-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── appcompat-v7 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ └── Views.kt │ │ ├── cardview-v7 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ └── Views.kt │ │ ├── common │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ └── AndroidManifest.xml │ │ ├── commons │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ └── AndroidManifest.xml │ │ ├── constraint-layout │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ └── Views.kt │ │ ├── coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── bg.kt │ │ │ │ └── weakReferenceSupport.kt │ │ ├── design-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── design-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── design │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ └── Views.kt │ │ ├── gridlayout-v7 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ └── Views.kt │ │ ├── percent │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ └── Views.kt │ │ ├── recyclerview-v7-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── recyclerview-v7-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── recyclerview-v7 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ └── Views.kt │ │ ├── sdk15-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── sdk15-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── sdk15 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ ├── Services.kt │ │ │ │ └── Views.kt │ │ ├── sdk19-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── sdk19-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── sdk19 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ ├── Services.kt │ │ │ │ └── Views.kt │ │ ├── sdk21-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── sdk21-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── sdk21 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ ├── Services.kt │ │ │ │ └── Views.kt │ │ ├── sdk23-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── sdk23-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── sdk23 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ ├── Services.kt │ │ │ │ └── Views.kt │ │ ├── sdk25-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── sdk25-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── sdk25 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ ├── Services.kt │ │ │ │ └── Views.kt │ │ ├── sdk27-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── sdk27-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── sdk27 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ ├── Services.kt │ │ │ │ └── Views.kt │ │ ├── sdk28-coroutines │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ListenersWithCoroutines.kt │ │ ├── sdk28-listeners │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Listeners.kt │ │ ├── sdk28 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── Layouts.kt │ │ │ │ ├── Properties.kt │ │ │ │ ├── Services.kt │ │ │ │ └── Views.kt │ │ ├── sqlite │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── SqlParserHelpers.kt │ │ ├── support-v4-commons │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ └── AndroidManifest.xml │ │ └── support-v4 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ ├── Layouts.kt │ │ │ ├── Listeners.kt │ │ │ └── Views.kt │ ├── generator │ │ ├── build.gradle │ │ ├── src │ │ │ └── org │ │ │ │ └── jetbrains │ │ │ │ └── android │ │ │ │ └── anko │ │ │ │ ├── ClassProcessor.kt │ │ │ │ ├── annotations │ │ │ │ ├── AnnotationManager.kt │ │ │ │ └── annotationProviders.kt │ │ │ │ ├── artifact │ │ │ │ └── Artifact.kt │ │ │ │ ├── config │ │ │ │ ├── AnkoConfiguration.kt │ │ │ │ ├── AnkoFile.kt │ │ │ │ ├── ArtifactType.kt │ │ │ │ ├── ConfigurationKey.kt │ │ │ │ ├── DefaultAnkoConfiguration.kt │ │ │ │ ├── GeneratorContext.kt │ │ │ │ ├── Logger.kt │ │ │ │ ├── Props.kt │ │ │ │ └── configurationKeys.kt │ │ │ │ ├── generator │ │ │ │ ├── GenerationState.kt │ │ │ │ ├── LayoutGenerator.kt │ │ │ │ ├── ListenerGenerator.kt │ │ │ │ ├── PropertyGenerator.kt │ │ │ │ ├── ServiceGenerator.kt │ │ │ │ ├── dslElements.kt │ │ │ │ ├── layoutParamsUtils.kt │ │ │ │ └── viewClassGenerators.kt │ │ │ │ ├── main.kt │ │ │ │ ├── render │ │ │ │ ├── LayoutRenderer.kt │ │ │ │ ├── ListenerRenderer.kt │ │ │ │ ├── PropertyRenderer.kt │ │ │ │ ├── RenderFacade.kt │ │ │ │ ├── ServiceRenderer.kt │ │ │ │ ├── SqlParserHelperRenderer.kt │ │ │ │ ├── viewConstructorUtils.kt │ │ │ │ └── viewRenderers.kt │ │ │ │ ├── sources │ │ │ │ ├── SourceManager.kt │ │ │ │ └── sourceProviders.kt │ │ │ │ ├── templates │ │ │ │ ├── JtwigTemplateProvider.kt │ │ │ │ ├── MustacheTemplateProvider.kt │ │ │ │ └── TemplateManager.kt │ │ │ │ ├── utils │ │ │ │ ├── Buffer.kt │ │ │ │ ├── ClassInfo.kt │ │ │ │ ├── ClassTree.kt │ │ │ │ ├── ClassTreeUtils.kt │ │ │ │ ├── ImportList.kt │ │ │ │ ├── KMethod.kt │ │ │ │ ├── KType.kt │ │ │ │ ├── KVariable.kt │ │ │ │ ├── MethodInfo.kt │ │ │ │ ├── Property.kt │ │ │ │ ├── ReflectionUtils.kt │ │ │ │ ├── SignatureParser.kt │ │ │ │ ├── Types.kt │ │ │ │ ├── stringUtils.kt │ │ │ │ └── utils.kt │ │ │ │ └── writer │ │ │ │ ├── AbstractWriter.kt │ │ │ │ ├── GeneratorWriter.kt │ │ │ │ └── VerifyWriter.kt │ │ └── test │ │ │ └── org │ │ │ └── jetbrains │ │ │ └── android │ │ │ └── anko │ │ │ └── ClassTreeTest.java │ ├── library.gradle │ ├── robolectricTests │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── local.properties │ │ └── src │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ ├── AndroidLayoutParamsTestActivity.kt │ │ │ │ ├── AndroidLayoutsTestActivity.kt │ │ │ │ ├── AndroidListenerHelpersTestActivity.kt │ │ │ │ ├── AndroidMultiMethodListenersActivity.kt │ │ │ │ ├── AndroidPropertiesTestActivity.kt │ │ │ │ ├── AndroidSimpleTestActivity.kt │ │ │ │ ├── AndroidWidgetTestActivity.kt │ │ │ │ └── README.md │ │ │ └── test │ │ │ └── java │ │ │ ├── AnkoLoggerTest.kt │ │ │ ├── AnkoSQliteTest.kt │ │ │ ├── AttemptTest.kt │ │ │ ├── BuildSpannedTest.kt │ │ │ ├── BundleOfTest.kt │ │ │ ├── ChildrenSequenceTest.kt │ │ │ ├── ClassParserTest.kt │ │ │ ├── CollectionsTest.kt │ │ │ ├── CreateIntentTest.kt │ │ │ ├── DialogsTest.kt │ │ │ ├── FindViewTest.kt │ │ │ ├── IntentForTest.kt │ │ │ ├── RelativeLayoutHelpersTest.kt │ │ │ ├── ServiceTest.kt │ │ │ ├── SimpleTest.kt │ │ │ ├── SparseArraysTest.kt │ │ │ └── WithArgumentsTest.kt │ ├── static │ │ ├── appcompatV7 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── SupportAlertBuilder.kt │ │ ├── commons │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── AnkoContext.kt │ │ │ │ ├── Async.kt │ │ │ │ ├── ContextUtils.kt │ │ │ │ ├── Custom.kt │ │ │ │ ├── Deprecated.kt │ │ │ │ ├── Dimensions.kt │ │ │ │ ├── Helpers.kt │ │ │ │ ├── Intents.kt │ │ │ │ ├── Internals.kt │ │ │ │ ├── Logging.kt │ │ │ │ ├── RelativeLayoutLayoutParamsHelpers.kt │ │ │ │ ├── SharedPreferences.kt │ │ │ │ ├── Theme.kt │ │ │ │ ├── Ui.kt │ │ │ │ ├── buildSpanned.kt │ │ │ │ ├── collections │ │ │ │ ├── Arrays.kt │ │ │ │ ├── Collections.kt │ │ │ │ └── SparseArrays.kt │ │ │ │ ├── dialogs │ │ │ │ ├── AlertBuilder.kt │ │ │ │ ├── AlertDialogBuilder.kt │ │ │ │ ├── AndroidAlertBuilder.kt │ │ │ │ ├── AndroidDialogs.kt │ │ │ │ ├── AndroidSelectors.kt │ │ │ │ ├── Dialogs.kt │ │ │ │ ├── Selectors.kt │ │ │ │ └── Toasts.kt │ │ │ │ ├── menuItemsSequences.kt │ │ │ │ └── viewChildrenSequences.kt │ │ ├── constraint-layout │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── ConstraintLayout.kt │ │ ├── design │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── Snackbar.kt │ │ ├── platform │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── CustomLayoutProperties.kt │ │ │ │ ├── CustomServices.kt │ │ │ │ ├── CustomViewProperties.kt │ │ │ │ ├── CustomViews.kt │ │ │ │ ├── InputConstraints.kt │ │ │ │ └── Menus.kt │ │ ├── sqlite │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ ├── ClassParser.kt │ │ │ │ ├── Database.kt │ │ │ │ ├── SelectQueryBuilder.kt │ │ │ │ ├── SqlParsers.kt │ │ │ │ ├── UpdateQueryBuilder.kt │ │ │ │ ├── org │ │ │ │ └── jetbrains │ │ │ │ │ └── anko │ │ │ │ │ └── db │ │ │ │ │ └── JavaSqliteUtils.java │ │ │ │ └── sqlTypes.kt │ │ └── supportV4 │ │ │ ├── build.gradle │ │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ ├── Support.kt │ │ │ ├── SupportAsync.kt │ │ │ ├── SupportContextUtils.kt │ │ │ ├── SupportDialogs.kt │ │ │ ├── SupportDimensions.kt │ │ │ └── SupportIntents.kt │ ├── stubs │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── Stubs.kt │ └── testUtils │ │ ├── build.gradle │ │ └── src │ │ ├── com │ │ └── intellij │ │ │ └── rt │ │ │ └── execution │ │ │ └── junit │ │ │ ├── FileComparisonFailure.java │ │ │ └── KnownException.kt │ │ └── org │ │ └── jetbrains │ │ └── anko │ │ └── test │ │ └── testUtils.kt └── props │ ├── annotations │ └── android │ │ ├── support │ │ └── v7 │ │ │ └── widget │ │ │ └── annotations.xml │ │ ├── view │ │ └── annotations.xml │ │ └── widget │ │ └── annotations.xml │ ├── configuration.json │ ├── excluded_methods.txt │ ├── excluded_properties.txt │ ├── helper_constructors.txt │ ├── imports_properties.txt │ ├── imports_sqliteparserhelpers.txt │ ├── imports_views.txt │ ├── kotlin-android-sdk-annotations-1.0.0.jar │ ├── properties_without_getters.txt │ └── templates │ ├── complex_listener.twig │ ├── complex_listener_coroutines.twig │ ├── layout.twig │ ├── services.twig │ ├── simple_listener.mustache │ ├── simple_listener_coroutines.twig │ ├── sql_parser_helpers.twig │ └── view.mustache ├── build.gradle ├── doc ├── helloworld.png ├── logo.png └── preview.png ├── download_android_sdk.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── update_dependencies.xml └── update_dependencies_idea.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /dependencies/ 2 | /ideaSDK/ 3 | build/ 4 | .DS_Store 5 | *.iml 6 | .gradle 7 | /out 8 | .idea/* 9 | !.idea/runConfigurations 10 | local.properties 11 | -------------------------------------------------------------------------------- /anko/idea-plugin/attrs/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'kotlin' 2 | 3 | sourceSets { 4 | main { 5 | java.srcDirs = ['src'] 6 | kotlin.srcDirs = ['src'] 7 | } 8 | } 9 | 10 | dependencies { 11 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 12 | compile project(':ide:plugin-classpath') 13 | } -------------------------------------------------------------------------------- /anko/idea-plugin/attrs/src/org/jetbrains/kotlin/android/Attrs.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.jetbrains.kotlin.android.attrs 18 | 19 | import java.io.File 20 | 21 | data class NameValue( 22 | val name: String = "", 23 | val value: String = "") 24 | 25 | data class Attr( 26 | val name: String = "", 27 | val format: List = emptyList(), 28 | val flags: List? = null, 29 | val enum: List? = null) 30 | 31 | val NoAttr: Attr = Attr() 32 | 33 | data class Styleable( 34 | val name: String = "", 35 | val attrs: List = emptyList()) 36 | 37 | data class Attrs( 38 | val free: List = emptyList(), 39 | val styleables: Map = emptyMap()) 40 | 41 | fun readResource(filename: String): String { 42 | return Attrs::class.java.classLoader.getResourceAsStream(filename)?.reader()?.readText() 43 | ?: File(filename).readText() 44 | } -------------------------------------------------------------------------------- /anko/idea-plugin/build.gradle: -------------------------------------------------------------------------------- 1 | subprojects { 2 | apply plugin: 'kotlin' 3 | 4 | sourceSets { 5 | main { 6 | java.srcDirs = ['src', 'resources'] 7 | kotlin.srcDirs = ['src'] 8 | resources.srcDirs = ['resources'] 9 | } 10 | } 11 | 12 | dependencies { 13 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 14 | } 15 | } -------------------------------------------------------------------------------- /anko/idea-plugin/idea-runner/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: new File(project.rootDir, "ideaSDK/lib"), include: ['*.jar']) 5 | } -------------------------------------------------------------------------------- /anko/idea-plugin/intentions/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'kotlin' 2 | 3 | sourceSets { 4 | main { 5 | java.srcDirs = ['src'] 6 | kotlin.srcDirs = ['src'] 7 | } 8 | } 9 | 10 | dependencies { 11 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 12 | compile project(':ide:plugin-classpath') 13 | } -------------------------------------------------------------------------------- /anko/idea-plugin/intentions/src/org/jetbrains/anko/idea/intentions/FindViewByIdIntention.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.anko.idea.intentions 2 | 3 | import com.intellij.psi.PsiElement 4 | import org.jetbrains.kotlin.idea.caches.resolve.analyze 5 | import org.jetbrains.kotlin.psi.* 6 | import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall 7 | 8 | class FindViewByIdIntention : AnkoIntention( 9 | KtExpression::class.java, 10 | "Simplify findViewById() with Anko" 11 | ) { 12 | override fun isApplicable(element: KtExpression, caretOffset: Int): Boolean { 13 | fun PsiElement?.requireFindViewByIdCall() = requireCall(FIND_VIEW_BY_ID, 1) { 14 | val resolvedCall = getResolvedCall(analyze()) 15 | isValueParameterTypeOf(0, resolvedCall, "kotlin.Int") 16 | && isReceiverParameterTypeOf(resolvedCall, FqNames.ACTIVITY_FQNAME, FqNames.VIEW_FQNAME) 17 | } 18 | 19 | return element.require() { 20 | operation.require("as") 21 | && (left.requireFindViewByIdCall() || left.require { 22 | selector.requireFindViewByIdCall() 23 | }) 24 | } 25 | } 26 | 27 | override fun replaceWith(element: KtExpression, psiFactory: KtPsiFactory): NewElement? { 28 | fun KtCallExpression.createElement(type: String, receiver: String? = null): NewElement { 29 | val id = valueArguments[0].text 30 | val receiverWithDot = if (receiver == null) "" else "$receiver." 31 | val newExpression = psiFactory.createExpression("${receiverWithDot}find<$type>($id)") 32 | return NewElement(newExpression, "find") 33 | } 34 | 35 | element.require() { 36 | val type = right?.text ?: return null 37 | 38 | left.requireCall(FIND_VIEW_BY_ID) { 39 | return createElement(type) 40 | } 41 | left.require { 42 | selector.requireCall(FIND_VIEW_BY_ID) { 43 | return createElement(type, receiver?.text) 44 | } 45 | } 46 | } 47 | return null 48 | } 49 | 50 | private companion object { 51 | val FIND_VIEW_BY_ID = "findViewById" 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /anko/idea-plugin/intentions/src/org/jetbrains/anko/idea/intentions/ToastMakeTextShowIntention.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.jetbrains.anko.idea.intentions 18 | 19 | import org.jetbrains.kotlin.psi.* 20 | 21 | class ToastMakeTextShowIntention : AnkoIntention( 22 | KtExpression::class.java, 23 | "Simplify Toast.makeText().show() with Anko" 24 | ) { 25 | 26 | override fun isApplicable(element: KtExpression, caretOffset: Int): Boolean { 27 | return element.require { 28 | receiver.require { 29 | receiver.require("Toast") 30 | && selector.requireCall("makeText", 3) { 31 | isLongToast() != null && isValueParameterTypeOf(0, null, FqNames.CONTEXT_FQNAME) 32 | } 33 | } 34 | && selector.requireCall("show", 0) 35 | } 36 | } 37 | 38 | private fun KtCallExpression.isLongToast(): Boolean? { 39 | return when (valueArguments[2].text) { 40 | "Toast.LENGTH_SHORT", "LENGTH_SHORT" -> false 41 | "Toast.LENGTH_LONG", "LENGTH_LONG" -> true 42 | else -> null 43 | } 44 | } 45 | 46 | override fun replaceWith(element: KtExpression, psiFactory: KtPsiFactory): NewElement? { 47 | element.require { 48 | receiver.require { 49 | selector.requireCall("makeText") { 50 | val args = valueArguments 51 | val ctxArg = args[0].text 52 | val textArg = args[1].text 53 | 54 | val funName = if (isLongToast()!!) "longToast" else "toast" 55 | val receiver = if (ctxArg == "this") "" else "$ctxArg." 56 | 57 | val newExpression = psiFactory.createExpression("$receiver$funName($textArg)") 58 | return NewElement(newExpression, funName) 59 | } 60 | } 61 | } 62 | return null 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /anko/idea-plugin/plugin-classpath/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: new File(project.rootDir, "ideaSDK/lib"), include: ['*.jar']) 5 | compile fileTree(dir: new File(project.rootDir, "ideaSDK/plugins/android/lib"), include: ['*.jar']) 6 | compile fileTree(dir: new File(project.rootDir, "ideaSDK/plugins/Kotlin/lib"), include: ['kotlin-plugin.jar']) 7 | } -------------------------------------------------------------------------------- /anko/idea-plugin/preview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.johnrengelman.shadow' 2 | apply plugin: 'kotlin' 3 | 4 | sourceSets { 5 | main { 6 | java.srcDirs = ['src'] 7 | kotlin.srcDirs = ['src'] 8 | } 9 | } 10 | 11 | configurations { 12 | shadow 13 | compile.extendsFrom shadow 14 | } 15 | 16 | dependencies { 17 | compile project(':ide:plugin-classpath') 18 | 19 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 20 | shadow "org.jetbrains.kotlinx:kotlinx.dom:$kotlinx_dom_version" 21 | 22 | shadow(project(':ide:attrs')) { 23 | transitive = false 24 | } 25 | shadow(project(':ide:intentions')) { 26 | transitive = false 27 | } 28 | shadow(project(':ide:xml-converter')) { 29 | transitive = false 30 | } 31 | } 32 | 33 | shadowJar { 34 | configurations = [project.configurations.shadow] 35 | } -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | org.jetbrains.kotlin.android.dsl 3 | Anko Support 4 | Anko Android library support. 5 | 0.10.8 6 | JetBrains s.r.o. 7 | 8 | 9 | 10 | org.jetbrains.kotlin 11 | org.jetbrains.android 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | org.jetbrains.anko.idea.intentions.ToastMakeTextShowIntention 26 | Anko 27 | 28 | 29 | 30 | org.jetbrains.anko.idea.intentions.FindViewByIdIntention 31 | Anko 32 | 33 | 34 | 35 | org.jetbrains.anko.idea.intentions.ReplaceColorGrayOpaqueIntention 36 | Anko 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.jetbrains.kotlin.android.dslpreview.AnkoNlPreviewManager 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/FindViewByIdIntention/after.kt.template: -------------------------------------------------------------------------------- 1 | find(R.id.name) -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/FindViewByIdIntention/before.kt.template: -------------------------------------------------------------------------------- 1 | findViewById(R.id.name) as TextView -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/FindViewByIdIntention/description.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This intention replaces 'findViewById() as T' method call with 'find' that is available in Anko. 4 | 5 | -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/ReplaceColorGrayOpaqueIntention/after.kt.template: -------------------------------------------------------------------------------- 1 | 0xCC.gray.opaque -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/ReplaceColorGrayOpaqueIntention/before.kt.template: -------------------------------------------------------------------------------- 1 | 0xFFCCCCCC.toInt() -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/ReplaceColorGrayOpaqueIntention/description.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This intention replaces numeric literals representing Android colors with ones that use Anko `gray` and `opaque` extension properties. 4 | 5 | -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/ToastMakeTextShowIntention/after.kt.template: -------------------------------------------------------------------------------- 1 | toast("Message") -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/ToastMakeTextShowIntention/before.kt.template: -------------------------------------------------------------------------------- 1 | Toast.makeText(this, "Message", Toast.LENGTH_SHORT).show() -------------------------------------------------------------------------------- /anko/idea-plugin/preview/resources/intentionDescriptions/ToastMakeTextShowIntention/description.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This intention replaces 'Toast.makeText(ctx, text, length).show()' method call with 'toast(text)' or 'longToast(text)' that is available in Anko. 4 | 5 | -------------------------------------------------------------------------------- /anko/idea-plugin/preview/src/org/jetbrains/kotlin/android/dslpreview/PreviewClassDescription.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.jetbrains.kotlin.android.dslpreview 18 | 19 | import org.jetbrains.kotlin.psi.KtClass 20 | 21 | class PreviewClassDescription(val ktClass: KtClass, val fqName: String, val internalName: String) { 22 | val packageName = fqName.substringBeforeLast('.') 23 | val name = fqName.substringAfterLast('.') 24 | 25 | override fun toString(): String { 26 | return if (packageName.isNotBlank()) 27 | "$packageName.$name" 28 | else 29 | "$name" 30 | } 31 | 32 | override fun equals(other: Any?): Boolean{ 33 | if (this === other) return true 34 | if (other?.javaClass != javaClass) return false 35 | 36 | other as PreviewClassDescription 37 | 38 | if (fqName != other.fqName) return false 39 | if (internalName != other.internalName) return false 40 | 41 | return true 42 | } 43 | 44 | override fun hashCode(): Int{ 45 | var result = fqName.hashCode() 46 | result += 31 * result + internalName.hashCode() 47 | return result 48 | } 49 | } -------------------------------------------------------------------------------- /anko/idea-plugin/preview/src/org/jetbrains/kotlin/android/dslpreview/SourceFileModificationTracker.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.jetbrains.kotlin.android.dslpreview 18 | 19 | import com.intellij.openapi.util.ModificationTracker 20 | import com.intellij.psi.PsiJavaFile 21 | import com.intellij.psi.impl.PsiTreeChangeEventImpl 22 | import com.intellij.psi.impl.PsiTreeChangePreprocessor 23 | import org.jetbrains.kotlin.psi.KtFile 24 | import java.util.concurrent.atomic.AtomicLong 25 | 26 | class SourceFileModificationTracker : PsiTreeChangePreprocessor, ModificationTracker { 27 | 28 | private val counter = AtomicLong() 29 | 30 | companion object { 31 | private val HANDLED_EVENTS = setOf( 32 | PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED, 33 | PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED, 34 | PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED, 35 | PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED, 36 | PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED) 37 | } 38 | 39 | override fun treeChanged(event: PsiTreeChangeEventImpl) { 40 | if (event.code in HANDLED_EVENTS) { 41 | val file = event.file 42 | if (file is KtFile || file is PsiJavaFile) counter.incrementAndGet() 43 | } 44 | } 45 | 46 | override fun getModificationCount() = counter.get() 47 | } -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'kotlin' 2 | 3 | sourceSets { 4 | main { 5 | java.srcDirs = ['src'] 6 | kotlin.srcDirs = ['src'] 7 | } 8 | test { 9 | java.srcDirs = ['test'] 10 | kotlin.srcDirs = ['test'] 11 | } 12 | } 13 | 14 | dependencies { 15 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 16 | compile "org.jetbrains.kotlinx:kotlinx.dom:$kotlinx_dom_version" 17 | 18 | compile project(':ide:plugin-classpath') 19 | compile project(':ide:attrs') 20 | } -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/resources/views.json: -------------------------------------------------------------------------------- 1 | {"DigitalClock":["TextView"],"Chronometer":["TextView"],"EditText":["TextView"],"Button":["TextView"],"CheckedTextView":["TextView"],"AbsSeekBar":["ProgressBar"],"ImageButton":["ImageView"],"QuickContactBadge":["ImageView"],"VideoView":["SurfaceView"],"GridLayout":["ViewGroup"],"SlidingDrawer":["ViewGroup"],"RelativeLayout":["ViewGroup"],"AbsoluteLayout":["ViewGroup"],"FrameLayout":["ViewGroup"],"LinearLayout":["ViewGroup"],"AdapterView":["ViewGroup"],"AutoCompleteTextView":["EditText","TextView"],"CompoundButton":["Button","TextView"],"SeekBar":["AbsSeekBar","ProgressBar"],"RatingBar":["AbsSeekBar","ProgressBar"],"ZoomButton":["ImageButton","ImageView"],"DialerFilter":["RelativeLayout","ViewGroup"],"TwoLineListItem":["RelativeLayout","ViewGroup"],"HorizontalScrollView":["FrameLayout","ViewGroup"],"TimePicker":["FrameLayout","ViewGroup"],"CalendarView":["FrameLayout","ViewGroup"],"ViewAnimator":["FrameLayout","ViewGroup"],"MediaController":["FrameLayout","ViewGroup"],"TabHost":["FrameLayout","ViewGroup"],"ScrollView":["FrameLayout","ViewGroup"],"DatePicker":["FrameLayout","ViewGroup"],"TableRow":["LinearLayout","ViewGroup"],"SearchView":["LinearLayout","ViewGroup"],"RadioGroup":["LinearLayout","ViewGroup"],"TableLayout":["LinearLayout","ViewGroup"],"ZoomControls":["LinearLayout","ViewGroup"],"NumberPicker":["LinearLayout","ViewGroup"],"TabWidget":["LinearLayout","ViewGroup"],"AbsSpinner":["AdapterView","ViewGroup"],"AdapterViewAnimator":["AdapterView","ViewGroup"],"AbsListView":["AdapterView","ViewGroup"],"MultiAutoCompleteTextView":["AutoCompleteTextView","EditText","TextView"],"CheckBox":["CompoundButton","Button","TextView"],"RadioButton":["CompoundButton","Button","TextView"],"Switch":["CompoundButton","Button","TextView"],"ToggleButton":["CompoundButton","Button","TextView"],"ViewSwitcher":["ViewAnimator","FrameLayout","ViewGroup"],"ViewFlipper":["ViewAnimator","FrameLayout","ViewGroup"],"Gallery":["AbsSpinner","AdapterView","ViewGroup"],"Spinner":["AbsSpinner","AdapterView","ViewGroup"],"AdapterViewFlipper":["AdapterViewAnimator","AdapterView","ViewGroup"],"StackView":["AdapterViewAnimator","AdapterView","ViewGroup"],"ListView":["AbsListView","AdapterView","ViewGroup"],"GridView":["AbsListView","AdapterView","ViewGroup"],"ImageSwitcher":["ViewSwitcher","ViewAnimator","FrameLayout","ViewGroup"],"TextSwitcher":["ViewSwitcher","ViewAnimator","FrameLayout","ViewGroup"],"ExpandableListView":["ListView","AbsListView","AdapterView","ViewGroup"]} -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/src/org/jetbrains/kotlin/android/xmlconverter/AttributeOptimizer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.jetbrains.kotlin.android.xmlconverter 18 | 19 | import org.jetbrains.kotlin.android.attrs.NoAttr 20 | 21 | internal val attributeOptimizations = listOf( 22 | ::optimizeInclude, 23 | ::optimizeHelperConstructors 24 | ) 25 | 26 | internal fun optimizeInclude(name: String, attrs: List): Pair>? { 27 | val layout = attrs.firstOrNull { it.key == "layout" }?.value 28 | return if (name == "include" && layout != null) { 29 | val rendered = renderReference(NoAttr, "layout", layout) 30 | "$name(${rendered?.value ?: layout})" to attrs.filter { it.key != "layout" } 31 | } else null 32 | } 33 | 34 | internal fun optimizeHelperConstructors(name: String, attrs: List): Pair>? { 35 | val helpers = listOf( 36 | attrs.firstOrNull { it.key == "text" }, 37 | attrs.firstOrNull { it.key == "textResource" } 38 | ).filterNotNull() 39 | return if (helpers.isNotEmpty()) { 40 | val helper = helpers.first() 41 | "$name(${helper.value})" to attrs.filter { it.key != helper.key } 42 | } else null 43 | } -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/src/org/jetbrains/kotlin/android/xmlconverter/Util.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.jetbrains.kotlin.android.xmlconverter 18 | 19 | import com.google.gson.Gson 20 | import com.google.gson.reflect.TypeToken 21 | import org.jetbrains.kotlin.android.attrs.Attrs 22 | import org.jetbrains.kotlin.android.attrs.readResource 23 | 24 | private val INTENT = " " 25 | 26 | internal val attrs = Gson().fromJson(readResource("attrs.json"), Attrs::class.java) 27 | 28 | internal val viewHierarchy = Gson().fromJson>>(readResource("views.json"), 29 | (object : TypeToken>>() {}).type) 30 | 31 | internal data class KeyValuePair(val key: String, val value: String) { 32 | override fun toString() = if (value.isNotEmpty()) "$key = $value" else key 33 | } 34 | 35 | internal operator fun String.times(value: String) = KeyValuePair(this, value) 36 | 37 | internal fun List.findFirst(transformer: (T) -> R?): R? { 38 | for (item in this) { 39 | val r = transformer(item) 40 | if (r != null) return r 41 | } 42 | return null 43 | } 44 | 45 | internal fun String.indent(width: Int): String { 46 | if (isEmpty()) return this 47 | val intent = INTENT.repeat(width) 48 | return split('\n').map { intent + it }.joinToString("\n") 49 | } 50 | 51 | internal fun String.swapCamelCase(): String { 52 | val ch = withIndex().firstOrNull { Character.isUpperCase(it.value) } 53 | return if (ch == null) this else substring(ch.index).toLowerCase() + substring(0, ch.index).firstCapital() 54 | } 55 | 56 | internal fun String.firstCapital(): String = if (isEmpty()) this else Character.toUpperCase(this[0]) + substring(1) -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/test/org/jetbrains/kotlin/android/xmlconverter/BaseXmlConverterTest.java: -------------------------------------------------------------------------------- 1 | package org.jetbrains.kotlin.android.xmlconverter; 2 | 3 | import static kotlin.collections.SetsKt.setOf; 4 | import static kotlin.io.FilesKt.readText; 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import java.io.File; 9 | 10 | import kotlin.text.Charsets; 11 | import org.junit.Rule; 12 | import org.junit.rules.TestName; 13 | 14 | public class BaseXmlConverterTest { 15 | 16 | @Rule 17 | public TestName name = new TestName(); 18 | 19 | protected void doLayoutTest() { 20 | File testDataDir = new File("testData"); 21 | String testName = name.getMethodName(); 22 | if (!testName.startsWith("test")) { 23 | throw new IllegalStateException("Test name must start with a 'test' preffix"); 24 | } 25 | 26 | File testDir = new File(testDataDir, decapitalize(testName.substring("test".length()))); 27 | File inputFile = new File(testDir, "layout.xml"); 28 | File outputFile = new File(testDir, "layout.kt"); 29 | 30 | assertTrue(inputFile + " does not exist", inputFile.exists()); 31 | assertTrue(outputFile + " does not exist", outputFile.exists()); 32 | 33 | String actual = XmlConverter.INSTANCE.convert(readText(inputFile, Charsets.UTF_8), setOf("raw")); 34 | String expected = readText(outputFile, Charsets.UTF_8); 35 | 36 | assertEquals(expected, actual); 37 | } 38 | 39 | private String decapitalize(String original) { 40 | if (original.isEmpty()) return original; 41 | return Character.toLowerCase(original.charAt(0)) + original.substring(1); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/test/org/jetbrains/kotlin/android/xmlconverter/XmlConverterTest.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.kotlin.android.xmlconverter 2 | 3 | import org.junit.Test 4 | 5 | class XmlConverterTest : BaseXmlConverterTest() { 6 | 7 | @Test fun testSimple() = doLayoutTest() 8 | @Test fun testLinearLayout() = doLayoutTest() 9 | @Test fun testRelativeLayout() = doLayoutTest() 10 | @Test fun testDimensions() = doLayoutTest() 11 | @Test fun testAttributes() = doLayoutTest() 12 | 13 | } -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/testData/attributes/layout.kt: -------------------------------------------------------------------------------- 1 | frameLayout { 2 | textView("Text") { 3 | backgroundColor = 0xff0000.opaque 4 | enabled = false 5 | hint = "Hint" 6 | id = Ids.textView1 7 | lines = 5 8 | paddingBottom = dip(4) 9 | paddingLeft = dip(1) 10 | paddingRight = dip(3) 11 | paddingTop = dip(2) 12 | tag = "Tag" 13 | textColor = 0x00ff00.opaque 14 | textSize = 17f 15 | visibility = View.INVISIBLE 16 | }.lparams(width = wrapContent, height = wrapContent) 17 | textView { 18 | backgroundColor = 0xeeffff00.toInt() 19 | textSize = 17f 20 | }.lparams(width = wrapContent, height = wrapContent) 21 | textView { 22 | backgroundResource = android.R.color.background_light 23 | textSize = 17f 24 | }.lparams(width = wrapContent, height = wrapContent) 25 | } -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/testData/attributes/layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/testData/dimensions/layout.kt: -------------------------------------------------------------------------------- 1 | linearLayout { 2 | button.lparams(width = wrapContent, height = wrapContent) { 3 | leftMargin = dip(0.5f) 4 | topMargin = dip(1) 5 | rightMargin = sp(2) 6 | bottomMargin = px(3) 7 | } 8 | button.lparams(width = wrapContent, height = wrapContent) 9 | } -------------------------------------------------------------------------------- /anko/idea-plugin/xml-converter/testData/dimensions/layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 |