├── .editorconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── README_EN.md ├── _config.yml ├── art ├── generator-mvvm-kotlin.gif └── newapp.png ├── generators └── app │ ├── index.js │ └── templates │ └── template-mvvm-kotlin │ ├── .gradle │ ├── 4.10.2 │ │ ├── fileChanges │ │ │ └── last-build.bin │ │ ├── fileHashes │ │ │ ├── fileHashes.bin │ │ │ └── fileHashes.lock │ │ └── gc.properties │ └── vcs-1 │ │ └── gc.properties │ ├── .project │ ├── .settings │ └── org.eclipse.buildship.core.prefs │ ├── README.md │ ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── io │ │ │ └── ditclear │ │ │ └── app │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── core │ │ │ ├── kotlin │ │ │ │ └── io │ │ │ │ │ └── ditclear │ │ │ │ │ └── app │ │ │ │ │ ├── CoreService.kt │ │ │ │ │ ├── aop │ │ │ │ │ ├── annotation │ │ │ │ │ │ └── SingleClick.kt │ │ │ │ │ └── aspect │ │ │ │ │ │ └── SingleClickAspect.kt │ │ │ │ │ ├── helper │ │ │ │ │ ├── Constants.kt │ │ │ │ │ ├── adapter │ │ │ │ │ │ └── viewpager │ │ │ │ │ │ │ └── AbstractPagerAdapter.kt │ │ │ │ │ ├── binds │ │ │ │ │ │ └── NormalBind.kt │ │ │ │ │ ├── extens │ │ │ │ │ │ ├── RxExtens.kt │ │ │ │ │ │ └── ViewExtens.kt │ │ │ │ │ ├── network │ │ │ │ │ │ ├── NetInterceptor.kt │ │ │ │ │ │ ├── NetMgr.kt │ │ │ │ │ │ ├── NetProvider.kt │ │ │ │ │ │ └── RequestHandler.kt │ │ │ │ │ └── uitls │ │ │ │ │ │ ├── SystemBarHelper.java │ │ │ │ │ │ └── ToastUtil.kt │ │ │ │ │ ├── view │ │ │ │ │ └── base │ │ │ │ │ │ ├── BaseActivity.kt │ │ │ │ │ │ ├── BaseFragment.kt │ │ │ │ │ │ └── Presenter.kt │ │ │ │ │ └── viewmodel │ │ │ │ │ └── BaseViewModel.kt │ │ │ └── res │ │ │ │ ├── layout │ │ │ │ └── core_layout_holder.xml │ │ │ │ └── values │ │ │ │ └── ids.xml │ │ ├── java │ │ │ └── io │ │ │ │ └── ditclear │ │ │ │ └── app │ │ │ │ ├── App.kt │ │ │ │ ├── di │ │ │ │ └── app_module.kt │ │ │ │ └── view │ │ │ │ └── main │ │ │ │ ├── MainActivity.kt │ │ │ │ └── viewmodel │ │ │ │ └── MainViewModel.kt │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ └── main_activity.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── io │ │ └── ditclear │ │ └── app │ │ └── ExampleUnitTest.kt │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── gulpfile.js ├── package-lock.json ├── package.json └── test └── app.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - v7 4 | - v6 -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2019 ditclear(https://github.com/ditclear) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # generator-mvvm-kotlin 2 | 3 | > 为[《MVVM With Kotin》](https://www.jianshu.com/c/50336d57e9b0) 系列 打造的脚手架工具,提供CLI支持,免去重复创建Android工程的烦恼 4 | 5 | 6 | 7 | [English Version](README_EN.md) 8 | 9 | #### Stack:MVVM/Kotlin/DataBinding/Rxjava2/Retrofit2/AAC/Koin/AOP 10 | 11 | 你可以查看以下链接学习如何使用Kotlin构建MVVM应用程序 12 | 13 | > 简书专题: 14 | > 15 | > 小专栏: 16 | 17 | 18 | 19 | ![](art/generator-mvvm-kotlin.gif) 20 | 21 | ![](art/newapp.png) 22 | 23 | 24 | 25 | ### Installation 26 | 27 | 首先,使用npm安装 [Yeoman](http://yeoman.io)和[generator-mvvm-kotlin](https://www.npmjs.com/package/generator-mvvm-kotlin) 28 | 29 | ```bash 30 | npm install -g yo 31 | npm install -g generator-mvvm-kotlin 32 | ``` 33 | 34 | 然后便可以快速搭建MVVM-Kotlin项目: 35 | 36 | ```bash 37 | mkdir NewApp 38 | cd NewApp 39 | yo mvvm-kotlin 40 | ``` 41 | 42 | ### Thanks To 43 | 44 | ### [ravidsrk](https://github.com/ravidsrk) 45 | 46 | #### If it saves your time , buy Me a Lunch ~ 47 | 48 | 49 | 50 | | Alipay | WeChatPay | 51 | | :----------------------------------------------------------: | :----------------------------------------------------------: | 52 | | ![](https://upload-images.jianshu.io/upload_images/3722695-ffde170fec931eae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/340) | ![](https://upload-images.jianshu.io/upload_images/3722695-1b827a54ec274e59.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/340) | 53 | 54 | ### LICENSE 55 | 56 | ```txt 57 | Copyright 2019 ditclear(https://github.com/ditclear) 58 | 59 | Licensed under the Apache License, Version 2.0 (the "License"); 60 | you may not use this file except in compliance with the License. 61 | You may obtain a copy of the License at 62 | 63 | http://www.apache.org/licenses/LICENSE-2.0 64 | 65 | Unless required by applicable law or agreed to in writing, software 66 | distributed under the License is distributed on an "AS IS" BASIS, 67 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 68 | See the License for the specific language governing permissions and 69 | limitations under the License. 70 | ``` 71 | 72 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # generator-mvvm-kotlin 2 | 3 | > An Kotlin MVVM Boilerplate for Android to save me having to create the same project over from scratch every time! :) 4 | 5 | #### Stack:MVVM/Kotlin/DataBinding/Rxjava2/Retrofit2/AAC/Koin/AOP 6 | 7 | 8 | 9 | ![](art/generator-mvvm-kotlin.gif) 10 | 11 | ![](art/newapp.png) 12 | 13 | 14 | 15 | ### Installation 16 | 17 | First, install [Yeoman](http://yeoman.io) and generator-mvvm-kotlin using [npm](https://www.npmjs.com/) (we assume you have pre-installed [node.js](https://nodejs.org/)). 18 | 19 | ```bash 20 | npm install -g yo 21 | npm install -g generator-mvvm-kotlin 22 | ``` 23 | 24 | Then generate your new project: 25 | 26 | ```bash 27 | mkdir NewApp 28 | cd NewApp 29 | yo mvvm-kotlin 30 | ``` 31 | 32 | ### Thanks To 33 | 34 | ### [ravidsrk](https://github.com/ravidsrk) 35 | 36 | #### If it saves your time , buy Me a Lunch ~ 37 | 38 | 39 | 40 | | Alipay | WeChatPay | 41 | | :----------------------------------------------------------: | :----------------------------------------------------------: | 42 | | ![](https://upload-images.jianshu.io/upload_images/3722695-ffde170fec931eae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/340) | ![](https://upload-images.jianshu.io/upload_images/3722695-1b827a54ec274e59.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/340) | 43 | 44 | ### LICENSE 45 | 46 | ```txt 47 | Copyright 2019 ditclear(https://github.com/ditclear) 48 | 49 | Licensed under the Apache License, Version 2.0 (the "License"); 50 | you may not use this file except in compliance with the License. 51 | You may obtain a copy of the License at 52 | 53 | http://www.apache.org/licenses/LICENSE-2.0 54 | 55 | Unless required by applicable law or agreed to in writing, software 56 | distributed under the License is distributed on an "AS IS" BASIS, 57 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 58 | See the License for the specific language governing permissions and 59 | limitations under the License. 60 | ``` 61 | 62 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /art/generator-mvvm-kotlin.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/art/generator-mvvm-kotlin.gif -------------------------------------------------------------------------------- /art/newapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/art/newapp.png -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Generator = require('yeoman-generator'); 4 | const mkdirp = require('mkdirp'); 5 | const yosay = require('yosay'); 6 | const chalk = require('chalk'); 7 | 8 | module.exports = Generator.extend({ 9 | initializing: function () { 10 | this.props = {}; 11 | }, 12 | prompting: function () { 13 | this.log(yosay( 14 | 'Welcome to ' + chalk.red('MVVM Kotlin Starter') + ' generator!' 15 | )); 16 | 17 | const prompts = [ 18 | { 19 | name: 'name', 20 | message: 'What are you calling your app?', 21 | store: true, 22 | default: this.appname // Default to current folder name 23 | }, 24 | { 25 | name: 'package', 26 | message: 'What package will you be publishing the app under?', 27 | store: true, 28 | default: 'com.mycompany.app' 29 | }, 30 | { 31 | name: 'targetSdk', 32 | message: 'What Android SDK will you be targeting?', 33 | store: true, 34 | default: 26 // Android 8.0 (O(7.1+)) 35 | }, 36 | { 37 | name: 'minSdk', 38 | message: 'What is the minimum Android SDK you wish to support?', 39 | store: true, 40 | default: 14 // Android 4.0 (Ice Cream Sandwich) 41 | }]; 42 | 43 | return this.prompt(prompts).then(props => { 44 | this.props.appPackage = props.package; 45 | this.props.appName = props.name; 46 | this.props.appPackage = props.package; 47 | this.props.androidTargetSdkVersion = props.targetSdk; 48 | this.props.androidMinSdkVersion = props.minSdk; 49 | }); 50 | }, 51 | 52 | writing: function () { 53 | var packageDir = this.props.appPackage.replace(/\./g, '/'); 54 | var appFolder = 'template-mvvm-kotlin'; 55 | 56 | mkdirp('app'); 57 | mkdirp('app/src/main/java/' + packageDir); 58 | mkdirp('app/src/main/core/kotlin/' + packageDir); 59 | mkdirp('app/src/main/core/res/layout'); 60 | mkdirp('app/src/main/core/res/values'); 61 | mkdirp('app/src/androidTest/java/' + packageDir); 62 | mkdirp('app/src/test/java/' + packageDir); 63 | var appPath = this.sourceRoot() + '/' + appFolder + '/'; 64 | this.fs.copy(appPath + 'README.md', 'README.md'); 65 | this.fs.copy(appPath + 'build.gradle', 'build.gradle'); 66 | this.fs.copy(appPath + 'gradle.properties', 'gradle.properties'); 67 | this.fs.copy(appPath + 'gradlew', 'gradlew'); 68 | this.fs.copy(appPath + 'gradlew.bat', 'gradlew.bat'); 69 | this.fs.copy(appPath + 'settings.gradle', 'settings.gradle'); 70 | this.fs.copy(appPath + 'app/proguard-rules.pro', 'app/proguard-rules.pro'); 71 | 72 | this.fs.copy(appPath + 'gradle', 'gradle'); 73 | this.fs.copy(appPath + 'app/src/main/res', 'app/src/main/res'); 74 | this.fs.copy(appPath + 'app/src/main/core/res', 'app/src/main/core/res'); 75 | 76 | this.fs.copyTpl(appPath + 'app/build.gradle', 'app/build.gradle', this.props); 77 | this.fs.copyTpl(appPath + 'app/src/main/AndroidManifest.xml', 'app/src/main/AndroidManifest.xml', this.props); 78 | this.fs.copyTpl(appPath + 'app/src/androidTest/java/io/ditclear/app', 'app/src/androidTest/java/' + packageDir, this.props); 79 | this.fs.copyTpl(appPath + 'app/src/test/java/io/ditclear/app', 'app/src/test/java/' + packageDir, this.props); 80 | this.fs.copyTpl(appPath + 'app/src/main/java/io/ditclear/app', 'app/src/main/java/' + packageDir, this.props); 81 | this.fs.copyTpl(appPath + 'app/src/main/core/kotlin/io/ditclear/app', 'app/src/main/core/kotlin/' + packageDir, this.props); 82 | 83 | this.fs.copyTpl(appPath + 'app/src/main/res/layout', 'app/src/main/res/layout', this.props); 84 | this.fs.copyTpl(appPath + 'app/src/main/core/res/layout', 'app/src/main/core/res/layout', this.props); 85 | this.fs.copyTpl(appPath + 'app/src/main/res/values/strings.xml', 'app/src/main/res/values/strings.xml', this.props); 86 | this.fs.copyTpl(appPath + 'app/src/main/core/res/layout', 'app/src/main/core/res/layout', this.props); 87 | } 88 | }); 89 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/.gradle/4.10.2/fileChanges/last-build.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/.gradle/4.10.2/fileHashes/fileHashes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/.gradle/4.10.2/fileHashes/fileHashes.bin -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/.gradle/4.10.2/fileHashes/fileHashes.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/.gradle/4.10.2/fileHashes/fileHashes.lock -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/.gradle/4.10.2/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/.gradle/4.10.2/gc.properties -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/.gradle/vcs-1/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/.gradle/vcs-1/gc.properties -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | template-mvvm-kotlin 4 | Project template-mvvm-kotlin created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/README.md: -------------------------------------------------------------------------------- 1 | ### generator-mvvm-kotlin 2 | 3 | > An Kotlin MVVM Boilerplate For Android to save me having to create the same project over from scratch every time! :) 4 | 5 | **stack**:MVVM/Kotlin/DataBinding/Rxjava2/Retrofit2/ViewModel/LiveData/Room/Dagger2/AOP 6 | 7 | ![](https://user-gold-cdn.xitu.io/2018/11/22/1673bc1247150cea?w=1240&h=607&f=png&s=161830) 8 | 9 | ### 目录: 10 | 11 | - [使用Kotlin构建MVVM应用程序—总览篇](https://www.jianshu.com/p/77e42aebd7bb) 12 | - [使用Kotlin构建MVVM应用程序—第一部分:入门篇](https://www.jianshu.com/p/80926d9e64f7) 13 | - [使用Kotlin构建MVVM应用程序—第二部分:Retrofit及RxJava](https://www.jianshu.com/p/8993b247947a) 14 | - [使用Kotlin构建MVVM应用程序—第三部分:Room](https://www.jianshu.com/p/264d7d0608f0) 15 | - [使用Kotlin构建MVVM应用程序—第四部分:依赖注入Dagger2](https://www.jianshu.com/p/da77266970d8) 16 | - [使用Kotlin构建MVVM应用程序—第五部分:LiveData](https://xiaozhuanlan.com/topic/9753861024) 17 | - [使用Kotlin构建MVVM应用程序—第六部分:单元测试](https://www.jianshu.com/p/2ce583fc3b2d) 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | apply plugin: "kotlin-android" 4 | 5 | apply plugin: "kotlin-kapt" 6 | //aspectj 7 | apply plugin: 'android-aspectjx' 8 | 9 | android { 10 | compileSdkVersion 28 11 | defaultConfig { 12 | applicationId "<%= appPackage %>" 13 | minSdkVersion <%= androidMinSdkVersion %> 14 | targetSdkVersion <%= androidTargetSdkVersion %> 15 | versionCode 1 16 | versionName "1.0" 17 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 18 | 19 | javaCompileOptions { 20 | annotationProcessorOptions { 21 | arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] 22 | } 23 | } 24 | } 25 | buildTypes { 26 | debug { 27 | applicationIdSuffix ".debug" 28 | versionNameSuffix "-debug" 29 | debuggable true 30 | } 31 | release { 32 | applicationIdSuffix ".release" 33 | versionNameSuffix "-release" 34 | debuggable true 35 | minifyEnabled false 36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 37 | } 38 | } 39 | 40 | sourceSets { 41 | main { 42 | java.srcDirs += "src/main/core/kotlin" 43 | res.srcDirs += "src/main/core/res" 44 | } 45 | 46 | } 47 | 48 | dataBinding { 49 | enabled = true 50 | } 51 | } 52 | 53 | aspectjx { 54 | 55 | exclude 'android.support' 56 | } 57 | 58 | dependencies { 59 | implementation fileTree(include: ['*.jar'], dir: 'libs') 60 | ///////////////////////Framework Start/////////////////////////////// 61 | implementation "com.android.support:design:$supportLibVersion" 62 | implementation "com.android.support:recyclerview-v7:$supportLibVersion" 63 | implementation "com.android.support:appcompat-v7:$supportLibVersion" 64 | implementation "com.android.support.constraint:constraint-layout:1.1.3" 65 | //ViewModel 66 | implementation "android.arch.lifecycle:extensions:$archLifecycleVersion" 67 | implementation "android.arch.lifecycle:viewmodel:$archLifecycleVersion" 68 | kapt "android.arch.lifecycle:compiler:$archLifecycleVersion" 69 | //kotlin 70 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 71 | //aspectj 72 | implementation "org.aspectj:aspectjrt:1.8.13" 73 | //bindinglistadapter 74 | implementation 'com.ditclear:bindinglistadapter:1.0.1' 75 | //rx android 76 | implementation "io.reactivex.rxjava2:rxandroid:2.1.0" 77 | implementation "io.reactivex.rxjava2:rxjava:2.2.2" 78 | //autodispose 79 | implementation "com.uber.autodispose:autodispose:0.8.0" 80 | implementation "com.uber.autodispose:autodispose-android-archcomponents:0.8.0" 81 | //di 82 | implementation "org.koin:koin-android-viewmodel:$koin_version" 83 | //retrofit 84 | implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" 85 | implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" 86 | implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion" 87 | implementation "com.squareup.okhttp3:logging-interceptor:3.10.0" 88 | implementation "com.google.code.gson:gson:2.8.5" 89 | //room 90 | implementation "android.arch.persistence.room:runtime:" + rootProject.archRoomVersion 91 | implementation "android.arch.persistence.room:rxjava2:" + rootProject.archRoomVersion 92 | kapt "android.arch.persistence.room:compiler:" + rootProject.archRoomVersion 93 | //image 94 | implementation "com.github.bumptech.glide:glide:3.7.0" 95 | implementation "jp.wasabeef:glide-transformations:2.0.1" 96 | 97 | ///////////unit test/////////////// 98 | testImplementation "junit:junit:4.12" 99 | //////////ui test////////////////// 100 | androidTestImplementation("com.android.support.test.espresso:espresso-core:2.2.2", { 101 | exclude group: "com.android.support", module: "support-annotations" 102 | exclude group: "com.google.code.findbugs", module: "jsr305" 103 | }) 104 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/androidTest/java/io/ditclear/app/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %> 2 | 3 | import android.support.test.InstrumentationRegistry 4 | import android.support.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("<%= appPackage %>", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/CoreService.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %> 2 | 3 | import android.app.Application 4 | 5 | /** 6 | * 页面描述:CoreService spi 加载 7 | * 8 | * Created by ditclear on 2018/11/28. 9 | */ 10 | interface CoreService{ 11 | 12 | val serviceName:String 13 | 14 | fun init(app:Application) 15 | 16 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/aop/annotation/SingleClick.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.aop.annotation 2 | 3 | /** 4 | * Created by ditclear 5 | * 6 | * 防止View被快速点击 7 | */ 8 | @Retention(AnnotationRetention.BINARY) 9 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) 10 | annotation class SingleClick 11 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/aop/aspect/SingleClickAspect.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.aop.aspect 2 | 3 | import android.util.Log 4 | import android.view.View 5 | import <%= appPackage %>.BuildConfig 6 | import <%= appPackage %>.R 7 | import org.aspectj.lang.ProceedingJoinPoint 8 | import org.aspectj.lang.annotation.Around 9 | import org.aspectj.lang.annotation.Aspect 10 | import org.aspectj.lang.annotation.Pointcut 11 | import java.util.* 12 | 13 | 14 | /** 15 | * Created by baixiaokang on 16/12/9. 16 | * {link https://github.com/north2016/T-MVP/blob/master/app/src/main/java/com/aop/SingleClickAspect.java} 17 | * 防止View被连续点击,间隔时间600ms 18 | */ 19 | 20 | @Aspect 21 | class SingleClickAspect { 22 | 23 | @Pointcut("execution(@<%= appPackage %>.aop.annotation.SingleClick * *(..))") //方法切入点 24 | fun methodAnnotated() { 25 | 26 | } 27 | 28 | @Around("methodAnnotated()")//在连接点进行方法替换 29 | @Throws(Throwable::class) 30 | fun aroundJoinPoint(joinPoint: ProceedingJoinPoint) { 31 | var view: View? = null 32 | for (arg in joinPoint.args) { 33 | if (arg is View) view = arg 34 | } 35 | if (view != null) { 36 | val tag = view.getTag(TIME_TAG) 37 | val lastClickTime = if (tag != null) tag as Long else 0 38 | if (BuildConfig.DEBUG) { 39 | Log.d(TAG, "lastClickTime:" + lastClickTime) 40 | } 41 | val currentTime = Calendar.getInstance().timeInMillis 42 | if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {//过滤掉600毫秒内的连续点击 43 | view.setTag(TIME_TAG, currentTime) 44 | if (BuildConfig.DEBUG) { 45 | Log.d(TAG, "currentTime:" + currentTime) 46 | } 47 | joinPoint.proceed()//执行原方法 48 | } 49 | } 50 | } 51 | 52 | companion object { 53 | 54 | val TAG = "SingleClickAspect" 55 | val MIN_CLICK_DELAY_TIME = 600 56 | internal var TIME_TAG = R.id.click_time 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/Constants.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper 2 | 3 | /** 4 | * 页面描述: 5 | * 6 | * Created by ditclear on 2017/10/2. 7 | */ 8 | 9 | object Constants { 10 | const val NORMAL = 0 11 | const val WARNING = 1 12 | const val ERROR = 2 13 | const val SUCCESS = 3 14 | 15 | } 16 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/adapter/viewpager/AbstractPagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.adapter.viewpager 2 | 3 | import android.support.v4.app.Fragment 4 | import android.support.v4.app.FragmentManager 5 | import android.support.v4.app.FragmentStatePagerAdapter 6 | 7 | /** 8 | * 页面描述:fragment PagerAdapter 9 | * 10 | * Created by ditclear on 2017/9/30. 11 | */ 12 | 13 | abstract class AbstractPagerAdapter(fm: FragmentManager, var title: Array) : FragmentStatePagerAdapter(fm) { 14 | var list :MutableList = mutableListOf() 15 | 16 | init { 17 | title.iterator().forEach { list.add(null) } 18 | } 19 | 20 | override fun getCount(): Int = title.size 21 | 22 | abstract override fun getItem(pos: Int): Fragment? 23 | 24 | override fun getPageTitle(position: Int): CharSequence = title[position] 25 | 26 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/binds/NormalBind.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.binds 2 | 3 | import android.databinding.BindingAdapter 4 | import android.widget.ImageView 5 | import com.bumptech.glide.Glide 6 | 7 | /** 8 | * 页面描述:normal bind class 9 | * 10 | * Created by ditclear on 2017/10/2. 11 | */ 12 | 13 | @BindingAdapter(value = ["url"]) 14 | fun bindUrl(imageView: ImageView, url: String?) { 15 | 16 | Glide.with(imageView.context).load(url).into(imageView) 17 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/extens/RxExtens.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.extens 2 | 3 | import android.arch.lifecycle.* 4 | import com.uber.autodispose.AutoDispose 5 | import com.uber.autodispose.SingleSubscribeProxy 6 | import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider 7 | import io.reactivex.BackpressureStrategy 8 | import io.reactivex.Flowable 9 | import io.reactivex.Single 10 | import io.reactivex.android.MainThreadDisposable 11 | import io.reactivex.android.schedulers.AndroidSchedulers 12 | import io.reactivex.schedulers.Schedulers 13 | import java.util.concurrent.TimeUnit 14 | 15 | /** 16 | * 页面描述:RxjavaExtens 17 | * 18 | * Created by ditclear on 2018/12/11. 19 | */ 20 | 21 | ////////////////////////////////////////RxJava扩展//////////////////////////////////////// 22 | 23 | fun Flowable.async(withDelay: Long = 0): Flowable = 24 | this.subscribeOn(Schedulers.io()).delay(withDelay, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()) 25 | 26 | fun Single.async(withDelay: Long = 0): Single = 27 | this.subscribeOn(Schedulers.io()).delay(withDelay, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()) 28 | 29 | 30 | fun Single.bindLifeCycle(owner: LifecycleOwner): SingleSubscribeProxy = 31 | this.`as`(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(owner, Lifecycle.Event.ON_DESTROY))) 32 | 33 | ////////////////////////////////////////LiveData扩展//////////////////////////////////////// 34 | fun LiveData.toFlowable(): Flowable = Flowable.create({ emitter -> 35 | val observer = Observer { data -> 36 | data?.let { emitter.onNext(it) } 37 | } 38 | observeForever(observer) 39 | 40 | emitter.setCancellable { 41 | object : MainThreadDisposable() { 42 | override fun onDispose() = removeObserver(observer) 43 | } 44 | } 45 | }, BackpressureStrategy.LATEST) 46 | 47 | fun MutableLiveData.set(value :T ?) = postValue(value) 48 | 49 | fun MutableLiveData.get() = value 50 | 51 | fun MutableLiveData.init(t:T?=null) = MediatorLiveData().apply { 52 | set(t) 53 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/extens/ViewExtens.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.extens 2 | 3 | import android.app.Activity 4 | import android.support.annotation.ColorRes 5 | import android.support.annotation.DimenRes 6 | import android.support.v4.content.ContextCompat 7 | import android.util.Log 8 | import android.widget.Toast 9 | import <%= appPackage %>.BuildConfig 10 | import <%= appPackage %>.helper.Constants 11 | import <%= appPackage %>.helper.uitls.ToastUtil 12 | import java.net.ConnectException 13 | import java.net.SocketTimeoutException 14 | import java.net.UnknownHostException 15 | 16 | 17 | /** 18 | * description:some extens 19 | * 20 | * Created by ditclear on 2017/9/29. 21 | */ 22 | 23 | fun Activity.getCompactColor(@ColorRes colorRes: Int): Int = ContextCompat.getColor(this, colorRes) 24 | 25 | fun Activity.dpToPx(@DimenRes resID: Int): Int = this.resources.getDimensionPixelOffset(resID) 26 | 27 | fun Any.logD(msg: String?) { 28 | if (BuildConfig.DEBUG) { 29 | Log.d(javaClass.simpleName, msg) 30 | } 31 | } 32 | 33 | fun Activity.toast(msg: CharSequence, duration: Int = Toast.LENGTH_SHORT, type: Int = Constants.NORMAL) { 34 | when (type) { 35 | Constants.WARNING -> ToastUtil.warning(this, msg, duration) 36 | Constants.ERROR -> ToastUtil.error(this, msg, duration) 37 | Constants.NORMAL -> ToastUtil.info(this, msg, duration) 38 | Constants.SUCCESS -> ToastUtil.success(this, msg, duration) 39 | } 40 | } 41 | 42 | 43 | fun Activity.dispatchFailure(error: Throwable?) { 44 | error?.let { 45 | if (BuildConfig.DEBUG) { 46 | it.printStackTrace() 47 | } 48 | if (error is SocketTimeoutException) { 49 | it.message?.let { toast("网络连接超时", Constants.ERROR) } 50 | 51 | } else if (it is UnknownHostException || it is ConnectException) { 52 | //网络未连接 53 | it.message?.let { toast("网络未连接", Constants.ERROR) } 54 | 55 | } else { 56 | it.message?.let { toast(it, Constants.ERROR) } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/network/NetInterceptor.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.network 2 | 3 | import okhttp3.Interceptor 4 | import okhttp3.Response 5 | import java.io.IOException 6 | 7 | 8 | /** 9 | * 页面描述:默认拦截器 10 | * 11 | * 12 | * Created by ditclear on 2017/7/28. 13 | */ 14 | 15 | class NetInterceptor(private val handler: RequestHandler?) : Interceptor { 16 | 17 | @Throws(IOException::class) 18 | override fun intercept(chain: Interceptor.Chain): Response { 19 | var request = chain.request() 20 | 21 | 22 | if (handler != null) { 23 | request = handler.onBeforeRequest(request, chain) 24 | } 25 | 26 | val response = chain.proceed(request) 27 | 28 | 29 | if (handler != null) { 30 | val tmp = handler.onAfterRequest(response, chain) 31 | if (tmp != null) { 32 | return tmp 33 | } 34 | 35 | } 36 | return response 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/network/NetMgr.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.network 2 | 3 | 4 | import com.google.gson.GsonBuilder 5 | import okhttp3.Interceptor 6 | import okhttp3.OkHttpClient 7 | import okhttp3.logging.HttpLoggingInterceptor 8 | import retrofit2.Retrofit 9 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory 10 | import retrofit2.converter.gson.GsonConverterFactory 11 | import java.util.* 12 | import java.util.concurrent.TimeUnit 13 | 14 | /** 15 | * 页面描述:网络管理类 16 | * 17 | * 18 | * Created by ditclear on 2017/7/28. 19 | */ 20 | 21 | object NetMgr { 22 | private val providerMap = HashMap() 23 | private val retrofitMap = HashMap() 24 | private val clientMap = HashMap() 25 | 26 | @JvmOverloads 27 | fun getRetrofit(baseUrl: String, provider: NetProvider? = null): Retrofit { 28 | var provider = provider 29 | if (empty(baseUrl)) { 30 | throw IllegalStateException("baseUrl can not be null") 31 | } 32 | if (retrofitMap[baseUrl] != null) { 33 | return retrofitMap[baseUrl]!! 34 | } 35 | 36 | if (provider == null) { 37 | provider = providerMap[baseUrl] 38 | if (provider == null) { 39 | provider = commonProvider 40 | } 41 | } 42 | checkProvider(provider) 43 | 44 | val gson = GsonBuilder() 45 | .setDateFormat("yyyy-MM-dd HH:mm:ss") 46 | .create() 47 | 48 | val builder = Retrofit.Builder() 49 | .baseUrl(baseUrl) 50 | .client(getClient(baseUrl, provider!!)) 51 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 52 | .addConverterFactory(GsonConverterFactory.create(gson)) 53 | 54 | val retrofit = builder.build() 55 | retrofitMap.put(baseUrl, retrofit) 56 | providerMap.put(baseUrl, provider) 57 | 58 | return retrofit 59 | } 60 | 61 | private fun empty(baseUrl: String?): Boolean { 62 | return baseUrl == null || baseUrl.isEmpty() 63 | } 64 | 65 | private fun getClient(baseUrl: String, provider: NetProvider): OkHttpClient { 66 | if (empty(baseUrl)) { 67 | throw IllegalStateException("baseUrl can not be null") 68 | } 69 | if (clientMap[baseUrl] != null) { 70 | return clientMap[baseUrl]!! 71 | } 72 | 73 | checkProvider(provider) 74 | 75 | val builder = OkHttpClient.Builder() 76 | 77 | builder.connectTimeout(if (provider.configConnectTimeoutSecs() != 0L) 78 | provider.configConnectTimeoutSecs() 79 | else 80 | connectTimeoutMills, TimeUnit.SECONDS) 81 | builder.readTimeout(if (provider.configReadTimeoutSecs() != 0L) 82 | provider.configReadTimeoutSecs() 83 | else 84 | readTimeoutMills, TimeUnit.SECONDS) 85 | 86 | builder.writeTimeout(if (provider.configWriteTimeoutSecs() != 0L) 87 | provider.configReadTimeoutSecs() 88 | else 89 | readTimeoutMills, TimeUnit.SECONDS) 90 | val cookieJar = provider.configCookie() 91 | if (cookieJar != null) { 92 | builder.cookieJar(cookieJar) 93 | } 94 | provider.configHttps(builder) 95 | 96 | val handler = provider.configHandler() 97 | if (handler != null) { 98 | builder.addInterceptor(NetInterceptor(handler)) 99 | } 100 | 101 | val interceptors = provider.configInterceptors() 102 | if (!empty(interceptors)) { 103 | for (interceptor in interceptors!!) { 104 | builder.addInterceptor(interceptor) 105 | } 106 | } 107 | 108 | if (provider.configLogEnable()) { 109 | val loggingInterceptor = HttpLoggingInterceptor() 110 | loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY 111 | builder.addInterceptor(loggingInterceptor) 112 | } 113 | 114 | val client = builder.build() 115 | clientMap.put(baseUrl, client) 116 | providerMap.put(baseUrl, provider) 117 | 118 | return client 119 | } 120 | 121 | private fun empty(interceptors: Array?): Boolean { 122 | return interceptors == null || interceptors.size == 0 123 | } 124 | 125 | private fun checkProvider(provider: NetProvider?) { 126 | if (provider == null) { 127 | throw IllegalStateException("must register provider first") 128 | } 129 | } 130 | 131 | fun getRetrofitMap(): Map { 132 | return retrofitMap 133 | } 134 | 135 | fun getClientMap(): Map { 136 | return clientMap 137 | } 138 | 139 | val connectTimeoutMills = 10 * 1000L 140 | val readTimeoutMills = 10 * 1000L 141 | var commonProvider: NetProvider? = null 142 | private set 143 | 144 | 145 | operator fun get(baseUrl: String, service: Class): S { 146 | return getRetrofit(baseUrl).create(service) 147 | } 148 | 149 | fun registerProvider(provider: NetProvider) { 150 | NetMgr.commonProvider = provider 151 | } 152 | 153 | fun registerProvider(baseUrl: String, provider: NetProvider) { 154 | providerMap.put(baseUrl, provider) 155 | } 156 | 157 | fun clearCache() { 158 | retrofitMap.clear() 159 | clientMap.clear() 160 | } 161 | 162 | 163 | } 164 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/network/NetProvider.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.network 2 | 3 | import okhttp3.CookieJar 4 | import okhttp3.Interceptor 5 | import okhttp3.OkHttpClient 6 | 7 | /** 8 | * 页面描述:网络配置 9 | * 10 | * 11 | * Created by ditclear on 2017/7/28. 12 | */ 13 | 14 | interface NetProvider { 15 | 16 | fun configInterceptors(): Array? 17 | 18 | fun configHttps(builder: OkHttpClient.Builder) 19 | 20 | fun configCookie(): CookieJar? 21 | 22 | fun configHandler(): RequestHandler 23 | 24 | fun configConnectTimeoutSecs(): Long 25 | 26 | fun configReadTimeoutSecs(): Long 27 | 28 | fun configWriteTimeoutSecs(): Long 29 | 30 | fun configLogEnable(): Boolean 31 | 32 | } 33 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/network/RequestHandler.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.network 2 | 3 | import okhttp3.Interceptor 4 | import okhttp3.Request 5 | import okhttp3.Response 6 | import java.io.IOException 7 | 8 | 9 | /** 10 | * 页面描述:网络拦截 11 | * 12 | * 13 | * Created by ditclear on 2017/7/28. 14 | */ 15 | 16 | interface RequestHandler { 17 | 18 | fun onBeforeRequest(request: Request, chain: Interceptor.Chain): Request 19 | 20 | @Throws(IOException::class) 21 | fun onAfterRequest(response: Response, chain: Interceptor.Chain): Response 22 | 23 | } 24 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/uitls/SystemBarHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 BiliBili Inc. 3 | */ 4 | 5 | package <%= appPackage %>.helper.uitls; 6 | 7 | import android.annotation.TargetApi; 8 | import android.app.Activity; 9 | import android.content.Context; 10 | import android.graphics.Color; 11 | import android.os.Build; 12 | import android.support.annotation.ColorInt; 13 | import android.support.annotation.FloatRange; 14 | import android.support.v4.view.ViewCompat; 15 | import android.support.v4.widget.DrawerLayout; 16 | import android.util.Log; 17 | import android.view.View; 18 | import android.view.ViewGroup; 19 | import android.view.Window; 20 | import android.view.WindowManager; 21 | import android.widget.FrameLayout; 22 | import <%= appPackage %>.R; 23 | import kotlin.jvm.JvmStatic; 24 | 25 | import java.lang.reflect.Field; 26 | import java.lang.reflect.Method; 27 | import java.util.regex.Pattern; 28 | /** 29 | * 状态栏工具类 状态栏两种模式(Android 4.4以上) 1.沉浸式全屏模式 2.状态栏着色模式 30 | */ 31 | public class SystemBarHelper { 32 | private static float DEFAULT_ALPHA = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 0.2f : 0.3f; 33 | 34 | /** 35 | * Android4.4以上的状态栏着色 36 | * 37 | * @param activity Activity对象 38 | * @param statusBarColor 状态栏颜色 39 | */ 40 | public static void tintStatusBar(Activity activity, @ColorInt int statusBarColor) { 41 | tintStatusBar(activity, statusBarColor, DEFAULT_ALPHA); 42 | } 43 | 44 | /** 45 | * Android4.4以上的状态栏着色 46 | * 47 | * @param activity Activity对象 48 | * @param statusBarColor 状态栏颜色 49 | * @param alpha 透明栏透明度[0.0-1.0] 50 | */ 51 | public static void tintStatusBar(Activity activity, @ColorInt int statusBarColor, @FloatRange(from = 0.0, to = 1.0) float alpha) { 52 | tintStatusBar(activity.getWindow(), statusBarColor, alpha); 53 | } 54 | 55 | /** 56 | * Android4.4以上的状态栏着色 57 | * 58 | * @param window 一般都是用于Activity的window,也可以是其他的例如Dialog,DialogFragment 59 | * @param statusBarColor 状态栏颜色 60 | */ 61 | public static void tintStatusBar(Window window, @ColorInt int statusBarColor) { 62 | tintStatusBar(window, statusBarColor, DEFAULT_ALPHA); 63 | } 64 | 65 | /** 66 | * Android4.4以上的状态栏着色 67 | * 68 | * @param window 一般都是用于Activity的window,也可以是其他的例如Dialog,DialogFragment 69 | * @param statusBarColor 状态栏颜色 70 | * @param alpha 透明栏透明度[0.0-1.0] 71 | */ 72 | public static void tintStatusBar(Window window, @ColorInt int statusBarColor, @FloatRange(from = 0.0, to = 1.0) float alpha) { 73 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 74 | return; 75 | } 76 | 77 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 78 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 79 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 80 | window.setStatusBarColor(Color.TRANSPARENT); 81 | } else { 82 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 83 | } 84 | 85 | ViewGroup decorView = (ViewGroup) window.getDecorView(); 86 | ViewGroup contentView = (ViewGroup) window.getDecorView().findViewById(Window.ID_ANDROID_CONTENT); 87 | View rootView = contentView.getChildAt(0); 88 | if (rootView != null) { 89 | ViewCompat.setFitsSystemWindows(rootView, true); 90 | } 91 | 92 | setStatusBar(decorView, statusBarColor, true); 93 | setTranslucentView(decorView, alpha); 94 | } 95 | 96 | /** 97 | * Android4.4以上的状态栏着色(针对于DrawerLayout) 注: 1.如果出现界面展示不正确,删除布局中所有fitsSystemWindows属性,尤其是DrawerLayout的fitsSystemWindows属性 98 | * 2.可以版本判断在5.0以上不调用该方法,使用系统自带 99 | * 100 | * @param activity Activity对象 101 | * @param drawerLayout DrawerLayout对象 102 | * @param statusBarColor 状态栏颜色 103 | */ 104 | public static void tintStatusBarForDrawer(Activity activity, DrawerLayout drawerLayout, @ColorInt int statusBarColor) { 105 | tintStatusBarForDrawer(activity, drawerLayout, statusBarColor, DEFAULT_ALPHA); 106 | } 107 | 108 | /** 109 | * Android4.4以上的状态栏着色(针对于DrawerLayout) 注: 1.如果出现界面展示不正确,删除布局中所有fitsSystemWindows属性,尤其是DrawerLayout的fitsSystemWindows属性 110 | * 2.可以版本判断在5.0以上不调用该方法,使用系统自带 111 | * 112 | * @param activity Activity对象 113 | * @param drawerLayout DrawerLayout对象 114 | * @param statusBarColor 状态栏颜色 115 | * @param alpha 透明栏透明度[0.0-1.0] 116 | */ 117 | public static void tintStatusBarForDrawer(Activity activity, DrawerLayout drawerLayout, @ColorInt int statusBarColor, 118 | @FloatRange(from = 0.0, to = 1.0) float alpha) { 119 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 120 | return; 121 | } 122 | 123 | Window window = activity.getWindow(); 124 | ViewGroup decorView = (ViewGroup) window.getDecorView(); 125 | ViewGroup drawContent = (ViewGroup) drawerLayout.getChildAt(0); 126 | 127 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 128 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 129 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 130 | window.setStatusBarColor(Color.TRANSPARENT); 131 | drawerLayout.setStatusBarBackgroundColor(statusBarColor); 132 | 133 | int systemUiVisibility = window.getDecorView().getSystemUiVisibility(); 134 | systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 135 | systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 136 | window.getDecorView().setSystemUiVisibility(systemUiVisibility); 137 | } else { 138 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 139 | } 140 | 141 | setStatusBar(decorView, statusBarColor, true, true); 142 | setTranslucentView(decorView, alpha); 143 | 144 | drawerLayout.setFitsSystemWindows(false); 145 | drawContent.setFitsSystemWindows(true); 146 | ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1); 147 | if (drawer != null) 148 | drawer.setFitsSystemWindows(false); 149 | } 150 | 151 | /** 152 | * Android4.4以上的沉浸式全屏模式 注: 1.删除fitsSystemWindows属性:Android5.0以上使用该方法如果出现界面展示不正确,删除布局中所有fitsSystemWindows属性 153 | * 或者调用forceFitsSystemWindows方法 2.不删除fitsSystemWindows属性:也可以区别处理,Android5.0以上使用自己的方式实现,不调用该方法 154 | * 155 | * @param activity Activity对象 156 | */ 157 | public static void immersiveStatusBar(Activity activity) { 158 | immersiveStatusBar(activity, DEFAULT_ALPHA); 159 | } 160 | 161 | /** 162 | * Android4.4以上的沉浸式全屏模式 注: 1.删除fitsSystemWindows属性:Android5.0以上使用该方法如果出现界面展示不正确,删除布局中所有fitsSystemWindows属性 163 | * 或者调用forceFitsSystemWindows方法 2.不删除fitsSystemWindows属性:也可以区别处理,Android5.0以上使用自己的方式实现,不调用该方法 164 | * 165 | * @param activity Activity对象 166 | * @param alpha 透明栏透明度[0.0-1.0] 167 | */ 168 | public static void immersiveStatusBar(Activity activity, @FloatRange(from = 0.0, to = 1.0) float alpha) { 169 | immersiveStatusBar(activity.getWindow(), alpha); 170 | } 171 | 172 | /** 173 | * Android4.4以上的沉浸式全屏模式 注: 1.删除fitsSystemWindows属性:Android5.0以上使用该方法如果出现界面展示不正确,删除布局中所有fitsSystemWindows属性 174 | * 或者调用forceFitsSystemWindows方法 2.不删除fitsSystemWindows属性:也可以区别处理,Android5.0以上使用自己的方式实现,不调用该方法 175 | * 176 | * @param window 一般都是用于Activity的window,也可以是其他的例如Dialog,DialogFragment 177 | */ 178 | public static void immersiveStatusBar(Window window) { 179 | immersiveStatusBar(window, DEFAULT_ALPHA); 180 | } 181 | 182 | /** 183 | * Android4.4以上的沉浸式全屏模式 注: 1.删除fitsSystemWindows属性:Android5.0以上使用该方法如果出现界面展示不正确,删除布局中所有fitsSystemWindows属性 184 | * 或者调用forceFitsSystemWindows方法 2.不删除fitsSystemWindows属性:也可以区别处理,Android5.0以上使用自己的方式实现,不调用该方法 185 | * 186 | * @param window 一般都是用于Activity的window,也可以是其他的例如Dialog,DialogFragment 187 | * @param alpha 透明栏透明度[0.0-1.0] 188 | */ 189 | public static void immersiveStatusBar(Window window, @FloatRange(from = 0.0, to = 1.0) float alpha) { 190 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 191 | return; 192 | } 193 | 194 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 195 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 196 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 197 | window.setStatusBarColor(Color.TRANSPARENT); 198 | 199 | int systemUiVisibility = window.getDecorView().getSystemUiVisibility(); 200 | systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 201 | systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 202 | window.getDecorView().setSystemUiVisibility(systemUiVisibility); 203 | } else { 204 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 205 | } 206 | 207 | ViewGroup decorView = (ViewGroup) window.getDecorView(); 208 | ViewGroup contentView = (ViewGroup) window.getDecorView().findViewById(Window.ID_ANDROID_CONTENT); 209 | View rootView = contentView.getChildAt(0); 210 | int statusBarHeight = getStatusBarHeight(window.getContext()); 211 | if (rootView != null) { 212 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) rootView.getLayoutParams(); 213 | ViewCompat.setFitsSystemWindows(rootView, true); 214 | lp.topMargin = -statusBarHeight; 215 | rootView.setLayoutParams(lp); 216 | } 217 | 218 | setTranslucentView(decorView, alpha); 219 | } 220 | 221 | /** 222 | * 设置状态栏darkMode,字体颜色及icon变黑(目前支持MIUI6以上,Flyme4以上,Android M以上) 223 | */ 224 | @JvmStatic 225 | public static void setStatusBarDarkMode(Activity activity) { 226 | setStatusBarDarkMode(activity.getWindow()); 227 | } 228 | 229 | /** 230 | * 设置状态栏darkMode,字体颜色及icon变黑(目前支持MIUI6以上,Flyme4以上,Android M以上) 231 | */ 232 | @JvmStatic 233 | public static void setStatusBarLightMode(Activity activity) { 234 | setStatusBarLightMode(activity.getWindow()); 235 | } 236 | 237 | /** 238 | * 设置状态栏darkMode,字体颜色及icon变白(目前支持MIUI6以上,Flyme4以上,Android M以上) 239 | */ 240 | public static void setStatusBarLightMode(Window window) { 241 | if (isFlyme4Later()) { 242 | setStatusBarDarkModeForFlyme4(window, false); 243 | } else if (isMIUI6LaterAnd9Before()) { 244 | setStatusBarDarkModeForMIUI6(window, false); 245 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 246 | setStatusBarDarkModeForM(window,false); 247 | } 248 | } 249 | /** 250 | * 设置状态栏darkMode,字体颜色及icon变黑(目前支持MIUI6以上,Flyme4以上,Android M以上) 251 | */ 252 | public static void setStatusBarDarkMode(Window window) { 253 | if (isFlyme4Later()) { 254 | setStatusBarDarkModeForFlyme4(window, true); 255 | } else if (isMIUI6LaterAnd9Before()) { 256 | setStatusBarDarkModeForMIUI6(window, true); 257 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 258 | setStatusBarDarkModeForM(window,true); 259 | } 260 | } 261 | 262 | 263 | /** 264 | * android 6.0设置字体颜色 265 | */ 266 | @TargetApi(Build.VERSION_CODES.M) 267 | public static void setStatusBarDarkModeForM(Window window,boolean darkMode) { 268 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 269 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 270 | window.setStatusBarColor(Color.TRANSPARENT); 271 | int systemUiVisibility = window.getDecorView().getSystemUiVisibility(); 272 | if (darkMode) { 273 | systemUiVisibility |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 274 | } else { 275 | systemUiVisibility &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 276 | } 277 | window.getDecorView().setSystemUiVisibility(systemUiVisibility); 278 | } 279 | 280 | 281 | /** 282 | * 设置Flyme4+的darkMode,darkMode时候字体颜色及icon变黑 http://open-wiki.flyme.cn/index.php?title=Flyme%E7%B3%BB%E7%BB%9FAPI 283 | */ 284 | public static boolean setStatusBarDarkModeForFlyme4(Window window, boolean dark) { 285 | boolean result = false; 286 | if (window != null) { 287 | try { 288 | WindowManager.LayoutParams e = window.getAttributes(); 289 | Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON"); 290 | Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags"); 291 | darkFlag.setAccessible(true); 292 | meizuFlags.setAccessible(true); 293 | int bit = darkFlag.getInt(null); 294 | int value = meizuFlags.getInt(e); 295 | if (dark) { 296 | value |= bit; 297 | } else { 298 | value &= ~bit; 299 | } 300 | 301 | meizuFlags.setInt(e, value); 302 | window.setAttributes(e); 303 | result = true; 304 | } catch (Exception var8) { 305 | Log.e("StatusBar", "setStatusBarDarkIcon: failed"); 306 | } 307 | } 308 | 309 | return result; 310 | } 311 | 312 | /** 313 | * 设置MIUI6+的状态栏是否为darkMode,darkMode时候字体颜色及icon变黑 http://dev.xiaomi.com/doc/p=4769/ 314 | */ 315 | public static void setStatusBarDarkModeForMIUI6(Window window, boolean darkmode) { 316 | Class clazz = window.getClass(); 317 | try { 318 | int darkModeFlag = 0; 319 | Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams"); 320 | Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE"); 321 | darkModeFlag = field.getInt(layoutParams); 322 | Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class); 323 | extraFlagField.invoke(window, darkmode ? darkModeFlag : 0, darkModeFlag); 324 | } catch (Exception e) { 325 | e.printStackTrace(); 326 | } 327 | } 328 | 329 | /** 330 | * 创建假的状态栏View 331 | */ 332 | private static void setStatusBar(ViewGroup container, @ColorInt int statusBarColor, boolean visible, boolean addToFirst) { 333 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 334 | View statusBarView = container.findViewById(R.id.statusbar_view); 335 | if (statusBarView == null) { 336 | statusBarView = new View(container.getContext()); 337 | statusBarView.setId(R.id.statusbar_view); 338 | ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( 339 | ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(container.getContext())); 340 | if (addToFirst) { 341 | container.addView(statusBarView, 0, lp); 342 | } else { 343 | container.addView(statusBarView, lp); 344 | } 345 | } 346 | 347 | statusBarView.setBackgroundColor(statusBarColor); 348 | statusBarView.setVisibility(visible ? View.VISIBLE : View.GONE); 349 | } 350 | } 351 | 352 | /** 353 | * 创建假的状态栏View 354 | */ 355 | private static void setStatusBar(ViewGroup container, @ColorInt int statusBarColor, boolean visible) { 356 | setStatusBar(container, statusBarColor, visible, false); 357 | } 358 | 359 | /** 360 | * 创建假的透明栏 361 | */ 362 | private static void setTranslucentView(ViewGroup container, 363 | @FloatRange(from = 0.0, to = 1.0) float alpha) { 364 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 365 | View translucentView = container.findViewById(R.id.translucent_view); 366 | if (translucentView == null) { 367 | translucentView = new View(container.getContext()); 368 | translucentView.setId(R.id.translucent_view); 369 | ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( 370 | ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(container.getContext())); 371 | container.addView(translucentView, lp); 372 | } 373 | 374 | translucentView.setBackgroundColor(Color.argb((int) (alpha * 255), 0, 0, 0)); 375 | } 376 | } 377 | 378 | 379 | /** 380 | * 获取状态栏高度 381 | */ 382 | public static int getStatusBarHeight(Context context) { 383 | int result = 0; 384 | int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); 385 | if (resId > 0) { 386 | result = context.getResources().getDimensionPixelSize(resId); 387 | } 388 | return result; 389 | } 390 | 391 | /** 392 | * 判断是否Flyme4以上 393 | */ 394 | public static boolean isFlyme4Later() { 395 | return Build.FINGERPRINT.contains("Flyme_OS_4") 396 | || Build.VERSION.INCREMENTAL.contains("Flyme_OS_4") 397 | || Pattern.compile("Flyme OS [4|5]", Pattern.CASE_INSENSITIVE).matcher(Build.DISPLAY).find() 398 | || Pattern.compile("Flyme [4|5|6]", Pattern.CASE_INSENSITIVE).matcher(Build.DISPLAY).find(); 399 | } 400 | 401 | /** 402 | * 判断是否为MIUI6以上9以下 403 | */ 404 | public static boolean isMIUI6LaterAnd9Before() { 405 | try { 406 | Class clz = Class.forName("android.os.SystemProperties"); 407 | Method mtd = clz.getMethod("get", String.class); 408 | String val = (String) mtd.invoke(null, "ro.miui.ui.version.name"); 409 | val = val.replaceAll("[vV]", ""); 410 | int version = Integer.parseInt(val); 411 | return version >= 6 && version <9; 412 | } catch (Exception e) { 413 | return false; 414 | } 415 | } 416 | 417 | /** 418 | * 增加View的高度以及paddingTop,增加的值为状态栏高度.一般是在沉浸式全屏给ToolBar用的 419 | */ 420 | public static void setHeightAndPadding(Context context, View view) { 421 | if (view == null) { 422 | return; 423 | } 424 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 425 | ViewGroup.LayoutParams lp = view.getLayoutParams(); 426 | lp.height += getStatusBarHeight(context);//增高 427 | view.setPadding(view.getPaddingLeft(), view.getPaddingTop() + getStatusBarHeight(context), 428 | view.getPaddingRight(), view.getPaddingBottom()); 429 | } 430 | } 431 | 432 | /** 433 | * 增加View的paddingTop,增加的值为状态栏高度 434 | */ 435 | public static void setPadding(Context context, View view) { 436 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 437 | view.setPadding(view.getPaddingLeft(), view.getPaddingTop() + getStatusBarHeight(context), 438 | view.getPaddingRight(), view.getPaddingBottom()); 439 | } 440 | } 441 | 442 | /** 443 | * 强制rootView下面的子View的FitsSystemWindows为false 444 | */ 445 | public static void forceFitsSystemWindows(Activity activity) { 446 | forceFitsSystemWindows(activity.getWindow()); 447 | } 448 | 449 | /** 450 | * 强制rootView下面的子View的FitsSystemWindows为false 451 | */ 452 | public static void forceFitsSystemWindows(Window window) { 453 | forceFitsSystemWindows((ViewGroup) window.getDecorView().findViewById(Window.ID_ANDROID_CONTENT)); 454 | } 455 | 456 | /** 457 | * 强制rootView下面的子View的FitsSystemWindows为false 458 | */ 459 | public static void forceFitsSystemWindows(ViewGroup viewGroup) { 460 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 461 | int count = viewGroup.getChildCount(); 462 | for (int i = 0; i < count; i++) { 463 | View view = viewGroup.getChildAt(i); 464 | if (view instanceof ViewGroup) { 465 | forceFitsSystemWindows((ViewGroup) view); 466 | } else { 467 | if (ViewCompat.getFitsSystemWindows(view)) { 468 | ViewCompat.setFitsSystemWindows(view, false); 469 | } 470 | } 471 | } 472 | } 473 | } 474 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/helper/uitls/ToastUtil.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.helper.uitls 2 | 3 | import android.app.Activity 4 | import android.widget.Toast 5 | 6 | /** 7 | * 页面描述:ToastUtil 8 | * 9 | * Created by ditclear on 2018/12/11. 10 | */ 11 | object ToastUtil { 12 | fun warning(activity: Activity, msg: CharSequence, duration: Int) { 13 | Toast.makeText(activity, msg, duration).show() 14 | } 15 | 16 | fun error(activity: Activity, msg: CharSequence, duration: Int) { 17 | Toast.makeText(activity, msg, duration).show() 18 | } 19 | 20 | fun info(activity: Activity, msg: CharSequence, duration: Int) { 21 | Toast.makeText(activity, msg, duration).show() 22 | } 23 | 24 | fun success(activity: Activity, msg: CharSequence, duration: Int) { 25 | Toast.makeText(activity, msg, duration).show() 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/view/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.view.base 2 | 3 | import android.content.Context 4 | import android.databinding.DataBindingUtil 5 | import android.databinding.ViewDataBinding 6 | import android.os.Bundle 7 | import android.support.v7.app.AppCompatActivity 8 | import android.view.MenuItem 9 | import android.view.View 10 | import <%= appPackage %>.BR 11 | 12 | 13 | /** 14 | * 页面描述:BaseActivity 15 | * 16 | * Created by ditclear on 2017/9/27. 17 | */ 18 | abstract class BaseActivity : AppCompatActivity(), Presenter { 19 | 20 | protected lateinit var mBinding: VB 21 | 22 | protected lateinit var mContext: Context 23 | 24 | protected var autoRefresh = true 25 | 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | mBinding = DataBindingUtil.setContentView(this, getLayoutId()) 29 | mBinding.setVariable(BR.presenter, this) 30 | mBinding.executePendingBindings() 31 | mBinding.setLifecycleOwner(this) 32 | mContext = this 33 | initView() 34 | if (autoRefresh) { 35 | loadData(true) 36 | } 37 | } 38 | 39 | 40 | abstract fun loadData(isRefresh: Boolean) 41 | 42 | abstract fun initView() 43 | 44 | abstract fun getLayoutId(): Int 45 | 46 | 47 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 48 | when (item.itemId) { 49 | android.R.id.home -> onBackPressed() 50 | } 51 | return super.onOptionsItemSelected(item) 52 | } 53 | 54 | override fun onClick(v: View?) { 55 | 56 | } 57 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/view/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.view.base 2 | 3 | import android.content.Context 4 | import android.databinding.DataBindingUtil 5 | import android.databinding.ViewDataBinding 6 | import android.os.Bundle 7 | import android.support.v4.app.Fragment 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import <%= appPackage %>.BR 12 | 13 | 14 | /** 15 | * 页面描述:fragment 基类 16 | * 17 | * Created by ditclear on 2017/9/27. 18 | */ 19 | 20 | abstract class BaseFragment : Fragment(), Presenter { 21 | 22 | protected lateinit var mBinding: VB 23 | 24 | protected lateinit var mContext: Context 25 | 26 | protected var lazyLoad = false 27 | 28 | protected var visible = false 29 | 30 | /** 31 | * 标志位,标志已经初始化完成 32 | */ 33 | protected var isPrepared: Boolean = false 34 | /** 35 | * 是否已被加载过一次,第二次就不再去请求数据了 36 | */ 37 | protected var hasLoadOnce: Boolean = false 38 | 39 | override fun onCreate(savedInstanceState: Bundle?) { 40 | super.onCreate(savedInstanceState) 41 | initArgs(savedInstanceState) 42 | } 43 | 44 | override fun onActivityCreated(savedInstanceState: Bundle?) { 45 | super.onActivityCreated(savedInstanceState) 46 | mContext = checkNotNull(activity) 47 | initView() 48 | if (lazyLoad) { 49 | //延迟加载,需重写lazyLoad方法 50 | lazyLoad() 51 | } else { 52 | // 加载数据 53 | loadData(true); 54 | } 55 | } 56 | 57 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 58 | mBinding = DataBindingUtil.inflate(inflater, getLayoutId(), null, false) 59 | mBinding.setVariable(BR.presenter, this) 60 | mBinding.executePendingBindings() 61 | mBinding.setLifecycleOwner(this) 62 | return mBinding.root 63 | } 64 | 65 | /** 66 | * 是否可见,延迟加载 67 | */ 68 | override fun setUserVisibleHint(isVisibleToUser: Boolean) { 69 | super.setUserVisibleHint(isVisibleToUser) 70 | if (userVisibleHint) { 71 | visible = true 72 | onVisible() 73 | } else { 74 | visible = false 75 | onInvisible() 76 | } 77 | } 78 | 79 | protected fun onInvisible() { 80 | 81 | } 82 | 83 | protected open fun onVisible() { 84 | lazyLoad() 85 | } 86 | 87 | 88 | open fun lazyLoad() {} 89 | 90 | open fun initArgs(savedInstanceState: Bundle?) { 91 | 92 | } 93 | 94 | abstract fun initView() 95 | abstract fun loadData(isRefresh: Boolean) 96 | 97 | abstract fun getLayoutId(): Int 98 | 99 | override fun onClick(v: View?) { 100 | 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/view/base/Presenter.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.view.base 2 | 3 | import android.view.View 4 | 5 | /** 6 | * 页面描述:Presenter 7 | * 8 | * Created by ditclear on 2017/11/2. 9 | */ 10 | interface Presenter:View.OnClickListener{ 11 | 12 | override fun onClick(v: View?) 13 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/kotlin/io/ditclear/app/viewmodel/BaseViewModel.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.viewmodel 2 | 3 | import android.arch.lifecycle.ViewModel 4 | 5 | /** 6 | * 页面描述:viewModel 基类 7 | * 8 | * Created by ditclear on 2017/9/28. 9 | */ 10 | 11 | open class BaseViewModel() : ViewModel(){ 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/res/layout/core_layout_holder.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/core/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/java/io/ditclear/app/App.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %> 2 | 3 | import android.app.Application 4 | import <%= appPackage %>.di.appModule 5 | import org.koin.android.ext.android.startKoin 6 | import org.koin.android.logger.AndroidLogger 7 | 8 | /** 9 | * 页面描述:App 10 | * 11 | * Created by ditclear on 2018/12/11. 12 | */ 13 | class App : Application() { 14 | 15 | override fun onCreate() { 16 | super.onCreate() 17 | startKoin(this, appModule, logger = AndroidLogger(showDebug = BuildConfig.DEBUG)) 18 | } 19 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/java/io/ditclear/app/di/app_module.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.di 2 | import org.koin.dsl.module.module 3 | import <%= appPackage %>.view.main.viewmodel.MainViewModel 4 | import org.koin.android.viewmodel.ext.koin.viewModel 5 | 6 | val viewModelModule = module { 7 | 8 | viewModel { MainViewModel() } 9 | 10 | } 11 | 12 | val appModule = listOf(viewModelModule) -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/java/io/ditclear/app/view/main/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.view.main 2 | 3 | import android.view.View 4 | import <%= appPackage %>.R 5 | import <%= appPackage %>.aop.annotation.SingleClick 6 | import <%= appPackage %>.databinding.MainActivityBinding 7 | import <%= appPackage %>.view.base.BaseActivity 8 | import <%= appPackage %>.view.main.viewmodel.MainViewModel 9 | import org.koin.android.viewmodel.ext.android.viewModel 10 | 11 | class MainActivity : BaseActivity() { 12 | 13 | 14 | private val mViewModel by viewModel() 15 | 16 | override fun loadData(isRefresh: Boolean) { 17 | 18 | } 19 | override fun initView() { 20 | mBinding.vm = mViewModel 21 | } 22 | 23 | override fun getLayoutId(): Int = R.layout.main_activity 24 | 25 | 26 | @SingleClick 27 | override fun onClick(v: View?) { 28 | when (v?.id) { 29 | R.id.test_tv -> testView() 30 | } 31 | } 32 | 33 | private fun testView() { 34 | mViewModel.testView() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/java/io/ditclear/app/view/main/viewmodel/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package <%= appPackage %>.view.main.viewmodel 2 | 3 | import android.arch.lifecycle.MutableLiveData 4 | import <%= appPackage %>.helper.extens.get 5 | import <%= appPackage %>.helper.extens.init 6 | import <%= appPackage %>.helper.extens.set 7 | import <%= appPackage %>.helper.extens.toFlowable 8 | import <%= appPackage %>.viewmodel.BaseViewModel 9 | 10 | /** 11 | * 页面描述:MainViewModel 12 | * 13 | * Created by ditclear on 2018/12/11. 14 | */ 15 | class MainViewModel constructor():BaseViewModel(){ 16 | 17 | val text = MutableLiveData().init("click me ") 18 | val doubleBindText = MutableLiveData().apply { 19 | set("") 20 | } 21 | 22 | init { 23 | doubleBindText.toFlowable() 24 | .doOnNext { 25 | println("MainViewModel------》$it") 26 | }.subscribe() 27 | } 28 | 29 | 30 | val loading = MutableLiveData().apply { set(false) } 31 | 32 | fun testView() { 33 | text.set("${text.get() ?: ""}111") 34 | } 35 | } -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | 21 | 22 | 23 | 29 | 30 | 37 | 38 | 39 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #262626 4 | #262626 5 | #F5F5F5 6 | 7 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | <%= appName %> 3 | 4 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/app/src/test/java/io/ditclear/app/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package < 2 | 3 | import org.junit.Test 4 | 5 | %= appPackage %> 6 | 7 | import org.junit.Test 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Example local unit test, which will execute on the development machine (host). 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | class ExampleUnitTest { 17 | @Test 18 | fun addition_isCorrect() { 19 | assertEquals(4, 2 + 2) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.10' 5 | ext.koin_version = '1.0.2' 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.2.1' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | //aspectj 14 | classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4' 15 | // NOTE: Do not place your application dependencies here; they belong 16 | // in the individual module build.gradle files 17 | } 18 | } 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | maven { url "https://jitpack.io" } 24 | jcenter() 25 | } 26 | } 27 | 28 | ext { 29 | complieSdkVersion = 28 30 | buildToolsVersion = "28.0.3" 31 | supportLibVersion = "28.0.0" 32 | archLifecycleVersion = "1.1.1" 33 | archRoomVersion = "1.1.0" 34 | retrofitVersion = "2.3.0" 35 | } 36 | 37 | task clean(type: Delete) { 38 | delete rootProject.buildDir 39 | } 40 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/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.daemon=true 10 | org.gradle.jvmargs=-Xmx14312M -XX:MaxPermSize=3072m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 11 | org.gradle.parallel=true 12 | org.gradle.configureondemand=true 13 | # Set to true or false to enable or disable the build cache. 14 | #If this parameter is not set, the build cache is disabled by default. 15 | android.enableBuildCache=true 16 | # When configured, Gradle will run in incubating parallel mode. 17 | # This option should only be used with decoupled projects. More details, visit 18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 19 | # org.gradle.parallel=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ditclear/generator-mvvm-kotlin/ba3e490e553a143b4bf72d04db7d4acc96f93430/generators/app/templates/template-mvvm-kotlin/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /generators/app/templates/template-mvvm-kotlin/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var gulp = require('gulp'); 4 | var eslint = require('gulp-eslint'); 5 | var excludeGitignore = require('gulp-exclude-gitignore'); 6 | var mocha = require('gulp-mocha'); 7 | var istanbul = require('gulp-istanbul'); 8 | var nsp = require('gulp-nsp'); 9 | var plumber = require('gulp-plumber'); 10 | var coveralls = require('gulp-coveralls'); 11 | 12 | gulp.task('static', function () { 13 | return gulp.src('**/*.js') 14 | .pipe(excludeGitignore()) 15 | .pipe(eslint()) 16 | .pipe(eslint.format()) 17 | .pipe(eslint.failAfterError()); 18 | }); 19 | 20 | gulp.task('nsp', function (cb) { 21 | nsp({package: path.resolve('package.json')}, cb); 22 | }); 23 | 24 | gulp.task('pre-test', function () { 25 | return gulp.src('generators/**/index.js') 26 | .pipe(excludeGitignore()) 27 | .pipe(istanbul({ 28 | includeUntested: true 29 | })) 30 | .pipe(istanbul.hookRequire()); 31 | }); 32 | 33 | gulp.task('test', ['pre-test'], function (cb) { 34 | var mochaErr; 35 | 36 | gulp.src('test/**/*.js') 37 | .pipe(plumber()) 38 | .pipe(mocha({reporter: 'spec'})) 39 | .on('error', function (err) { 40 | mochaErr = err; 41 | }) 42 | .pipe(istanbul.writeReports()) 43 | .on('end', function () { 44 | cb(mochaErr); 45 | }); 46 | }); 47 | 48 | gulp.task('watch', function () { 49 | gulp.watch(['generators/**/*.js', 'test/**'], ['test']); 50 | }); 51 | 52 | gulp.task('coveralls', ['test'], function () { 53 | if (!process.env.CI) { 54 | return; 55 | } 56 | 57 | return gulp.src(path.join(__dirname, 'coverage/lcov.info')) 58 | .pipe(coveralls()); 59 | }); 60 | 61 | gulp.task('prepublish', ['nsp']); 62 | gulp.task('default', ['static', 'test', 'coveralls']); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-mvvm-kotlin", 3 | "version": "1.3.2", 4 | "description": "An Kotlin MVVM Boilerplate For Android to save me having to create the same project over from scratch every time! :)", 5 | "homepage": "https://github.com/ditclear/paonet", 6 | "author": { 7 | "name": "ditclear", 8 | "email": "ditclear@qq.com", 9 | "url": "https://github.com/ditclear" 10 | }, 11 | "files": [ 12 | "generators" 13 | ], 14 | "main": "generators/index.js", 15 | "keywords": [ 16 | "Android", 17 | "Starter", 18 | "MVVM", 19 | "Kotlin", 20 | "yeoman-generator" 21 | ], 22 | "dependencies": { 23 | "chalk": "^1.0.0", 24 | "generator-git-init": "^1.1.3", 25 | "glob": "^7.0.5", 26 | "mkdirp": "^0.5.1", 27 | "yeoman-generator": "^1.1.1", 28 | "yosay": "^2.0.0" 29 | }, 30 | "devDependencies": { 31 | "async": "^2.0.1", 32 | "eslint": "^4.0.0", 33 | "eslint-config-xo-space": "^0.16.0", 34 | "filter-files": "^0.4.0", 35 | "find-in-files": "^0.4.0", 36 | "fs-finder": "^1.8.1", 37 | "gulp": "^3.9.0", 38 | "gulp-coveralls": "^0.1.0", 39 | "gulp-eslint": "^4.0.0", 40 | "gulp-exclude-gitignore": "^1.0.0", 41 | "gulp-istanbul": "^1.1.2", 42 | "gulp-line-ending-corrector": "^1.0.1", 43 | "gulp-mocha": "^4.3.1", 44 | "gulp-nsp": "^2.1.0", 45 | "gulp-plumber": "^1.0.0", 46 | "mv": "^2.1.1", 47 | "ncp": "^2.0.0", 48 | "nodegit": "^0.19.0", 49 | "path": "^0.12.7", 50 | "renamer": "^0.6.1", 51 | "replace": "^0.3.0", 52 | "rimraf": "^2.5.4", 53 | "string-search": "^1.2.0", 54 | "yeoman-assert": "^3.0.0", 55 | "yeoman-test": "^1.0.0" 56 | }, 57 | "eslintConfig": { 58 | "extends": "xo-space", 59 | "env": { 60 | "mocha": true 61 | } 62 | }, 63 | "repository": "ditclear/generator-mvvm-kotlin", 64 | "scripts": { 65 | "test": "gulp" 66 | }, 67 | "license": "Apache-2.0" 68 | } 69 | -------------------------------------------------------------------------------- /test/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var assert = require('yeoman-assert'); 4 | var helpers = require('yeoman-test'); 5 | 6 | describe('generator-android-mvp-starter:app', function () { 7 | this.timeout(15000); 8 | 9 | before(function () { 10 | return helpers.run(path.join(__dirname, '../generators/app')) 11 | .withPrompts({ 12 | name: 'SampleApp', 13 | package: 'com.sample.mvp', 14 | targetSdk: '21', 15 | minSdk: '14', 16 | language: 'kotlin' 17 | }) 18 | .toPromise(); 19 | }); 20 | 21 | it('creates project files', function () { 22 | assert.file([ 23 | '.gitignore', 24 | 'build.gradle', 25 | 'gradle.properties', 26 | 'gradlew', 27 | 'gradlew.bat', 28 | 'settings.gradle' 29 | ]); 30 | }); 31 | 32 | it('creates core app files', function () { 33 | assert.file([ 34 | 'app/.gitignore', 35 | 'app/build.gradle', 36 | 'app/proguard-rules.pro' 37 | ]); 38 | }); 39 | 40 | it('copies gradle wrapper', function () { 41 | assert.file([ 42 | 'gradle/wrapper/gradle-wrapper.jar', 43 | 'gradle/wrapper/gradle-wrapper.properties' 44 | ]); 45 | }); 46 | }); 47 | --------------------------------------------------------------------------------