├── .github
└── workflows
│ └── android-master.yml
├── .gitignore
├── .idea
├── .gitignore
├── .name
├── compiler.xml
├── gradle.xml
├── jarRepositories.xml
└── misc.xml
├── README.md
├── app
├── .editorconfig
├── .gitignore
├── build.gradle
├── code-quality.gradle
├── detekt-rule.yml
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── dev
│ │ └── happysingh
│ │ └── template
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── dev
│ │ │ └── happysingh
│ │ │ └── template
│ │ │ ├── MainApplication.kt
│ │ │ └── ui
│ │ │ └── MainActivity.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.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-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── dev
│ └── happysingh
│ └── template
│ └── ExampleUnitTest.kt
├── build.gradle
├── buildSrc
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ ├── ConfigFields.kt
│ ├── Dependencies.kt
│ ├── MavenUrls.kt
│ └── Version.kt
├── core
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── dev
│ │ └── happysingh
│ │ └── core
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── dev
│ │ │ └── happysingh
│ │ │ └── core
│ │ │ ├── base
│ │ │ ├── BaseActivity.kt
│ │ │ └── BaseFragment.kt
│ │ │ └── ext
│ │ │ ├── ActivityExt.kt
│ │ │ ├── AndroidApiExt.kt
│ │ │ ├── BitmapExt.kt
│ │ │ ├── CommonViewExt.kt
│ │ │ ├── CoreExt.kt
│ │ │ ├── FileExt.kt
│ │ │ ├── FragmentExt.kt
│ │ │ ├── SpecificViewExt.kt
│ │ │ ├── StringExt.kt
│ │ │ └── WebViewExt.kt
│ └── res
│ │ └── values
│ │ ├── colors.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── dev
│ └── happysingh
│ └── core
│ └── ExampleUnitTest.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.github/workflows/android-master.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on: pull_request
4 |
5 | jobs:
6 | # Running linting using detekt,ktlint
7 | lint:
8 | name: Running lints
9 | runs-on: ubuntu-18.04
10 |
11 | steps:
12 | - uses: actions/checkout@v1
13 |
14 | - name: Set up JDK 1.8
15 | uses: actions/setup-java@v1
16 | with:
17 | java-version: 1.8
18 |
19 | - name: Running Ktlint
20 | run: bash ./gradlew ktlint --stacktrace
21 |
22 | - name: Running detekt
23 | run: bash ./gradlew detekt --stacktrace
24 |
25 | # Running Unit Test Cases
26 | unitTest:
27 | needs: lint
28 | name: Running Unit Tests
29 | runs-on: ubuntu-18.04
30 |
31 | steps:
32 | - uses: actions/checkout@v1
33 | - name: Set up JDK 1.8
34 | uses: actions/setup-java@v1
35 | with:
36 | java-version: 1.8
37 | - name: Run Unit tests
38 | run: bash ./gradlew test --stacktrace
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /local.properties
3 | /.idea/caches
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | /.idea/navEditor.xml
8 | /.idea/assetWizardSettings.xml
9 | .DS_Store
10 | /build
11 | /captures
12 | .externalNativeBuild
13 | .cxx
14 | local.properties
15 |
16 |
17 |
18 | # Created by https://www.toptal.com/developers/gitignore/api/androidstudio
19 | # Edit at https://www.toptal.com/developers/gitignore?templates=androidstudio
20 |
21 | ### AndroidStudio ###
22 | # Covers files to be ignored for android development using Android Studio.
23 |
24 | # Built application files
25 | *.apk
26 | *.ap_
27 | *.aab
28 |
29 | # Files for the ART/Dalvik VM
30 | *.dex
31 |
32 | # Java class files
33 | *.class
34 |
35 | # Generated files
36 | bin/
37 | gen/
38 | out/
39 |
40 | # Gradle files
41 | .gradle
42 | .gradle/
43 | build/
44 |
45 | # Signing files
46 | .signing/
47 |
48 | # Proguard folder generated by Eclipse
49 | proguard/
50 |
51 | # Log Files
52 | *.log
53 |
54 | # Android Studio
55 | /*/build/
56 | /*/local.properties
57 | /*/out
58 | /*/*/build
59 | /*/*/production
60 | captures/
61 | .navigation/
62 | *.ipr
63 | *~
64 | *.swp
65 |
66 | # Keystore files
67 | *.jks
68 | *.keystore
69 |
70 | # Google Services (e.g. APIs or Firebase)
71 | # google-services.json
72 |
73 | # Android Patch
74 | gen-external-apklibs
75 |
76 |
77 | # NDK
78 | obj/
79 |
80 | # IntelliJ IDEA
81 | *.iws
82 | /out/
83 |
84 | # User-specific configurations
85 | .idea/caches/
86 | .idea/libraries/
87 | .idea/shelf/
88 | .idea/workspace.xml
89 | .idea/tasks.xml
90 | .idea/.name
91 | .idea/compiler.xml
92 | .idea/copyright/profiles_settings.xml
93 | .idea/encodings.xml
94 | .idea/misc.xml
95 | .idea/modules.xml
96 | .idea/scopes/scope_settings.xml
97 | .idea/dictionaries
98 | .idea/vcs.xml
99 | .idea/jsLibraryMappings.xml
100 | .idea/datasources.xml
101 | .idea/dataSources.ids
102 | .idea/sqlDataSources.xml
103 | .idea/dynamic.xml
104 | .idea/uiDesigner.xml
105 | .idea/assetWizardSettings.xml
106 | .idea/gradle.xml
107 | .idea/jarRepositories.xml
108 | .idea/navEditor.xml
109 |
110 | # OS-specific files
111 | .DS_Store?
112 | ._*
113 | .Spotlight-V100
114 | .Trashes
115 | ehthumbs.db
116 | Thumbs.db
117 |
118 | # Legacy Eclipse project files
119 | .classpath
120 | .project
121 | .cproject
122 | .settings/
123 |
124 | # Mobile Tools for Java (J2ME)
125 | .mtj.tmp/
126 |
127 | # Package Files #
128 | *.war
129 | *.ear
130 |
131 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
132 | hs_err_pid*
133 |
134 | ## Plugin-specific files:
135 |
136 | # mpeltonen/sbt-idea plugin
137 | .idea_modules/
138 |
139 | # JIRA plugin
140 | atlassian-ide-plugin.xml
141 |
142 | # Mongo Explorer plugin
143 | .idea/mongoSettings.xml
144 |
145 | # Crashlytics plugin (for Android Studio and IntelliJ)
146 | com_crashlytics_export_strings.xml
147 | crashlytics.properties
148 | crashlytics-build.properties
149 | fabric.properties
150 |
151 | ### AndroidStudio Patch ###
152 |
153 | !/gradle/wrapper/gradle-wrapper.jar
154 |
155 | # End of https://www.toptal.com/developers/gitignore/api/androidstudio
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Android-Github-Repo-Template
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android Project Github Template
2 |
3 | [](https://www.android.com)
4 | [](LICENSE)
5 | 
6 | 
7 | 
8 | 
9 | 
10 |
11 | > A template for creating new repositories for the new Android Project.
12 |
13 | ## What is diffrent here from creating a new project from Android Studio?
14 |
15 | This repository is meant to serve as a general template for how to set up new repository for Android. In general, setting up a new repository takes 30-60 minutes; use this repository as a way of setting up in 5 minutes, and use the following checklist to ensure that you've set up the repository correctly.
16 | It has additional modules and files to save your time.
17 |
18 | ### Features
19 | - BuildSrc module (for handling dependecies at one place).
20 | - Core module (includes Kotlin Extensions, Base classess etc.).
21 | - Static tool analysis with Report generation (Ktlint, KtlintAutoFormat Detekt, Custom Detekt Lint Rules).
22 | - Android CI (using Github's Action workflow)
23 | - .gitignore for Android Studio Projects.
24 | - and many more to come....
25 |
26 | ## Checklist
27 | These instructions are basic; The important part is making sure that you follow the checklist for error free setup.
28 |
29 | ### Create Repository from Github
30 | - [ ] Click on **use this template** on this repository.
31 | - [ ] Enter your Github repo name.
32 | - [ ] Uncheck **include all branches** option.
33 | - [ ] Click on **create repo from template** button.
34 | now your repo has been created.
35 |
36 | ### Clone Repo in Android Studio and set up.
37 | - [ ] Clone your newly created github repo into Android Studio.
38 | - [ ] Go to **settings.gradle** and change **rootProject.name** as per your project name.
39 | - [ ] Go to App's **build.gradle** and change **applicationId** as per your project package.
40 | - [ ] Go to App's module **strings.xml** and change **app_name** to your app name.
41 | - [ ] Delete Readme.MD file.
42 | - [ ] [Optional] Go to **themes.xml** and refactor Base Application them's name **Theme.AndroidRepoGithubTemplate** as per your requirements.
43 | that's it.
44 |
45 | ### Additional Notes
46 | - CI is only triggred on pull request. If you need to change action go to [android-master.yml](https://github.com/happysingh23828/android-github-repo-template/blob/master/.github/workflows/android-master.yml)
47 | - You can edit rules for **Detekt** in this [detekt-rule.yml](https://github.com/happysingh23828/android-github-repo-template/blob/master/app/detekt-rule.yml).
48 |
49 | ## - Code Quality Checks
50 | This projects uses detekt and ktlint static code analyser in CI/CD pipeline to maintain code quality. they also genrated reports.
51 |
52 | #### Run detekt locally
53 | Use `./gradlew detekt`
54 |
55 | Reports location for each module-
56 | `-/app/build/reports/detekt/report.html`
57 | `-/core/build/reports/detekt/report.html`
58 |
59 | #### Run ktlint locally
60 | Use `./gradlew ktlint`
61 |
62 | Reports location for each module-
63 | `-/app/build/reports/ktlint/ktlint-checkstyle-report.xml`
64 | `-/core/build/reports/ktlint/ktlint-checkstyle-report.xml`
65 |
66 | #### Run ktlint formatter locally
67 | Use `./gradlew ktlintFormat`
68 |
69 |
70 | ## If this project helps you in anyway, show your love :heart: by putting a :star: on this project :v:
71 |
72 |
73 | ## - Contributing
74 |
75 | Please fork this repository and contribute back using
76 | [pull requests](https://github.com/happysingh23828/android-github-repo-template/pulls).
77 |
78 | Any contributions, large or small, major features, bug fixes, are welcomed and appreciated
79 | but will be thoroughly reviewed .
80 |
81 | ### - Contact - Let's become friend
82 | - [Blog](https://happysingh.dev/)
83 | - [Youtube Channel](https://www.youtube.com/channel/UCILhpbLSFkGzsiCYAeR30DA)
84 | - [Github](https://github.com/happysingh23828)
85 | - [Linkedin](https://www.linkedin.com/in/happpysingh23828/)
86 |
87 | ## - License
88 |
89 | ```
90 | MIT License
91 |
92 | Copyright (c) 2020 Happy Singh
93 |
94 | Permission is hereby granted, free of charge, to any person obtaining a copy
95 | of this software and associated documentation files (the "Software"), to deal
96 | in the Software without restriction, including without limitation the rights
97 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
98 | copies of the Software, and to permit persons to whom the Software is
99 | furnished to do so, subject to the following conditions:
100 |
101 | The above copyright notice and this permission notice shall be included in all
102 | copies or substantial portions of the Software.
103 |
104 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
105 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
106 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
107 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
108 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
109 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
110 | SOFTWARE.```
111 |
--------------------------------------------------------------------------------
/app/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{kt,kts}]
2 | # Disabling rules that were added in the latest versions of ktlint
3 | # tracking here: https://github.com/mozilla-mobile/fenix/issues/4861
4 | disabled_rules=import-ordering
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | import dependencies.Dependencies
2 | import dependencies.Version
3 |
4 | apply plugin: Dependencies.Plugins.ANDROID_APPLICATION
5 | apply plugin: Dependencies.Plugins.KOTLIN_ANDROID
6 | apply plugin: Dependencies.Plugins.KOTLIN_ANDROID_EXTENSIONS
7 | apply plugin: Dependencies.Plugins.KOTLIN_KAPT
8 |
9 | android {
10 | compileSdkVersion Version.compileSdk
11 | buildToolsVersion Version.buildTools
12 |
13 | defaultConfig {
14 | applicationId "com.your.packagename"
15 | minSdkVersion Version.minSdk
16 | targetSdkVersion Version.targetSdk
17 | versionCode Version.versionCode
18 | versionName Version.versionName
19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled true
25 | shrinkResources true
26 | debuggable false
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 |
30 | debug {
31 | debuggable true
32 | }
33 | }
34 |
35 | kotlinOptions {
36 | jvmTarget = Version.jvmTarget
37 | }
38 |
39 | androidExtensions {
40 | experimental = true
41 | }
42 |
43 | dataBinding {
44 | enabled = true
45 | }
46 |
47 | testOptions {
48 | unitTests.includeAndroidResources = true
49 | unitTests.returnDefaultValues = true
50 | }
51 |
52 |
53 | // comment out below to create customize apk name with build details.
54 | /*applicationVariants.all { variant ->
55 | variant.outputs.all { output ->
56 | def versionName = variant.versionName
57 | def versionCode = variant.versionCode
58 | def flavorName = variant.flavorName
59 | def variantName = variant.name
60 | //customize your app name by using variables
61 | outputFileName = "YourAppName-$variantName-$versionCode-${versionName}.apk"
62 | }
63 | }*/
64 |
65 | }
66 |
67 | dependencies {
68 | implementation fileTree(dir: "libs", include: ["*.jar"])
69 | implementation Dependencies.Kotlin.kotlin_stdlib_jdk7
70 |
71 | // Modules
72 | implementation project(Dependencies.Module.core)
73 |
74 | //Android X
75 | implementation Dependencies.AndroidX.appcompat
76 | implementation Dependencies.AndroidX.materialDesign
77 | implementation Dependencies.AndroidX.constraintlayout
78 | implementation Dependencies.AndroidX.vectordrawable
79 | implementation Dependencies.AndroidX.core
80 |
81 | //Testing
82 | testImplementation Dependencies.Test.test_junit
83 | androidTestImplementation Dependencies.Test.android_test_espresso_core
84 |
85 | //LifeCycle
86 | implementation Dependencies.Lifecycle.lifeCycleExtension
87 | }
--------------------------------------------------------------------------------
/app/code-quality.gradle:
--------------------------------------------------------------------------------
1 | import dependencies.Dependencies
2 |
3 | //detekt implementation
4 | configurations {
5 | detekt
6 | }
7 |
8 | dependencies {
9 | detekt Dependencies.Lint.detekt
10 | }
11 |
12 | def output = new File(project.buildDir, "reports/detekt/")
13 |
14 | task detekt(type: JavaExec, group: "verification", description: "Runs detekt.") {
15 | def configFile = project.rootProject.file("app/detekt-rule.yml")
16 | inputs.files(project.fileTree(dir: "src", include: "**/*.kt"), configFile)
17 | outputs.dir(output.toString())
18 | main = "io.gitlab.arturbosch.detekt.cli.Main"
19 | classpath = project.configurations.detekt
20 | args = ["--config", configFile, "--input", project.file("."), "--report", "plain:$output/plain.txt,xml:$output/checkstyle.xml,html:$output/report.html"]
21 | }
22 |
23 | // ktlint.
24 | configurations {
25 | ktlint
26 | }
27 |
28 | dependencies {
29 | ktlint Dependencies.Lint.ktLint
30 | }
31 |
32 | def outputDir = "${project.buildDir}/reports/ktlint/"
33 |
34 | task ktlint(type: JavaExec, group: "verification", description: "Runs ktlint.") {
35 | inputs.files(fileTree(dir: "src", include: "**/*.kt"),
36 | fileTree(dir: ".", include: "**/.editorconfig"))
37 | outputs.dir(outputDir)
38 | main = "com.pinterest.ktlint.Main"
39 | classpath = configurations.ktlint
40 | args = ["--reporter=plain",
41 | "--reporter=checkstyle,output=${outputDir}ktlint-checkstyle-report.xml",
42 | "src/**/*.kt"]
43 | }
44 |
45 | // Automatic lint fix with ktlintFormat
46 | task ktlintFormat(type: JavaExec, group: "formatting") {
47 | inputs.files(
48 | fileTree(dir: "src", include: "**/*.kt"),
49 | fileTree(dir: ".", include: "**/.editorconfig")
50 | )
51 | outputs.upToDateWhen { true }
52 | description = "Runs ktlint and autoformats your code."
53 | main = "com.pinterest.ktlint.Main"
54 | classpath = configurations.ktlint
55 | args = ["-F", "src/**/*.kt"]
56 | }
--------------------------------------------------------------------------------
/app/detekt-rule.yml:
--------------------------------------------------------------------------------
1 | build:
2 | maxIssues: 1
3 | weights:
4 | # complexity: 2
5 | # LongParameterList: 1
6 | # style: 1
7 | # comments: 1
8 |
9 | processors:
10 | active: true
11 | exclude:
12 | # - 'DetektProgressListener'
13 | # - 'FunctionCountProcessor'
14 | # - 'PropertyCountProcessor'
15 | # - 'ClassCountProcessor'
16 | # - 'PackageCountProcessor'
17 | # - 'KtFileCountProcessor'
18 |
19 | console-reports:
20 | active: true
21 | exclude:
22 | # - 'ProjectStatisticsReport'
23 | # - 'ComplexityReport'
24 | # - 'NotificationReport'
25 | # - 'FindingsReport'
26 | - 'FileBasedFindingsReport'
27 | # - 'BuildFailureReport'
28 |
29 | comments:
30 | active: true
31 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
32 | CommentOverPrivateFunction:
33 | active: false
34 | CommentOverPrivateProperty:
35 | active: false
36 | EndOfSentenceFormat:
37 | active: false
38 | endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!:]$)
39 | UndocumentedPublicClass:
40 | active: false
41 | searchInNestedClass: true
42 | searchInInnerClass: true
43 | searchInInnerObject: true
44 | searchInInnerInterface: true
45 | UndocumentedPublicFunction:
46 | active: false
47 | UndocumentedPublicProperty:
48 | active: false
49 |
50 | complexity:
51 | active: true
52 | ComplexCondition:
53 | active: true
54 | threshold: 4
55 | ComplexInterface:
56 | active: false
57 | threshold: 10
58 | includeStaticDeclarations: false
59 | ComplexMethod:
60 | active: true
61 | threshold: 10
62 | ignoreSingleWhenExpression: false
63 | ignoreSimpleWhenEntries: false
64 | LabeledExpression:
65 | active: false
66 | ignoredLabels: ""
67 | LargeClass:
68 | active: true
69 | threshold: 600
70 | LongMethod:
71 | active: true
72 | threshold: 60
73 | LongParameterList:
74 | active: true
75 | functionThreshold: 6
76 | constructorThreshold: 6
77 | ignoreDefaultParameters: true
78 | MethodOverloading:
79 | active: false
80 | threshold: 6
81 | NestedBlockDepth:
82 | active: true
83 | threshold: 4
84 | StringLiteralDuplication:
85 | active: false
86 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
87 | threshold: 3
88 | ignoreAnnotation: true
89 | excludeStringsWithLessThan5Characters: true
90 | ignoreStringsRegex: '$^'
91 | TooManyFunctions:
92 | active: true
93 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
94 | thresholdInFiles: 13
95 | thresholdInClasses: 13
96 | thresholdInInterfaces: 13
97 | thresholdInObjects: 13
98 | thresholdInEnums: 13
99 | ignoreDeprecated: false
100 | ignorePrivate: false
101 | ignoreOverridden: false
102 |
103 | empty-blocks:
104 | active: true
105 | EmptyCatchBlock:
106 | active: true
107 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
108 | EmptyClassBlock:
109 | active: true
110 | EmptyDefaultConstructor:
111 | active: true
112 | EmptyDoWhileBlock:
113 | active: true
114 | EmptyElseBlock:
115 | active: true
116 | EmptyFinallyBlock:
117 | active: true
118 | EmptyForBlock:
119 | active: true
120 | EmptyFunctionBlock:
121 | active: true
122 | ignoreOverridden: false
123 | EmptyIfBlock:
124 | active: true
125 | EmptyInitBlock:
126 | active: true
127 | EmptyKtFile:
128 | active: true
129 | EmptySecondaryConstructor:
130 | active: true
131 | EmptyWhenBlock:
132 | active: true
133 | EmptyWhileBlock:
134 | active: true
135 |
136 | exceptions:
137 | active: true
138 | ExceptionRaisedInUnexpectedLocation:
139 | active: false
140 | methodNames: 'toString,hashCode,equals,finalize'
141 | InstanceOfCheckForException:
142 | active: false
143 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
144 | NotImplementedDeclaration:
145 | active: false
146 | PrintStackTrace:
147 | active: false
148 | RethrowCaughtException:
149 | active: false
150 | ReturnFromFinally:
151 | active: false
152 | ignoreLabeled: false
153 | SwallowedException:
154 | active: false
155 | ignoredExceptionTypes: 'InterruptedException,NumberFormatException,ParseException,MalformedURLException'
156 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
157 | ThrowingExceptionFromFinally:
158 | active: false
159 | ThrowingExceptionInMain:
160 | active: false
161 | ThrowingExceptionsWithoutMessageOrCause:
162 | active: false
163 | exceptions: 'IllegalArgumentException,IllegalStateException,IOException'
164 | ThrowingNewInstanceOfSameException:
165 | active: false
166 | TooGenericExceptionCaught:
167 | active: true
168 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
169 | exceptionNames:
170 | - ArrayIndexOutOfBoundsException
171 | - Error
172 | - Exception
173 | - IllegalMonitorStateException
174 | - NullPointerException
175 | - IndexOutOfBoundsException
176 | - RuntimeException
177 | - Throwable
178 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
179 | TooGenericExceptionThrown:
180 | active: true
181 | exceptionNames:
182 | - Error
183 | - Exception
184 | - Throwable
185 | - RuntimeException
186 |
187 | formatting:
188 | active: true
189 | android: false
190 | autoCorrect: true
191 | AnnotationOnSeparateLine:
192 | active: false
193 | autoCorrect: true
194 | ChainWrapping:
195 | active: true
196 | autoCorrect: true
197 | CommentSpacing:
198 | active: true
199 | autoCorrect: true
200 | Filename:
201 | active: true
202 | FinalNewline:
203 | active: true
204 | autoCorrect: true
205 | ImportOrdering:
206 | active: false
207 | autoCorrect: true
208 | Indentation:
209 | active: false
210 | autoCorrect: true
211 | indentSize: 4
212 | continuationIndentSize: 4
213 | MaximumLineLength:
214 | active: true
215 | maxLineLength: 120
216 | ModifierOrdering:
217 | active: true
218 | autoCorrect: true
219 | MultiLineIfElse:
220 | active: true
221 | autoCorrect: true
222 | NoBlankLineBeforeRbrace:
223 | active: true
224 | autoCorrect: true
225 | NoConsecutiveBlankLines:
226 | active: true
227 | autoCorrect: true
228 | NoEmptyClassBody:
229 | active: true
230 | autoCorrect: true
231 | NoLineBreakAfterElse:
232 | active: true
233 | autoCorrect: true
234 | NoLineBreakBeforeAssignment:
235 | active: true
236 | autoCorrect: true
237 | NoMultipleSpaces:
238 | active: true
239 | autoCorrect: true
240 | NoSemicolons:
241 | active: true
242 | autoCorrect: true
243 | NoTrailingSpaces:
244 | active: true
245 | autoCorrect: true
246 | NoUnitReturn:
247 | active: true
248 | autoCorrect: true
249 | NoUnusedImports:
250 | active: true
251 | autoCorrect: true
252 | NoWildcardImports:
253 | active: true
254 | PackageName:
255 | active: true
256 | autoCorrect: true
257 | ParameterListWrapping:
258 | active: true
259 | autoCorrect: true
260 | indentSize: 4
261 | SpacingAroundColon:
262 | active: true
263 | autoCorrect: true
264 | SpacingAroundComma:
265 | active: true
266 | autoCorrect: true
267 | SpacingAroundCurly:
268 | active: true
269 | autoCorrect: true
270 | SpacingAroundDot:
271 | active: true
272 | autoCorrect: true
273 | SpacingAroundKeyword:
274 | active: true
275 | autoCorrect: true
276 | SpacingAroundOperators:
277 | active: true
278 | autoCorrect: true
279 | SpacingAroundParens:
280 | active: true
281 | autoCorrect: true
282 | SpacingAroundRangeOperator:
283 | active: true
284 | autoCorrect: true
285 | StringTemplate:
286 | active: true
287 | autoCorrect: true
288 |
289 | naming:
290 | active: true
291 | ClassNaming:
292 | active: true
293 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
294 | classPattern: '[A-Z$][a-zA-Z0-9$]*'
295 | ConstructorParameterNaming:
296 | active: true
297 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
298 | parameterPattern: '[a-z][A-Za-z0-9]*'
299 | privateParameterPattern: '[a-z][A-Za-z0-9]*'
300 | excludeClassPattern: '$^'
301 | EnumNaming:
302 | active: true
303 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
304 | enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*'
305 | ForbiddenClassName:
306 | active: false
307 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
308 | forbiddenName: ''
309 | FunctionMaxLength:
310 | active: false
311 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
312 | maximumFunctionNameLength: 30
313 | FunctionMinLength:
314 | active: false
315 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
316 | minimumFunctionNameLength: 3
317 | FunctionNaming:
318 | active: true
319 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
320 | functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$'
321 | excludeClassPattern: '$^'
322 | ignoreOverridden: true
323 | FunctionParameterNaming:
324 | active: true
325 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
326 | parameterPattern: '[a-z][A-Za-z0-9]*'
327 | excludeClassPattern: '$^'
328 | ignoreOverridden: true
329 | InvalidPackageDeclaration:
330 | active: false
331 | rootPackage: ''
332 | MatchingDeclarationName:
333 | active: true
334 | MemberNameEqualsClassName:
335 | active: false
336 | ignoreOverridden: true
337 | ObjectPropertyNaming:
338 | active: true
339 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
340 | constantPattern: '[A-Za-z][_A-Za-z0-9]*'
341 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
342 | privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'
343 | PackageNaming:
344 | active: true
345 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
346 | packagePattern: '^[a-z]+(\.[a-z][A-Za-z0-9]*)*$'
347 | TopLevelPropertyNaming:
348 | active: true
349 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
350 | constantPattern: '[A-Z][_A-Z0-9]*'
351 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
352 | privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*'
353 | VariableMaxLength:
354 | active: false
355 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
356 | maximumVariableNameLength: 64
357 | VariableMinLength:
358 | active: false
359 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
360 | minimumVariableNameLength: 1
361 | VariableNaming:
362 | active: true
363 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
364 | variablePattern: '[a-z][A-Za-z0-9]*'
365 | privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'
366 | excludeClassPattern: '$^'
367 | ignoreOverridden: true
368 |
369 | performance:
370 | active: true
371 | ArrayPrimitive:
372 | active: false
373 | ForEachOnRange:
374 | active: true
375 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
376 | SpreadOperator:
377 | active: true
378 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
379 | UnnecessaryTemporaryInstantiation:
380 | active: true
381 |
382 | potential-bugs:
383 | active: true
384 | Deprecation:
385 | active: false
386 | DuplicateCaseInWhenExpression:
387 | active: true
388 | EqualsAlwaysReturnsTrueOrFalse:
389 | active: false
390 | EqualsWithHashCodeExist:
391 | active: true
392 | ExplicitGarbageCollectionCall:
393 | active: true
394 | HasPlatformType:
395 | active: false
396 | InvalidRange:
397 | active: false
398 | IteratorHasNextCallsNextMethod:
399 | active: false
400 | IteratorNotThrowingNoSuchElementException:
401 | active: false
402 | LateinitUsage:
403 | active: false
404 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
405 | excludeAnnotatedProperties: ""
406 | ignoreOnClassesPattern: ""
407 | MissingWhenCase:
408 | active: false
409 | RedundantElseInWhen:
410 | active: false
411 | UnconditionalJumpStatementInLoop:
412 | active: false
413 | UnreachableCode:
414 | active: true
415 | UnsafeCallOnNullableType:
416 | active: false
417 | UnsafeCast:
418 | active: false
419 | UselessPostfixExpression:
420 | active: false
421 | WrongEqualsTypeParameter:
422 | active: false
423 |
424 | style:
425 | active: true
426 | CollapsibleIfStatements:
427 | active: false
428 | DataClassContainsFunctions:
429 | active: false
430 | conversionFunctionPrefix: 'to'
431 | DataClassShouldBeImmutable:
432 | active: false
433 | EqualsNullCall:
434 | active: false
435 | EqualsOnSignatureLine:
436 | active: false
437 | ExplicitItLambdaParameter:
438 | active: false
439 | ExpressionBodySyntax:
440 | active: false
441 | includeLineWrapping: false
442 | ForbiddenComment:
443 | active: true
444 | values: 'TODO:,FIXME:,STOPSHIP:'
445 | allowedPatterns: ""
446 | ForbiddenImport:
447 | active: false
448 | imports: ''
449 | forbiddenPatterns: ""
450 | ForbiddenVoid:
451 | active: false
452 | ignoreOverridden: false
453 | ignoreUsageInGenerics: false
454 | FunctionOnlyReturningConstant:
455 | active: false
456 | ignoreOverridableFunction: true
457 | excludedFunctions: 'describeContents'
458 | excludeAnnotatedFunction: "dagger.Provides"
459 | LibraryCodeMustSpecifyReturnType:
460 | active: false
461 | LoopWithTooManyJumpStatements:
462 | active: false
463 | maxJumpCount: 1
464 | MagicNumber:
465 | active: true
466 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
467 | ignoreNumbers: '-1,0,1,2'
468 | ignoreHashCodeFunction: true
469 | ignorePropertyDeclaration: false
470 | ignoreConstantDeclaration: true
471 | ignoreCompanionObjectPropertyDeclaration: true
472 | ignoreAnnotation: false
473 | ignoreNamedArgument: true
474 | ignoreEnums: false
475 | ignoreRanges: false
476 | MandatoryBracesIfStatements:
477 | active: false
478 | MaxLineLength:
479 | active: true
480 | maxLineLength: 120
481 | excludePackageStatements: true
482 | excludeImportStatements: true
483 | excludeCommentStatements: false
484 | MayBeConst:
485 | active: false
486 | ModifierOrder:
487 | active: true
488 | NestedClassesVisibility:
489 | active: false
490 | NewLineAtEndOfFile:
491 | active: true
492 | NoTabs:
493 | active: false
494 | OptionalAbstractKeyword:
495 | active: true
496 | OptionalUnit:
497 | active: false
498 | OptionalWhenBraces:
499 | active: false
500 | PreferToOverPairSyntax:
501 | active: false
502 | ProtectedMemberInFinalClass:
503 | active: false
504 | RedundantExplicitType:
505 | active: false
506 | RedundantVisibilityModifierRule:
507 | active: false
508 | ReturnCount:
509 | active: true
510 | max: 2
511 | excludedFunctions: "equals"
512 | excludeLabeled: false
513 | excludeReturnFromLambda: true
514 | excludeGuardClauses: false
515 | SafeCast:
516 | active: true
517 | SerialVersionUIDInSerializableClass:
518 | active: false
519 | SpacingBetweenPackageAndImports:
520 | active: false
521 | ThrowsCount:
522 | active: true
523 | max: 2
524 | TrailingWhitespace:
525 | active: false
526 | UnderscoresInNumericLiterals:
527 | active: false
528 | acceptableDecimalLength: 5
529 | UnnecessaryAbstractClass:
530 | active: false
531 | excludeAnnotatedClasses: "dagger.Module"
532 | UnnecessaryApply:
533 | active: false
534 | UnnecessaryInheritance:
535 | active: false
536 | UnnecessaryLet:
537 | active: false
538 | UnnecessaryParentheses:
539 | active: false
540 | UntilInsteadOfRangeTo:
541 | active: false
542 | UnusedImports:
543 | active: false
544 | UnusedPrivateClass:
545 | active: false
546 | UnusedPrivateMember:
547 | active: false
548 | allowedNames: "(_|ignored|expected|serialVersionUID)"
549 | UseArrayLiteralsInAnnotations:
550 | active: false
551 | UseCheckOrError:
552 | active: false
553 | UseDataClass:
554 | active: false
555 | excludeAnnotatedClasses: ""
556 | allowVars: false
557 | UseIfInsteadOfWhen:
558 | active: false
559 | UseRequire:
560 | active: false
561 | UselessCallOnNotNull:
562 | active: false
563 | UtilityClassWithPublicConstructor:
564 | active: false
565 | VarCouldBeVal:
566 | active: false
567 | WildcardImport:
568 | active: true
569 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
570 | excludeImports: 'java.util.*,kotlinx.android.synthetic.*'
571 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/app/src/androidTest/java/dev/happysingh/template/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.template
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 | import org.junit.Assert.assertEquals
6 |
7 | import org.junit.Test
8 | import org.junit.runner.RunWith
9 |
10 | /**
11 | * Instrumented test, which will execute on an Android device.
12 | *
13 | * See [testing documentation](http://d.android.com/tools/testing).
14 | */
15 | @RunWith(AndroidJUnit4::class)
16 | class ExampleInstrumentedTest {
17 | @Test
18 | fun useAppContext() {
19 | // Context of the app under test.
20 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
21 | assertEquals("dev.happysingh.template", appContext.packageName)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/dev/happysingh/template/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.template
2 |
3 | import android.app.Application
4 |
5 | class MainApplication : Application()
6 |
--------------------------------------------------------------------------------
/app/src/main/java/dev/happysingh/template/ui/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.template.ui
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import dev.happysingh.template.R
6 |
7 | class MainActivity : AppCompatActivity() {
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | setContentView(R.layout.activity_main)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Android-Repo-Github-Template
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/test/java/dev/happysingh/template/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.template
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | import dependencies.Dependencies
2 | import dependencies.MavenUrls
3 |
4 | buildscript {
5 | repositories {
6 | google()
7 | jcenter()
8 | maven { url MavenUrls.JITPACK_IO}
9 | }
10 | dependencies {
11 | classpath Dependencies.ClassPaths.gradleClasspath
12 | classpath Dependencies.ClassPaths.kotlinGradlePluginClasspath
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | google()
19 | jcenter()
20 | maven { url MavenUrls.JITPACK_IO}
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
27 |
28 | subprojects { subProject ->
29 | //this allows to run detekt or ktlint for a specific module
30 | // example usage: ./gradlew :data:ktlintFormat
31 | apply from: "$project.rootDir/app/code-quality.gradle"
32 | }
--------------------------------------------------------------------------------
/buildSrc/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/buildSrc/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'kotlin'
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.3.72'
5 | repositories {
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
10 | }
11 | }
12 | repositories {
13 | mavenCentral()
14 | }
15 | dependencies {
16 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
17 | }
18 | compileKotlin {
19 | kotlinOptions {
20 | jvmTarget = "1.8"
21 | }
22 | }
23 | compileTestKotlin {
24 | kotlinOptions {
25 | jvmTarget = "1.8"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/buildSrc/src/main/java/ConfigFields.kt:
--------------------------------------------------------------------------------
1 | package dependencies
2 |
3 | object ConfigFields {
4 | // add your config fields KEYS here for ex :
5 | // const val BASE_URL = "BASE_URL"
6 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Dependencies.kt:
--------------------------------------------------------------------------------
1 | package dependencies
2 |
3 | object Dependencies {
4 |
5 | // add your modules variables here
6 | object Module {
7 | const val core = ":core"
8 | }
9 |
10 |
11 | object ClassPaths {
12 | const val gradleClasspath = "com.android.tools.build:gradle:${Version.gradleVersion}"
13 | const val googleService = "com.google.gms:google-services:${Version.googleServices}"
14 | const val firebaseCrashlytics = "com.google.firebase:firebase-crashlytics-gradle:${Version.firebaseCrashlyticsGradle}"
15 | const val navigationSafeArgs = "androidx.navigation:navigation-safe-args-gradle-plugin:${Version.navigation}"
16 | const val kotlinGradlePluginClasspath =
17 | "org.jetbrains.kotlin:kotlin-gradle-plugin:${Version.kotlinVersion}"
18 | const val dokkaPluginClasspath =
19 | "org.jetbrains.dokka:dokka-gradle-plugin:${Version.dokkaVeresion}"
20 | const val jacoco = "com.vanniktech:gradle-android-junit-jacoco-plugin:${Version.jacoco}"
21 | }
22 |
23 | object Plugins {
24 | const val ANDROID_APPLICATION = "com.android.application"
25 | const val ANDROID_LIBRARY = "com.android.library"
26 | const val GOOGLE_SERVICES = "com.google.gms.google-services"
27 | const val FIREBASE_CRASHLYTICS = "com.google.firebase.crashlytics"
28 | const val KOTLIN_ANDROID = "kotlin-android"
29 | const val KOTLIN_KAPT = "kotlin-kapt"
30 | const val KOTLIN_ANDROID_EXTENSIONS = "kotlin-android-extensions"
31 | const val SAFE_ARGS = "androidx.navigation.safeargs.kotlin"
32 | const val DETEKT = "io.gitlab.arturbosch.detekt"
33 | const val JACOCO = "com.vanniktech.android.junit.jacoco"
34 | }
35 |
36 | object Lint {
37 | const val detekt = "io.gitlab.arturbosch.detekt:detekt-cli:${Version.detektVersion}"
38 | const val ktLint = "com.pinterest:ktlint:${Version.ktLint}"
39 | }
40 |
41 | object Firebase {
42 | const val core = "com.google.firebase:firebase-core:${Version.firebaseCore}"
43 | const val analytics = "com.google.firebase:firebase-analytics:${Version.firebaseAnalytics}"
44 | const val crashlytics = "com.google.firebase:firebase-crashlytics:${Version.firebaseCrashlytics}"
45 | const val messaging = "com.google.firebase:firebase-messaging:${Version.message}"
46 | const val play_services = "com.google.android.gms:play-services-auth:${Version.play_services}"
47 | const val play_plus = "com.google.android.gms:play-services-plus:${Version.play_plus}"
48 | const val location = "com.google.android.gms:play-services-location:${Version.location}"
49 | const val remoteConfig = "com.google.firebase:firebase-config:${Version.firebaseRemoteConfig}"
50 | const val playCore = "com.google.android.play:core:${Version.playCore}"
51 |
52 | }
53 |
54 | object Lifecycle {
55 | const val extension = "android.arch.lifecycle:extensions:${Version.lifecycle}"
56 | const val annotation_compliler = "android.arch.lifecycle:compiler:${Version.lifecycle}"
57 |
58 | // ViewModel and LiveData
59 | const val lifeCycleExtension =
60 | "androidx.lifecycle:lifecycle-extensions:${Version.lifecycleVersion}"
61 | }
62 |
63 | object Glide {
64 | const val glide = "com.github.bumptech.glide:glide:${Version.glide}"
65 | const val annotationProcessor = "androidx.annotation:annotation:1.0.0"
66 | const val annotationCompiler = "com.github.bumptech.glide:compiler:${Version.glide}"
67 | }
68 |
69 | object Gson {
70 | const val gson = "com.google.code.gson:gson:${Version.gson}"
71 | }
72 |
73 | object Kotlin {
74 | const val kotlin_stdlib_jdk7 = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Version.kotlin}"
75 | }
76 |
77 | object OkHttp3 {
78 | const val loggingInterceptor =
79 | "com.squareup.okhttp3:logging-interceptor:${Version.retrofit_log}"
80 | const val okHttp3 = "com.squareup.okhttp3:okhttp:3.12.1"
81 | }
82 |
83 | object Retrofit2 {
84 | const val adapterRxjava2 = "com.squareup.retrofit2:adapter-rxjava2:${Version.retrofit}"
85 | const val converterGson = "com.squareup.retrofit2:converter-gson:${Version.retrofit}"
86 | const val retrofit = "com.squareup.retrofit2:retrofit:${Version.retrofit}"
87 | }
88 |
89 | object AndroidX {
90 | const val fragment = "androidx.fragment:fragment:${Version.androidx}"
91 | const val annotation = "androidx.annotation:annotation:${Version.androidx}"
92 | const val core = "androidx.core:core:${Version.androidx}"
93 | const val coreKtx = "androidx.core:core-ktx:${Version.ktx}"
94 | const val constraintlayout =
95 | "androidx.constraintlayout:constraintlayout:${Version.androidx_112}"
96 | const val materialDesign = "com.google.android.material:material:${Version.materialDesign}"
97 | const val support_recyclerview_v7 =
98 | "androidx.recyclerview:recyclerview:${Version.recyclerView}"
99 | const val appcompat = "androidx.appcompat:appcompat:${Version.androidx_100beta01}"
100 | const val vectordrawable =
101 | "androidx.vectordrawable:vectordrawable:${Version.androidx_100beta01}"
102 | const val legacySupport = "androidx.legacy:legacy-support-v4:${Version.legacySupport}"
103 | const val navigation = "androidx.navigation:navigation-fragment-ktx:${Version.navigation}"
104 | const val navigationUI = "androidx.navigation:navigation-ui-ktx:${Version.navigation}"
105 | }
106 |
107 | object Room {
108 | const val runtime = "androidx.room:room-runtime:${Version.room}"
109 | const val rxjava2 = "androidx.room:room-rxjava2:${Version.room}"
110 | const val annotationProcessor = "androidx.room:room-compiler:${Version.room}"
111 | }
112 |
113 | object RxJava {
114 | const val rxAndroid = "io.reactivex.rxjava2:rxandroid:${Version.rxAndroid}"
115 | const val rxjava2 = "io.reactivex.rxjava2:rxjava:${Version.rx}"
116 | const val rxrelay2 = "com.jakewharton.rxrelay2:rxrelay:${Version.rxRelay}"
117 | const val rxBinding = "com.jakewharton.rxbinding3:rxbinding:${Version.rxBinding}"
118 | }
119 |
120 | object Dagger {
121 | const val dagger2 = "com.google.dagger:dagger:${Version.dagger2}"
122 | const val daggerAndroid = "com.google.dagger:dagger-android:${Version.dagger2}"
123 | const val daggerAndroidSupport =
124 | "com.google.dagger:dagger-android-support:${Version.dagger2}"
125 | const val processor = "com.google.dagger:dagger-android-processor:${Version.dagger2}"
126 | const val compiler = "com.google.dagger:dagger-compiler:${Version.dagger2}"
127 | }
128 |
129 | object Test {
130 | const val test_junit = "androidx.test.ext:junit:${Version.androidXJunit}"
131 | const val android_test_espresso_core =
132 | "androidx.test.espresso:espresso-core:${Version.espresso}"
133 | const val android_test_room = "android.arch.persistence.room:testing:${Version.room}"
134 | const val testing_core_testing = "android.arch.core:core-testing:${Version.lifecycle}"
135 | const val android_test_rules = "androidx.test:rules:${Version.rules}"
136 | const val android_test_runner = "androidx.test:runner:${Version.runner}"
137 | const val mockito = "org.mockito:mockito-core:${Version.mockito}"
138 | const val mockitoInLine = "org.mockito:mockito-inline:${Version.mockitoInline}"
139 | const val mockWebServer = "com.squareup.okhttp3:mockwebserver:${Version.mockWebServer}"
140 | const val assert_j = "org.assertj:assertj-core:${Version.assertJVersion}"
141 | const val roboElectric = "org.robolectric:robolectric:${Version.roboElectric}"
142 | }
143 |
144 | object Support {
145 | const val supportV4 = "com.android.support:support-v4:${Version.supportLib}"
146 | }
147 |
148 | object ThirdPartiesLib {
149 | const val timber = "com.jakewharton.timber:timber:${Version.timber}"
150 | const val jodaTime = "joda-time:joda-time:${Version.jodaTime}"
151 | const val picasso = "com.squareup.picasso:picasso:${Version.picasso}"
152 | }
153 |
154 | const val javax = "javax.inject:javax.inject:${Version.javaxInject}"
155 | const val javaxjsr250 = "javax.annotation:jsr250-api:${Version.javaxAnnotation}"
156 | const val parceler = "org.parceler:parceler-api:${Version.parcelerVersion}"
157 | const val parcelerProcessor = "org.parceler:parceler-api:${Version.parcelerVersion}"
158 | }
159 |
--------------------------------------------------------------------------------
/buildSrc/src/main/java/MavenUrls.kt:
--------------------------------------------------------------------------------
1 | package dependencies
2 |
3 | object MavenUrls {
4 | const val FABRIC_PUBLIC = "https://maven.fabric.io/public"
5 | const val JITPACK_IO = "https://jitpack.io"
6 | const val COMMONS_WARE = "https://s3.amazonaws.com/repo.commonsware.com"
7 | const val PLUGIN_GRADLE_M2 = "https://plugins.gradle.org/m2/"
8 | }
9 |
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Version.kt:
--------------------------------------------------------------------------------
1 | package dependencies
2 |
3 | object Version {
4 |
5 | // android configuration
6 | const val buildTools = "28.0.3"
7 | const val compileSdk = 29
8 | const val minSdk = 21
9 | const val targetSdk = 29
10 | const val versionCode = 3
11 | const val versionName = "1.0.0"
12 |
13 | // Libraries
14 | const val supportLib = "28.0.0"
15 | const val recyclerView = "1.0.0"
16 | const val androidx = "1.0.0"
17 | const val androidx_112 = "1.1.3"
18 | const val androidx_100beta01 = "1.0.0-beta01"
19 | const val assertJVersion = "3.2.0"
20 | const val circleImageView = "3.1.0"
21 | const val componentManager = "2.0.1"
22 | const val firebaseBOM = "25.12.0"
23 | const val firebaseCore = "17.4.4"
24 | const val firebaseAnalytics = "18.0.0"
25 | const val firebasePref = "19.0.8"
26 | const val firebaseCrashlytics = "17.2.1"
27 | const val firebaseCrashlyticsGradle = "2.2.1"
28 | const val firebaseRemoteConfig = "19.1.4"
29 | const val materialDesign = "1.2.1"
30 | const val mockito = "1.10.19"
31 | const val mockitoInline = "2.24.5"
32 | const val mockWebServer = "4.9.0"
33 | const val mpAndroidChart = "3.1.0"
34 | const val navigation = "2.3.0"
35 | const val dagger2 = "2.21"
36 | const val lifecycleVersion = "2.0.0"
37 | const val javaxInject = "1"
38 | const val javaxAnnotation = "1.0"
39 | const val jacoco = "0.16.0"
40 | const val jodaTime = "2.10.6"
41 | const val jvmTarget = "1.8"
42 | const val parcelerVersion = "1.1.12"
43 | const val permissionDispatcher = "4.8.0"
44 | const val permissionAnnotation = "4.8.0"
45 | const val picasso = "2.71828"
46 | const val gradleVersion = "3.5.0"
47 | const val googleServices = "4.3.3"
48 | const val ktx = "1.1.0"
49 | const val ktLint = "0.35.0"
50 | const val kotlinVersion = "1.3.50"
51 | const val legacySupport = "1.0.0"
52 | const val dokkaVeresion = "0.9.18"
53 | const val espresso = "3.1.0"
54 | const val glide = "4.9.0"
55 | const val gson = "2.8.5"
56 | const val androidXJunit = "1.1.2"
57 | const val kotlin = "1.3.31"
58 | const val lifecycle = "1.1.1"
59 | const val playCore = "1.7.0"
60 | const val reactiveNetwork = "3.0.3"
61 | const val retrofit = "2.5.0"
62 | const val retrofit_log = "3.10.0"
63 | const val roboElectric = "3.4.2"
64 | const val room = "2.2.5"
65 | const val rules = "1.1.0"
66 | const val runner = "1.1.0"
67 | const val rx = "2.1.0"
68 | const val rxAndroid = "2.0.1"
69 | const val rxRelay = "2.0.0"
70 | const val rxBinding = "3.0.0"
71 | const val stetho = "1.5.1"
72 | const val timber = "4.7.1"
73 | const val message = "21.0.0"
74 | const val play_services = "18.1.0"
75 | const val play_plus = "17.0.0"
76 | const val location = "17.1.0"
77 | const val expandableLayout = "2.9.2"
78 | const val progressWheel = "1.1.5"
79 | const val imageSlider = "1.4.0"
80 |
81 | // plugins versions
82 | const val detektVersion = "1.9.1"
83 | }
84 |
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/build.gradle:
--------------------------------------------------------------------------------
1 | import dependencies.Dependencies
2 | import dependencies.Version
3 |
4 | apply plugin: Dependencies.Plugins.ANDROID_LIBRARY
5 | apply plugin: Dependencies.Plugins.KOTLIN_ANDROID
6 | apply plugin: Dependencies.Plugins.KOTLIN_ANDROID_EXTENSIONS
7 | apply plugin: Dependencies.Plugins.KOTLIN_KAPT
8 |
9 | android {
10 | compileSdkVersion Version.compileSdk
11 | buildToolsVersion Version.buildTools
12 |
13 | defaultConfig {
14 | minSdkVersion Version.minSdk
15 | targetSdkVersion Version.targetSdk
16 | versionCode Version.versionCode
17 | versionName Version.versionName
18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
19 | consumerProguardFiles "consumer-rules.pro"
20 | }
21 |
22 | kotlinOptions {
23 | jvmTarget = Version.jvmTarget
24 | }
25 |
26 | androidExtensions {
27 | experimental = true
28 | }
29 |
30 | dataBinding {
31 | enabled = true
32 | }
33 |
34 | buildTypes {
35 | release {
36 | minifyEnabled false
37 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
38 | }
39 |
40 | debug {
41 | debuggable true
42 | }
43 | }
44 |
45 | }
46 |
47 | dependencies {
48 | implementation fileTree(dir: "libs", include: ["*.jar"])
49 | implementation Dependencies.Kotlin.kotlin_stdlib_jdk7
50 |
51 | //Android X
52 | implementation Dependencies.AndroidX.appcompat
53 | implementation Dependencies.AndroidX.materialDesign
54 | implementation Dependencies.AndroidX.constraintlayout
55 | implementation Dependencies.AndroidX.vectordrawable
56 | implementation Dependencies.AndroidX.core
57 |
58 | //Testing
59 | testImplementation Dependencies.Test.test_junit
60 | androidTestImplementation Dependencies.Test.android_test_espresso_core
61 |
62 | //LifeCycle
63 | implementation Dependencies.Lifecycle.lifeCycleExtension
64 | }
--------------------------------------------------------------------------------
/core/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/core/consumer-rules.pro
--------------------------------------------------------------------------------
/core/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in 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
--------------------------------------------------------------------------------
/core/src/androidTest/java/dev/happysingh/core/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("dev.happysingh.core.test", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.base
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 |
5 | abstract class BaseActivity : AppCompatActivity()
6 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/base/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.base
2 |
3 | import androidx.fragment.app.Fragment
4 |
5 | abstract class BaseFragment : Fragment()
6 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/ActivityExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.app.Activity
4 | import android.view.WindowManager
5 | import android.view.inputmethod.InputMethodManager
6 | import android.widget.EditText
7 | import android.widget.Toast
8 | import androidx.annotation.StyleRes
9 | import androidx.appcompat.app.AppCompatActivity
10 | import androidx.fragment.app.Fragment
11 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
12 | import com.google.android.material.snackbar.Snackbar
13 | import dev.happysingh.core.R
14 |
15 | fun AppCompatActivity.disableScreenCapture(buildType: String) {
16 | this.window.setFlags(
17 | WindowManager.LayoutParams.FLAG_SECURE,
18 | WindowManager.LayoutParams.FLAG_SECURE
19 | )
20 | }
21 |
22 | fun Activity.hideInputMethod() =
23 | run {
24 | val inputMethodManager: InputMethodManager =
25 | getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
26 | window.peekDecorView()
27 | ?.let {
28 | inputMethodManager.hideSoftInputFromWindow(
29 | window.peekDecorView().windowToken,
30 | 0
31 | )
32 | }
33 | }
34 |
35 | fun Activity.showInputMethod(v: EditText) =
36 | run {
37 | val inputMethodManager: InputMethodManager =
38 | getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
39 | v.requestFocus()
40 | inputMethodManager.showSoftInput(v, InputMethodManager.SHOW_FORCED)
41 | }
42 |
43 | /**
44 | * This showToast fun can be called from Activity
45 | */
46 | fun AppCompatActivity.showToast(message: String?) {
47 | Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
48 | }
49 |
50 | /**
51 | * This showSnackBar fun can be called from Activity
52 | */
53 | fun AppCompatActivity.showSnackBar(message: String) {
54 | val mParentView = this.window.decorView.rootView
55 | if (mParentView != null) {
56 | Snackbar.make(mParentView, message, Snackbar.LENGTH_LONG).show()
57 | }
58 | }
59 |
60 | fun AppCompatActivity.openSelectionDialog(
61 | title: String,
62 | arrayOfString: Array,
63 | onPositionSelect: (Int) -> Unit,
64 | @StyleRes style: Int = 0
65 | ) {
66 |
67 | MaterialAlertDialogBuilder(this, style)
68 | .setTitle(title)
69 | .setItems(arrayOfString) { dialog, which ->
70 | onPositionSelect.invoke(which)
71 | dialog.dismiss()
72 | }.show()
73 | }
74 |
75 | fun AppCompatActivity.openConfirmDialog(
76 | msg: String,
77 | onYesClick: () -> Unit,
78 | onNoClick: () -> Unit
79 | ) {
80 | MaterialAlertDialogBuilder(this)
81 | .setMessage(msg)
82 | .setPositiveButton(getString(R.string.yes)) { dialog, _ ->
83 | onYesClick.invoke()
84 | dialog.dismiss()
85 | }
86 | .setNegativeButton(getString(R.string.no)) { dialog, _ ->
87 | onNoClick.invoke()
88 | dialog.dismiss()
89 | }.show()
90 | }
91 |
92 | fun AppCompatActivity.getScreenOrientation(): ScreenOrientation {
93 | return when (resources.configuration.orientation) {
94 | ScreenOrientation.PORTRAIT.value -> ScreenOrientation.PORTRAIT
95 | ScreenOrientation.LANDSCAPE.value -> ScreenOrientation.LANDSCAPE
96 | else -> ScreenOrientation.PORTRAIT
97 | }
98 | }
99 |
100 | fun AppCompatActivity.addFragment(layoutId: Int, fragment: Fragment) {
101 | this.supportFragmentManager.beginTransaction().add(layoutId, fragment).commit()
102 | }
103 |
104 | fun AppCompatActivity.replaceFragment(layoutId: Int, fragment: Fragment) {
105 | this.supportFragmentManager.beginTransaction().replace(layoutId, fragment).commit()
106 | }
107 |
108 | fun AppCompatActivity.addFragmentWithBackStack(layoutId: Int, fragment: Fragment, tag: String) {
109 | this.supportFragmentManager.beginTransaction().add(layoutId, fragment)
110 | .addToBackStack(tag).commit()
111 | }
112 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/AndroidApiExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.os.Build
4 |
5 | inline fun aboveApi(api: Int, included: Boolean = false, block: () -> Unit) {
6 | if (Build.VERSION.SDK_INT > if (included) api - 1 else api) {
7 | block()
8 | }
9 | }
10 |
11 | inline fun belowApi(api: Int, included: Boolean = false, block: () -> Unit) {
12 | if (Build.VERSION.SDK_INT < if (included) api + 1 else api) {
13 | block()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/BitmapExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.graphics.Bitmap
4 | import android.graphics.Matrix
5 | import android.util.Base64
6 | import java.io.ByteArrayOutputStream
7 | import java.io.File
8 | import java.io.FileOutputStream
9 |
10 | private const val BITMAP_QUALITY = 100
11 | fun Bitmap.toBase64(compressFormat: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG): String {
12 | val result: String
13 | val baos = ByteArrayOutputStream()
14 | compress(compressFormat, BITMAP_QUALITY, baos)
15 | baos.flush()
16 | baos.close()
17 | val bitmapBytes = baos.toByteArray()
18 | result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT)
19 | baos.flush()
20 | baos.close()
21 | return result
22 | }
23 |
24 | fun Bitmap.resize(w: Number, h: Number): Bitmap {
25 | val width = width
26 | val height = height
27 | val scaleWidth = w.toFloat() / width
28 | val scaleHeight = h.toFloat() / height
29 | val matrix = Matrix()
30 | matrix.postScale(scaleWidth, scaleHeight)
31 | if (width > 0 && height > 0) {
32 | return Bitmap.createBitmap(this, 0, 0, width, height, matrix, true)
33 | }
34 | return this
35 | }
36 |
37 | fun Bitmap.saveFile(path: String, compressFormat: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG) {
38 | val f = File(path)
39 | if (!f.exists()) {
40 | f.createNewFile()
41 | }
42 | val stream = FileOutputStream(f)
43 | compress(compressFormat, BITMAP_QUALITY, stream)
44 | stream.flush()
45 | stream.close()
46 | }
47 |
48 | fun Bitmap.toByteArray(compressFormat: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG): ByteArray {
49 | val stream = ByteArrayOutputStream()
50 | compress(compressFormat, BITMAP_QUALITY, stream)
51 | return stream.toByteArray()
52 | }
53 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/CommonViewExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.view.View
4 | import android.view.ViewGroup
5 | import com.google.android.material.snackbar.Snackbar
6 |
7 | operator fun ViewGroup.get(index: Int): View {
8 | return getChildAt(index)
9 | }
10 |
11 | fun View.visible() {
12 | if (visibility != View.VISIBLE) {
13 | visibility = View.VISIBLE
14 | }
15 | }
16 |
17 | inline fun View.visibleIf(block: () -> Boolean) {
18 | if (visibility != View.VISIBLE && block()) {
19 | visibility = View.VISIBLE
20 | }
21 | }
22 |
23 | fun View.invisible() {
24 | if (visibility != View.INVISIBLE) {
25 | visibility = View.INVISIBLE
26 | }
27 | }
28 |
29 | inline fun View.invisiableIf(block: () -> Boolean) {
30 | if (visibility != View.INVISIBLE && block()) {
31 | visibility = View.INVISIBLE
32 | }
33 | }
34 |
35 | fun View.gone() {
36 | if (visibility != View.GONE) {
37 | visibility = View.GONE
38 | }
39 | }
40 |
41 | inline fun View.goneIf(block: () -> Boolean) {
42 | if (visibility != View.GONE && block()) {
43 | visibility = View.GONE
44 | }
45 | }
46 |
47 | fun View.isVisible() = visibility == View.VISIBLE
48 |
49 | fun View.isGone() = visibility == View.GONE
50 |
51 | fun View.isInvisible() = visibility == View.INVISIBLE
52 |
53 | /**
54 | * This showSnackBar fun can be called from any view
55 | */
56 | fun View.showSnackBar(message: String) {
57 | Snackbar.make(this, message, Snackbar.LENGTH_LONG).show()
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/CoreExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.content.res.Configuration
6 | import android.graphics.Paint
7 | import android.net.Uri
8 | import android.provider.Settings
9 | import android.view.View
10 | import android.view.ViewGroup
11 | import android.widget.Toast
12 | import androidx.annotation.ColorRes
13 | import androidx.appcompat.widget.AppCompatTextView
14 | import androidx.core.content.ContextCompat
15 | import androidx.core.graphics.ColorUtils
16 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
17 | import kotlin.math.roundToInt
18 |
19 | fun isAllValuesNull(vararg items: Int?): Boolean {
20 | for (item in items) {
21 | if (item == null) {
22 | return true
23 | }
24 | }
25 | return false
26 | }
27 |
28 | fun isAllValuesNull(vararg items: String?): Boolean {
29 | for (item in items) {
30 | if (item == null) {
31 | return true
32 | }
33 | }
34 | return false
35 | }
36 |
37 | fun isAllValuesNull(vararg items: Any?): Boolean {
38 | for (item in items) {
39 | if (item == null) {
40 | return true
41 | }
42 | }
43 | return false
44 | }
45 |
46 | fun Float.roundToOneDecimalPlace(): Float {
47 | return String.format("%.2f", this).toFloat()
48 | }
49 |
50 | fun Context.shareIntent(msg: String) {
51 | val shareIntent = Intent()
52 | shareIntent.action = Intent.ACTION_SEND
53 | shareIntent.type = "text/plain"
54 | shareIntent.putExtra(Intent.EXTRA_TEXT, msg)
55 | startActivity(Intent.createChooser(shareIntent, "Share to"))
56 | }
57 |
58 | fun Context.openSettings() {
59 | val intent = Intent(
60 | Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
61 | Uri.fromParts("package", packageName, null)
62 | )
63 | intent.addCategory(Intent.CATEGORY_DEFAULT)
64 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
65 | startActivity(intent)
66 | }
67 |
68 | inline var AppCompatTextView.strike: Boolean
69 | set(visible) {
70 | paintFlags = if (visible) paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
71 | else paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
72 | }
73 | get() = paintFlags and Paint.STRIKE_THRU_TEXT_FLAG == Paint.STRIKE_THRU_TEXT_FLAG
74 |
75 | fun Context.openCustomizedConfirmDialog(
76 | msg: String,
77 | positiveButtonText: String,
78 | negativeButtonText: String,
79 | onYesClick: () -> Unit,
80 | onNoClick: () -> Unit
81 | ) {
82 | MaterialAlertDialogBuilder(this)
83 | .setMessage(msg)
84 | .setPositiveButton(positiveButtonText) { dialog, _ ->
85 | onYesClick.invoke()
86 | dialog.dismiss()
87 | }
88 | .setNegativeButton(negativeButtonText) { dialog, _ ->
89 | onNoClick.invoke()
90 | dialog.dismiss()
91 | }.show()
92 | }
93 |
94 | // send alpha under from 0.0f to 1.0f.
95 | private const val RGB_MAX_VALUE = 255
96 | fun Context.getAlphaColor(@ColorRes color: Int, alpha: Float): Int {
97 | return ColorUtils.setAlphaComponent(
98 | ContextCompat.getColor(this, color),
99 | RGB_MAX_VALUE.times(alpha).roundToInt()
100 | )
101 | }
102 |
103 | /**
104 | * This showToast fun can be called from context object
105 | */
106 | fun Context.showToast(message: String?) {
107 | Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
108 | }
109 |
110 | enum class ScreenOrientation(val value: Int) {
111 | PORTRAIT(Configuration.ORIENTATION_PORTRAIT),
112 | LANDSCAPE(Configuration.ORIENTATION_LANDSCAPE)
113 | }
114 |
115 | inline val ViewGroup.children: List
116 | get() = (0 until childCount).map { getChildAt(it) }
117 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/FileExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import java.io.ByteArrayOutputStream
4 | import java.io.File
5 | import java.io.FileInputStream
6 | import java.io.FileOutputStream
7 | import java.io.IOException
8 | import java.nio.channels.FileChannel
9 |
10 | fun File.copy(dest: File) {
11 | var fi: FileInputStream? = null
12 | var fo: FileOutputStream? = null
13 | var ic: FileChannel? = null
14 | var oc: FileChannel? = null
15 | try {
16 | if (!dest.exists()) {
17 | dest.createNewFile()
18 | }
19 | fi = FileInputStream(this)
20 | fo = FileOutputStream(dest)
21 | ic = fi.channel
22 | oc = fo.channel
23 | ic.transferTo(0, ic.size(), oc)
24 | } catch (e: IOException) {
25 | e.printStackTrace()
26 | } finally {
27 | fi?.close()
28 | fo?.close()
29 | ic?.close()
30 | oc?.close()
31 | }
32 | }
33 |
34 | fun File.move(dest: File) {
35 | copy(dest)
36 | delete()
37 | }
38 |
39 | fun File.copyDirectory(dest: File) {
40 | if (!dest.exists()) {
41 | dest.mkdirs()
42 | }
43 | val files = listFiles()
44 | files?.forEach {
45 | if (it.isFile) {
46 | it.copy(File("${dest.absolutePath}/${it.name}"))
47 | }
48 | if (it.isDirectory) {
49 | val dirSrc = File("$absolutePath/${it.name}")
50 | val dirDest = File("${dest.absolutePath}/${it.name}")
51 | dirSrc.copyDirectory(dirDest)
52 | }
53 | }
54 | }
55 |
56 | fun File.moveDirectory(dest: File) {
57 | copyDirectory(dest)
58 | deleteAll()
59 | }
60 |
61 | fun File.deleteAll() {
62 | if (isFile && exists()) {
63 | delete()
64 | return
65 | }
66 | if (isDirectory) {
67 | val files = listFiles()
68 | if (files == null || files.isEmpty()) {
69 | delete()
70 | return
71 | }
72 | files.forEach { it.deleteAll() }
73 | delete()
74 | }
75 | }
76 |
77 | private const val ONE_MB = 1024
78 | fun File.toByteArray(): ByteArray {
79 | val bos = ByteArrayOutputStream(this.length().toInt())
80 | val input = FileInputStream(this)
81 | val size = ONE_MB
82 | val buffer = ByteArray(size)
83 | var len = input.read(buffer, 0, size)
84 | while (len != -1) {
85 | bos.write(buffer, 0, len)
86 | len = input.read(buffer, 0, size)
87 | }
88 | input.close()
89 | bos.close()
90 | return bos.toByteArray()
91 | }
92 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/FragmentExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.widget.Toast
4 | import androidx.annotation.StyleRes
5 | import androidx.fragment.app.Fragment
6 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
7 | import com.google.android.material.snackbar.Snackbar
8 |
9 | /**
10 | * This showToast fun can be called from fragment
11 | */
12 | fun Fragment.showToast(message: String?) {
13 | Toast.makeText(this.activity, message, Toast.LENGTH_SHORT).show()
14 | }
15 |
16 | /**
17 | * This showSnackBar fun can be called from fragment
18 | */
19 | fun Fragment.showSnackBar(message: String) {
20 | val mParentView = requireActivity().window.decorView.rootView
21 | if (mParentView != null) {
22 | Snackbar.make(mParentView, message, Snackbar.LENGTH_LONG).show()
23 | }
24 | }
25 |
26 | fun Fragment.openSelectionDialog(
27 | title: String,
28 | arrayOfString: Array,
29 | onPositionSelect: (Int) -> Unit,
30 | @StyleRes style: Int = 0
31 | ) {
32 |
33 | MaterialAlertDialogBuilder(requireContext(), style)
34 | .setTitle(title)
35 | .setItems(arrayOfString) { dialog, which ->
36 | onPositionSelect.invoke(which)
37 | dialog.dismiss()
38 | }.show()
39 | }
40 |
41 | fun Fragment.getScreenOrientation(): ScreenOrientation {
42 | return when (resources.configuration.orientation) {
43 | ScreenOrientation.PORTRAIT.value -> ScreenOrientation.PORTRAIT
44 | ScreenOrientation.LANDSCAPE.value -> ScreenOrientation.LANDSCAPE
45 | else -> ScreenOrientation.PORTRAIT
46 | }
47 | }
48 |
49 | fun Fragment.addFragment(layoutId: Int, fragment: Fragment) {
50 | this.requireFragmentManager().beginTransaction().add(layoutId, fragment).commit()
51 | }
52 |
53 | fun Fragment.addChildFragment(layoutId: Int, fragment: Fragment) {
54 | this.childFragmentManager.beginTransaction().add(layoutId, fragment).commit()
55 | }
56 |
57 | fun Fragment.addFragmentBackStack(layoutId: Int, fragment: Fragment, tag: String) {
58 | this.fragmentManager?.beginTransaction()?.add(layoutId, fragment)?.addToBackStack(tag)
59 | ?.commit()
60 | }
61 |
62 | fun Fragment.replaceFragment(layoutId: Int, fragment: Fragment) {
63 | this.requireFragmentManager().beginTransaction().replace(layoutId, fragment).commit()
64 | }
65 |
66 | fun Fragment.replaceChildFragment(layoutId: Int, fragment: Fragment) {
67 | if (isAdded) {
68 | this.childFragmentManager.beginTransaction().replace(layoutId, fragment)
69 | .commitAllowingStateLoss()
70 | }
71 | }
72 |
73 | fun Fragment.replaceFragmentBackStack(layoutId: Int, fragment: Fragment, tag: String) {
74 | this.requireFragmentManager().beginTransaction().replace(layoutId, fragment).addToBackStack(tag)
75 | .commit()
76 | }
77 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/SpecificViewExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.graphics.Paint
4 | import android.text.method.ReplacementTransformationMethod
5 | import android.widget.RadioButton
6 | import android.widget.RadioGroup
7 | import android.widget.ScrollView
8 | import androidx.appcompat.widget.AppCompatButton
9 | import androidx.appcompat.widget.AppCompatEditText
10 | import androidx.appcompat.widget.AppCompatTextView
11 |
12 | fun AppCompatTextView.underLine() {
13 | paint.flags = paint.flags or Paint.UNDERLINE_TEXT_FLAG
14 | paint.isAntiAlias = true
15 | }
16 |
17 | fun AppCompatTextView.deleteLine() {
18 | paint.flags = paint.flags or Paint.STRIKE_THRU_TEXT_FLAG
19 | paint.isAntiAlias = true
20 | }
21 |
22 | fun AppCompatTextView.bold(isBold: Boolean = true) {
23 | paint.isFakeBoldText = isBold
24 | paint.isAntiAlias = true
25 | }
26 |
27 | var AppCompatEditText.value: String
28 | get() = text.toString()
29 | set(value) = setText(value)
30 |
31 | fun AppCompatEditText.uppercase() {
32 | transformationMethod = object : ReplacementTransformationMethod() {
33 | private val lower = charArrayOf('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
34 | 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z')
35 | private val upper = charArrayOf('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
36 | 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
37 |
38 | override fun getOriginal() = lower
39 |
40 | override fun getReplacement() = upper
41 | }
42 | }
43 |
44 | fun AppCompatEditText.lowercase() {
45 | transformationMethod = object : ReplacementTransformationMethod() {
46 | private val lower = charArrayOf('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
47 | 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z')
48 | private val upper = charArrayOf('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
49 | 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
50 |
51 | override fun getOriginal() = upper
52 |
53 | override fun getReplacement() = lower
54 | }
55 | }
56 |
57 | var RadioGroup.checkedIndex: Int
58 | get() = (0 until childCount).firstOrNull { (getChildAt(it) as RadioButton).isChecked } ?: -1
59 | set(value) {
60 | if (value !in 0 until childCount) {
61 | children.map { it as RadioButton }.filter { it.isChecked }
62 | .forEach { it.isChecked = false }
63 | } else {
64 | (getChildAt(value) as RadioButton).isChecked = true
65 | }
66 | }
67 |
68 | private const val HALF_ALPHA = 0.5f
69 | private const val NO_ALPHA = 1f
70 | fun AppCompatButton.disableAlpha() {
71 | this.isClickable = false
72 | this.isEnabled = false
73 | this.alpha = HALF_ALPHA
74 | }
75 |
76 | fun AppCompatButton.enableWithDefaultAlpha() {
77 | this.isClickable = true
78 | this.isEnabled = true
79 | this.alpha = NO_ALPHA
80 | }
81 |
82 | fun AppCompatTextView.disableAlpha() {
83 | this.isClickable = false
84 | this.isEnabled = false
85 | this.alpha = HALF_ALPHA
86 | }
87 |
88 | fun AppCompatTextView.enableWithDefaultAlpha() {
89 | this.isClickable = true
90 | this.isEnabled = true
91 | this.alpha = NO_ALPHA
92 | }
93 |
94 | fun AppCompatEditText.disableAlpha() {
95 | alpha = HALF_ALPHA
96 | isFocusable = false
97 | isFocusableInTouchMode = false
98 | }
99 |
100 | fun AppCompatEditText.enableWithDefaultAlpha() {
101 | alpha = NO_ALPHA
102 | isFocusable = true
103 | isFocusableInTouchMode = true
104 | }
105 |
106 | fun ScrollView.scrollToBottom() {
107 | val lastChild = getChildAt(childCount - 1)
108 | val bottom = lastChild.bottom + paddingBottom
109 | val delta = bottom - (scrollY + height)
110 | smoothScrollBy(0, delta)
111 | }
112 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/StringExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.os.Build
4 | import android.text.Editable
5 | import android.text.Html
6 | import android.text.Spanned
7 | import android.text.TextUtils
8 | import java.util.regex.Pattern
9 |
10 | fun String?.isValid(): Boolean {
11 | return this != null && this.isNotEmpty() && this.isNotBlank()
12 | }
13 |
14 | fun String?.isNotValid(): Boolean {
15 | return !this.isValid()
16 | }
17 |
18 | fun String.space(string: String?): String {
19 | return this.plus(" ${string ?: ""}")
20 | }
21 |
22 | fun String.newLineWithBullet(): String {
23 | return "".plus("\n \n").plus("\u25cf ").plus(this)
24 | }
25 |
26 | fun String.toBoldHtml(): String {
27 | return "".plus(this).plus("")
28 | }
29 |
30 | fun String.toSpannedHtml(): Spanned {
31 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
32 | Html.fromHtml(this, Html.FROM_HTML_MODE_COMPACT)
33 | } else {
34 | Html.fromHtml(this)
35 | }
36 | }
37 |
38 | fun String.toFormattedInt(): String {
39 | return if (this.contains(".00")) {
40 | this.toDouble().toInt().toString()
41 | } else
42 | this.toDouble().toString()
43 | }
44 |
45 | private val emailRegex = Pattern.compile(
46 | "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
47 | "\\@" +
48 | "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
49 | "(" +
50 | "\\." +
51 | "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
52 | ")+"
53 | )
54 |
55 | fun String.isEmail(): Boolean {
56 | return this.isValid() && emailRegex.matcher(this.trimEnd().trimStart()).matches()
57 | }
58 |
59 | private const val MIN_LENGTH_PHONE = 7
60 | private const val MAX_LENGTH_PHONE = 13
61 | fun String.isPhoneNumber(): Boolean {
62 | val minLength = MIN_LENGTH_PHONE
63 | val maxLength = MAX_LENGTH_PHONE
64 | return this.isValid() && IntRange(minLength, maxLength).contains(this.trimEnd().trimStart().length)
65 | }
66 |
67 | fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this)
68 |
69 | fun String.toHtmlString(): Spanned {
70 | return Html.fromHtml(this)
71 | }
72 |
73 | fun String?.fromHtmlToPlainText(): String? {
74 |
75 | return if (this != null) {
76 | val text = this.replace("\n", "
")
77 | val spanned = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
78 | Html.fromHtml(text, Html.FROM_HTML_MODE_COMPACT)
79 | } else {
80 | Html.fromHtml(text)
81 | }
82 |
83 | val chars = CharArray(spanned.length)
84 | TextUtils.getChars(spanned, 0, spanned.length, chars, 0)
85 | return String(chars)
86 | } else {
87 | null
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/happysingh/core/ext/WebViewExt.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core.ext
2 |
3 | import android.webkit.WebChromeClient
4 | import android.webkit.WebResourceError
5 | import android.webkit.WebResourceRequest
6 | import android.webkit.WebView
7 | import android.webkit.WebViewClient
8 |
9 | /**
10 | * returns lambda if [WebView] is successfully loaded.
11 | */
12 | private const val MAX_PROGRESS = 100
13 | fun WebView.doOnPageLoad(onWebPageLoad: () -> Unit) {
14 | webChromeClient = object : WebChromeClient() {
15 |
16 | override fun onProgressChanged(view: WebView?, newProgress: Int) {
17 | super.onProgressChanged(view, newProgress)
18 | if (progress == MAX_PROGRESS) {
19 | onWebPageLoad.invoke()
20 | }
21 | }
22 | }
23 | }
24 |
25 | /**
26 | * returns lambda if [WebView] is gets an error while loading loaded.
27 | */
28 | fun WebView.doOnPageLoadError(onError: () -> Unit) {
29 | webViewClient = object : WebViewClient() {
30 |
31 | override fun onReceivedError(
32 | view: WebView?,
33 | request: WebResourceRequest?,
34 | error: WebResourceError?
35 | ) {
36 | super.onReceivedError(view, request, error)
37 | onError.invoke()
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 | #FFEBEE
9 | #FFCDD2
10 | #EF9A9A
11 | #E57373
12 | #EF5350
13 | #F44336
14 | #E53935
15 | #D32F2F
16 | #C62828
17 | #B71C1C
18 | #FF8A80
19 | #FF5252
20 | #FF1744
21 | #D50000
22 |
23 |
24 | #FCE4EC
25 | #F8BBD0
26 | #F48FB1
27 | #F06292
28 | #EC407A
29 | #E91E63
30 | #D81B60
31 | #C2185B
32 | #AD1457
33 | #880E4F
34 | #FF80AB
35 | #FF4081
36 | #F50057
37 | #C51162
38 |
39 |
40 | #F3E5F5
41 | #E1BEE7
42 | #CE93D8
43 | #BA68C8
44 | #AB47BC
45 | #9C27B0
46 | #8E24AA
47 | #7B1FA2
48 | #6A1B9A
49 | #4A148C
50 | #EA80FC
51 | #E040FB
52 | #D500F9
53 | #AA00FF
54 |
55 |
56 | #EDE7F6
57 | #D1C4E9
58 | #B39DDB
59 | #9575CD
60 | #7E57C2
61 | #673AB7
62 | #5E35B1
63 | #512DA8
64 | #4527A0
65 | #311B92
66 | #B388FF
67 | #7C4DFF
68 | #651FFF
69 | #6200EA
70 |
71 |
72 | #E8EAF6
73 | #C5CAE9
74 | #9FA8DA
75 | #7986CB
76 | #5C6BC0
77 | #3F51B5
78 | #3949AB
79 | #303F9F
80 | #283593
81 | #1A237E
82 | #8C9EFF
83 | #536DFE
84 | #3D5AFE
85 | #304FFE
86 |
87 |
88 | #E3F2FD
89 | #BBDEFB
90 | #90CAF9
91 | #64B5F6
92 | #42A5F5
93 | #2196F3
94 | #1E88E5
95 | #1976D2
96 | #1565C0
97 | #0D47A1
98 | #82B1FF
99 | #448AFF
100 | #2979FF
101 | #2962FF
102 |
103 |
104 | #E1F5FE
105 | #B3E5FC
106 | #81D4fA
107 | #4fC3F7
108 | #29B6FC
109 | #03A9F4
110 | #039BE5
111 | #0288D1
112 | #0277BD
113 | #01579B
114 | #80D8FF
115 | #40C4FF
116 | #00B0FF
117 | #0091EA
118 |
119 |
120 | #E0F7FA
121 | #B2EBF2
122 | #80DEEA
123 | #4DD0E1
124 | #26C6DA
125 | #00BCD4
126 | #00ACC1
127 | #0097A7
128 | #00838F
129 | #006064
130 | #84FFFF
131 | #18FFFF
132 | #00E5FF
133 | #00B8D4
134 |
135 |
136 | #E0F2F1
137 | #B2DFDB
138 | #80CBC4
139 | #4DB6AC
140 | #26A69A
141 | #009688
142 | #00897B
143 | #00796B
144 | #00695C
145 | #004D40
146 | #A7FFEB
147 | #64FFDA
148 | #1DE9B6
149 | #00BFA5
150 |
151 |
152 | #E8F5E9
153 | #C8E6C9
154 | #A5D6A7
155 | #81C784
156 | #66BB6A
157 | #4CAF50
158 | #43A047
159 | #388E3C
160 | #2E7D32
161 | #1B5E20
162 | #B9F6CA
163 | #69F0AE
164 | #00E676
165 | #00C853
166 |
167 |
168 | #F1F8E9
169 | #DCEDC8
170 | #C5E1A5
171 | #AED581
172 | #9CCC65
173 | #8BC34A
174 | #7CB342
175 | #689F38
176 | #558B2F
177 | #33691E
178 | #CCFF90
179 | #B2FF59
180 | #76FF03
181 | #64DD17
182 |
183 |
184 | #F9FBE7
185 | #F0F4C3
186 | #E6EE9C
187 | #DCE775
188 | #D4E157
189 | #CDDC39
190 | #C0CA33
191 | #A4B42B
192 | #9E9D24
193 | #827717
194 | #F4FF81
195 | #EEFF41
196 | #C6FF00
197 | #AEEA00
198 |
199 |
200 | #FFFDE7
201 | #FFF9C4
202 | #FFF590
203 | #FFF176
204 | #FFEE58
205 | #FFEB3B
206 | #FDD835
207 | #FBC02D
208 | #F9A825
209 | #F57F17
210 | #FFFF82
211 | #FFFF00
212 | #FFEA00
213 | #FFD600
214 |
215 |
216 | #FFF8E1
217 | #FFECB3
218 | #FFE082
219 | #FFD54F
220 | #FFCA28
221 | #FFC107
222 | #FFB300
223 | #FFA000
224 | #FF8F00
225 | #FF6F00
226 | #FFE57F
227 | #FFD740
228 | #FFC400
229 | #FFAB00
230 |
231 |
232 | #FFF3E0
233 | #FFE0B2
234 | #FFCC80
235 | #FFB74D
236 | #FFA726
237 | #FF9800
238 | #FB8C00
239 | #F57C00
240 | #EF6C00
241 | #E65100
242 | #FFD180
243 | #FFAB40
244 | #FF9100
245 | #FF6D00
246 |
247 |
248 | #FBE9A7
249 | #FFCCBC
250 | #FFAB91
251 | #FF8A65
252 | #FF7043
253 | #FF5722
254 | #F4511E
255 | #E64A19
256 | #D84315
257 | #BF360C
258 | #FF9E80
259 | #FF6E40
260 | #FF3D00
261 | #DD2600
262 |
263 |
264 | #EFEBE9
265 | #D7CCC8
266 | #BCAAA4
267 | #A1887F
268 | #8D6E63
269 | #795548
270 | #6D4C41
271 | #5D4037
272 | #4E342E
273 | #3E2723
274 |
275 |
276 | #FAFAFA
277 | #F5F5F5
278 | #EEEEEE
279 | #E0E0E0
280 | #BDBDBD
281 | #9E9E9E
282 | #757575
283 | #616161
284 | #424242
285 | #212121
286 |
287 |
288 | #ECEFF1
289 | #CFD8DC
290 | #B0BBC5
291 | #90A4AE
292 | #78909C
293 | #607D8B
294 | #546E7A
295 | #455A64
296 | #37474F
297 | #263238
298 |
299 |
300 | #ffffff
301 | #121212
302 | #000000
303 | #00FFFFFF
304 | #BCC0DC
305 |
306 |
307 |
--------------------------------------------------------------------------------
/core/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Yes
4 | No
5 |
--------------------------------------------------------------------------------
/core/src/test/java/dev/happysingh/core/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package dev.happysingh.core
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happysingh23828/android-github-repo-template/0c79546786520c4ef05b1b22334f81797ebc3d4b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Feb 07 11:51:42 IST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':core'
2 | include ':app'
3 | rootProject.name = "Android-Github-Repo-Template"
--------------------------------------------------------------------------------