├── .gitignore
├── .idea
├── dictionaries
│ └── gilgoldzweig.xml
├── encodings.xml
├── gradle.xml
├── kannotator.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── goldzweigapps
│ │ └── com
│ │ └── extentions
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── goldzweigapps
│ │ │ └── com
│ │ │ └── extentions
│ │ │ └── MainActivity.kt
│ └── res
│ │ ├── 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_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── goldzweigapps
│ └── com
│ └── extentions
│ └── ExampleUnitTest.kt
├── build.gradle
├── core
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── goldzweigapps
│ │ │ └── com
│ │ │ └── core
│ │ │ ├── bundles
│ │ │ ├── Bundlify.kt
│ │ │ ├── BundlifyDelegate.kt
│ │ │ └── BundlifyType.kt
│ │ │ ├── collections
│ │ │ └── CollectionExtensions.kt
│ │ │ ├── colors
│ │ │ └── ColorGenerator.kt
│ │ │ ├── context
│ │ │ └── ContextExtension.kt
│ │ │ ├── database
│ │ │ └── SQLDatabaseExtensions.kt
│ │ │ ├── exceptions
│ │ │ ├── InitializeException.kt
│ │ │ ├── UnsupportedTypeException.kt
│ │ │ └── WrongThreadException.kt
│ │ │ ├── notifications
│ │ │ ├── Notification.kt
│ │ │ └── NotificationManager.kt
│ │ │ ├── other
│ │ │ └── LazyInitializeObject.kt
│ │ │ ├── permissions
│ │ │ └── PermissionsExtensions.kt
│ │ │ ├── preferences
│ │ │ ├── GlobalSharedPreferences.kt
│ │ │ └── PreferencesProperty.kt
│ │ │ ├── resources
│ │ │ └── ResourcesExtensions.kt
│ │ │ ├── streams
│ │ │ └── StreamsExtensions.kt
│ │ │ ├── support
│ │ │ ├── GenericRecyclerAdapter.kt
│ │ │ └── GenericRecyclerViewAdapterExtensions.kt
│ │ │ ├── threads
│ │ │ └── ThreadsExtensions.kt
│ │ │ └── views
│ │ │ └── ViewsExtensions.kt
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── goldzweigapps
│ └── com
│ └── core
│ └── ExampleUnitTest.java
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jackson
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── goldzweigapps
│ │ │ └── com
│ │ │ └── jackson
│ │ │ └── jacksonExtensions.kt
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── goldzweigapps
│ └── com
│ └── jackson
│ └── JacksonUnitTest.kt
├── projectFilesBackup
└── .idea
│ └── workspace.xml
├── reactive
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── goldzweigapps
│ │ └── com
│ │ └── reactive
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── goldzweigapps
│ │ │ └── com
│ │ │ └── reactive
│ │ │ └── ReactiveExtensions.kt
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── goldzweigapps
│ └── com
│ └── reactive
│ └── ExampleUnitTest.java
├── settings.gradle
└── timber
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
├── androidTest
└── java
│ └── goldzweigapps
│ └── com
│ └── timber
│ └── ExampleInstrumentedTest.java
├── main
├── AndroidManifest.xml
├── java
│ └── goldzweigapps
│ │ └── com
│ │ └── timber
│ │ └── Timber.kt
└── res
│ └── values
│ └── strings.xml
└── test
└── java
└── goldzweigapps
└── com
└── timber
└── ExampleUnitTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/dictionaries/gilgoldzweig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | bundlify
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/kannotator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 1.8
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kotlinify
2 |
3 | 
4 |
5 |
6 | Kotlinify is a suite of extension and classes for easier daily android development in kotlin.
7 | I've created it after my own needs and i decided i should publish it and save time for others.
8 |
9 | The library contanis 4 modules:
10 | - Core extensions.
11 | - Reactive extensions.
12 | - Jackson extensions.
13 | - Custom edition of JakeWharton/timber
14 | ## Installiton
15 | In your app's build.gradle add the following.
16 | ```
17 | repositories {
18 | maven {url "https://jitpack.io" }
19 | }
20 |
21 | dependencies {
22 | You can add each module seperatly
23 |
24 | //All of the modules
25 | implementation 'com.github.GilGoldzweig:kotlinify:latestVersion'
26 | // Core module
27 | implementation 'com.github.GilGoldzweig.kotlinify:core:latestVersion'
28 | // Reactive module
29 | implementation 'com.github.GilGoldzweig.kotlinify:reactive:latestVersion'
30 | // Jackson module
31 | implementation 'com.github.GilGoldzweig.kotlinify:jackson:latestVersion'
32 | // Timber module
33 | implementation 'com.github.GilGoldzweig.kotlinify:timber:latestVersion'
34 | }
35 | ```
36 |
37 | # Core
38 | ##### The core module provides the following classes and extensions.
39 |
40 |
41 | ### Bundlify
42 | Let's you create bundles in a simple way and with operators.
43 | ```
44 | val bundle = bundle {
45 | //put key(String), value(Any)
46 |
47 | //String
48 | put("key", "value")
49 |
50 | //Int
51 | put("key", 1)
52 |
53 | //Long
54 | put("key", 1L)
55 |
56 | //Float
57 | put("key", 1.5131F)
58 |
59 | //parcelable
60 | put("key", Parcelable) //Some parcelable object
61 |
62 | //parcelable array
63 | put("key", Array()) //Some parcelable Array
64 |
65 | //parcelable arrayList
66 | put("key", ArrayList())//Some parcelable ArrayList
67 |
68 | "key" += 5
69 | this += "keyPair" to 6L
70 |
71 | //remove
72 | remove("keyToRemove")
73 |
74 | this - ""
75 |
76 | }
77 | "key" in bundle
78 |
79 | ```
80 | ### GlobalSharedPreferences
81 | GlobalSharedPrefrences a SharedPreferences object that let you use it anywhere without the direct access to context. The class also contains an easy usage
82 | ```
83 | First initialize it in your application class
84 | //You don't have to provide a name if nothing is placed it will use the default value
85 | GlobalSharedPreferences.initialize(application, "sharedPreferencesName")
86 | pref {
87 | //put key(String), value(Any)
88 |
89 | //String
90 | put("key", "value")
91 |
92 | //Int
93 | put("key", 1)
94 |
95 | //Long
96 | put("key", 1L)
97 |
98 | //Float
99 | put("key", 1.5131F)
100 |
101 | "key" += 5
102 | this += "keyPair" to 6L
103 |
104 | //remove
105 | remove("keyToRemove")
106 | this - ""
107 |
108 | } //not need to apply inside pref
109 |
110 | "key" in GlobalSharedPreferences // return's Boolean
111 |
112 | (GlobalSharedPreferences += "keyPair" to 6L).apply()
113 |
114 | (GlobalSharedPreferences - "key").apply()
115 | ```
116 | ### Fragment
117 | An easier way to create a fragment using a dsl extension of fragment
118 | ```
119 | fragment(layoutRes = R.layout.fragment_test) {
120 | //every field in fragment is accessable from here
121 | arguments = bundle // we use the bundle from before to insert the arguments (optinal, you can use a normal Bundle)
122 | var name: TextView // declaring your views
123 | onViewCreated { view, context, savedInstanceState ->
124 | name = view.findViewById(R.id.text) //accessing the views
125 | }
126 | } //return's a ready to use fragment
127 | ```
128 | ### Notification
129 | //You can use but it did not get tested so i'm not writing description
130 | //will be added soon
131 |
132 | ### GenericRecyclerAdapter
133 | An abstract extension of RecyclerView.Adapter that reduces the creating time of a RecyclerView.
134 | In additon you receive a lot of extension function to make the adapter work simieler to List so by extending the class you receive a lot of bounses
135 | ```
136 | The adapter
137 | class CustomRecyclerAdapter(context: Context, // Require context to make it easily accessible
138 | listOfObjects: ArrayList = ArrayList() //Put your list of objects
139 | ):
140 | GenericRecyclerAdapter(context,
141 | ArrayList()
142 | //the list of objects could by empty and it will use the default value
143 | , R.layout.item_recycler_test // the item's layout currently one one view type supported
144 | ) {
145 |
146 | override fun View.onBind(currentElementPosition: Int,
147 | currentElement: String, // the current element with the type provided above in this example a String
148 | holder: GenericViewHolder) {
149 | //because of the extension of View i can just call
150 | // findViewById and that's it you don't need to call holder.view.findViewById
151 | }
152 | }
153 | extension given
154 |
155 | val customRecyclerAdapter = CustomRecyclerAdapter(this, ArrayList())
156 |
157 | customRecyclerAdapter - "" //removing item and notifying the adapter if you are on uiThread
158 |
159 | customRecyclerAdapter - 2 //removing item and notifying the adapter if you are on uiThread
160 |
161 | customRecyclerAdapter + "" //adding item and notifying the adapter if you are on uiThread
162 |
163 | customRecyclerAdapter.add("",5)
164 |
165 | customRecyclerAdapter[""] //getItem by object
166 |
167 | customRecyclerAdapter[12] //getItem by position
168 |
169 | customRecyclerAdapter - (1..4) //removing position range and notifying the adapter if you are on uiThread
170 |
171 | customRecyclerAdapter - (listOf("", "")) //removing list of objects and notifying the adapter if you are on uiThread
172 |
173 | customRecyclerAdapter.setItem(5, "gg")
174 |
175 | customRecyclerAdapter.clear()
176 |
177 | customRecyclerAdapter.count()
178 |
179 | customRecyclerAdapter.setItems(listOf("", "", "", "", "")) //replace the current list and notifying the adapter if you are on uiThread
180 |
181 | customRecyclerAdapter.isEmpty()
182 |
183 | customRecyclerAdapter.isNotEmpty()
184 | ```
185 | ### threads
186 | ```
187 | //single function to run in background
188 | runInBackground {
189 |
190 | }
191 |
192 | //multiple functions to run in background
193 | runInBackground({}, {}, {})
194 |
195 | //function to run on ui thread
196 | runOnUI {
197 |
198 | }
199 |
200 | //run's a task after 2 secounds on UI thread
201 | runAfter(millis = 2000, thread = RunnableThread.UI) {
202 |
203 | }
204 |
205 | //run's a task after 2 secounds in background
206 | runAfter(millis = 2000, thread = RunnableThread.BACKGROUND) {
207 |
208 | }
209 |
210 | //run's a task after 2 secounds on the current thread
211 | runAfter(millis = 2000, thread = RunnableThread.CURRENT) {
212 |
213 | }
214 |
215 | //run's a task after 2 secounds
216 | runAfter(millis = 2000) {
217 |
218 | }
219 |
220 | isUiThread() //Boolean is the current thread is UI
221 | ```
222 | ### views
223 | ```
224 | val group = LinearLayout(this)//LinearLayout as example can be any ViewGroup
225 |
226 | group += TextView(this)
227 | group += TextView(this)
228 | group += TextView(this)
229 | group += TextView(this)
230 | "in" in TextView(this)
231 | group -= TextView(this)
232 |
233 | group[0]
234 | for (view in group.iterator()) {
235 |
236 | }
237 | group.first()
238 | group.last()
239 | group.forEach { }
240 | group.forEachIndexed { i, view -> }
241 | group.forEachRevered { }
242 | group.forEachReveredIndexed { i, view -> }
243 |
244 | group.inflate(R.layout.some_layout)
245 | this.inflate(R.layout.some_layout, false, group) //this = context
246 |
247 | View(this).onClick {
248 |
249 | }
250 | View(this).onLongClick {
251 |
252 | }
253 |
254 | View(this).hide()
255 | View(this).hide()
256 | View(this).show()
257 | View(this).invisible()
258 | View(this).toggleVisibility()
259 | View(this).isVisible()
260 | ```
261 | ### collections
262 | ```
263 | val testMap = mapOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9)
264 | val testSet = setOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9)
265 | val testList = listOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9)
266 | val testArrayList = ArrayList()
267 |
268 | testMap.isNullOrEmpty()
269 | testMap.isNotNullOrEmpty()
270 |
271 | testSet.isNullOrEmpty()
272 | testSet.isNotNullOrEmpty()
273 |
274 | testArrayList.isNullOrEmpty()
275 | testArrayList.isNotNullOrEmpty()
276 | testArrayList addIfNotExist 5
277 | testArrayList removeIfExist 5
278 |
279 |
280 | testList.isNullOrEmpty()
281 | testList.isNotNullOrEmpty()
282 | testList / 3 //returns a map of page number and the amount of items given in this case 3
283 | testList.random() //returns a random element from the list
284 |
285 | ```
286 | ### resourses
287 | Provides two extensions
288 | ```
289 | 15.toDp() //return's the number as a convertion from px to dp
290 | 15.toPx()//return's the number as a convertion from dp to px
291 | ```
292 | ### permission
293 | Provides few functions
294 | ```
295 | isVersionAbove(26) // boolean
296 | isVersionAbove(14) // boolean same as above but with diffrent version
297 |
298 | isMarshmallowOrAbove() //boolean is current version is at least Marshmallow(23)
299 | isLollipopOrAbove() //boolean is current version is at least Lollipop(21)
300 |
301 | Context.isGranted("StringPermission") // boolean checks if the permission is granted or not
302 |
303 | ```
304 | ### ColorGenerator
305 | A class with 2 lists of colors one normal colors and one material design colors
306 | the class let's you get all the colors or a random color
307 | ```
308 | ColorGenerator.DEFAULT_COLOR_LIST
309 | ColorGenerator.instance.randomColor
310 |
311 | ColorGenerator.MATERIAL_COLOR_LIST
312 | ColorGenerator.materialInstance.randomColor
313 | ```
314 |
315 |
316 | # Reactive
317 | ##### The Reactive module provides the following extensions.
318 | Provides two extension functions to most if not all reactive types
319 | ```
320 | /**
321 | * observe on main thread
322 | * subscribe on new thread
323 | * unsubsidised on error and on complete and removes the need to handle it afterwards
324 | * @usage
325 | * someObservable //or any other reactive type
326 | * .runSafeOnMain()
327 | * .subscribe({}, {])
328 | */
329 | fun Observable.runSafeOnMain(): Observable =
330 | observeOn(mainThread)
331 | .subscribeOn(newThread)
332 | .doOnError({ unsubscribeOn(newThread) })
333 | .doOnComplete { unsubscribeOn(newThread) }
334 |
335 | /**
336 | * observe on io thread
337 | * subscribe on new thread
338 | * unsubsidised on error and on complete and removes the need to handle it afterwards
339 | * @usage
340 | * someObservable //or any other reactive type
341 | * .runSafeOnIO()
342 | * .subscribe({}, {])
343 | */
344 | fun Observable.runSafeOnIO(): Observable =
345 | observeOn(ioThread)
346 | .subscribeOn(newThread)
347 | .doOnError({ unsubscribeOn(newThread) })
348 | .doOnComplete { unsubscribeOn(newThread) }
349 | ```
350 |
351 | # Jackson
352 | ##### The jackson module provides a few extension functions and an annotation
353 | ```
354 | val locationObject = LocationObject("Tel-Aviv", arrayOf(5.152155, 1512.5120))
355 |
356 | val jsonString = "{\"locationText\":\"Tel-Aviv\",\"locationCoordinates\":[5.152155,1512.512]}"
357 |
358 | locationObject.toJson() //{"locationText":"Tel-Aviv","locationCoordinates":[5.152155,1512.512]}
359 |
360 |
361 | locationObject.toPrettyJson() /** {
362 | "locationText": "Tel-Aviv",
363 | "locationCoordinates": [
364 | 5.152155,
365 | 1512.512
366 | ]
367 | }*/
368 |
369 | jsonString.fromJson() // A new LocationObject
370 |
371 | LocationObject
372 |
373 | @JsonIgnoreUnknown //A new annotation to make it easier to use jackson instad of @JsonIgnoreProperties(ignoreUnknown = true)
374 | data class LocationObject(val locationText: String, val locationCoordinates: Array)
375 | ```
376 |
377 | # Timber
378 | ##### The timber module provides the following class.
379 | Adds a possibilty to print any object using timber a very small change but saves a lot of annying toString()
380 | ```
381 | You can use it like so or just put the object
382 | Timber.d(someObject.toString())
383 | Timber.d(5.toString())
384 | Timber.d(someBoolean.toString())
385 |
386 | //you can just do like so
387 | Timber.d(someObject)
388 | Timber.d(5)
389 | Timber.d(someBoolean)
390 | someObject.d()// no need to call Timber
391 | someOtherObject.e()// no need to call Timber
392 | someOtherObject.i()// no need to call Timber
393 | someOtherObject.wtf()// no need to call Timber
394 | someOtherObject.w()// no need to call Timber
395 | ```
396 |
397 | License
398 | ----
399 |
400 | MIT
401 |
402 |
403 | **Free Software, Hell Yeah!**
404 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | apply plugin: 'kotlin-android-extensions'
6 |
7 | android {
8 | compileSdkVersion 27
9 | buildToolsVersion '27.0.3'
10 | defaultConfig {
11 | applicationId "goldzweigapps.com.extentions"
12 | minSdkVersion 15
13 | targetSdkVersion 27
14 | versionCode 1
15 | versionName "1.0"
16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
17 | }
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | }
25 | //repositories {
26 | //// maven { url 'https://jitpack.io' }
27 | // maven {
28 | // url "https://dl.bintray.com/gilgoldzweig/maven"
29 | // }
30 | //}
31 |
32 | dependencies {
33 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
34 | implementation "com.android.support:appcompat-v7:$rootProject.versions.support"
35 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
36 | testImplementation 'junit:junit:4.12'
37 | // compileProject('timber')
38 | // compile 'com.github.gilgoldzweig.kotlinify:core:1.1'
39 | // compile 'com.github.GilGoldzweig.kotlinify:timber:1.0.1'
40 | // compile 'com.github.GilGoldzweig.kotlinify:reactive:1.0.0'
41 | // compile 'com.github.GilGoldzweig.kotlinify:jackson:1.0.0'
42 | implementation project(':timber')
43 | implementation project(':core')
44 | // compile project(':core')
45 | }
46 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/gilgoldzweig/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/goldzweigapps/com/extentions/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.extentions
2 |
3 |
4 | import org.junit.Assert.assertEquals
5 | import org.junit.Test
6 | import org.junit.runner.RunWith
7 |
8 | /**
9 | * Instrumented test, which will execute on an Android device.
10 | *
11 | * See [testing documentation](http://d.android.com/tools/testing).
12 | */
13 | @RunWith(AndroidJUnit4::class)
14 | class ExampleInstrumentedTest {
15 | @Test
16 | fun useAppContext() {
17 | // Context of the app under test.
18 | val appContext = InstrumentationRegistry.getTargetContext()
19 | assertEquals("goldzweigapps.com.extentions", appContext.packageName)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/goldzweigapps/com/extentions/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.extentions
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.AppCompatActivity
5 | import goldzweigapps.com.core.threads.RunnableThread
6 | import goldzweigapps.com.timber.Timber
7 |
8 | class MainActivity : AppCompatActivity() {
9 |
10 |
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setContentView(R.layout.activity_main)
14 | Timber.plant(Timber.DebugTree())
15 |
16 |
17 | // findViewById<>()
18 | // Timber.plant(Timber.DebugTree())
19 | // runAfter(2000, RunnableThread.BACKGROUND) {
20 | // "run a function in background".d()
21 | // if (isUiThread()) "Something is not working".e()
22 | // }
23 | // runAfter(3000, RunnableThread.UI) {
24 | // "run a function on ui".d()
25 | // if (isUiThread()) "Something is working".d()
26 | // }
27 | // notificationManager {
28 | // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
29 | // showSingle(15,notification("channel", 15) {
30 | // title = "testTitle"
31 | // contentText = "contextTextTest"
32 | // smallIconRes = R.mipmap.ic_launcher_round
33 | // intent = PendingIntent.getActivity(this@MainActivity,
34 | // 5,
35 | // Intent(),
36 | // PendingIntent.FLAG_UPDATE_CURRENT)
37 | // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
38 | // action {
39 | // title = "customTitle"
40 | // icon = Icon.createWithResource(this@MainActivity, R.mipmap.ic_launcher_round)
41 | // intent = PendingIntent.getActivity(this@MainActivity,
42 | // 5,
43 | // Intent(),
44 | // PendingIntent.FLAG_UPDATE_CURRENT)
45 | // }
46 | // }
47 | // })
48 | // }
49 | // }
50 | //
51 | // runInBackground {
52 | // if (isUiThread()) "Something is not working".e()
53 | // runOnUiThread {
54 | // if (isUiThread()) "Something is working".d()
55 | // }
56 | // }
57 |
58 |
59 | // locationObject.toJson() //{"locationText":"Tel-Aviv","locationCoordinates":[5.152155,1512.512]}
60 | // locationObject.toPrettyJson()
61 | /**{
62 | "locationText": "Tel-Aviv",
63 | "locationCoordinates": [
64 | 5.152155,
65 | 1512.512
66 | ]
67 | }*/
68 | // jsonString.fromJson() // A new LocationObject
69 | //
70 | //
71 | // //single function
72 | // runInBackground {
73 | //
74 | // }
75 | //
76 | // //multiple functions
77 | // runInBackground({}, {}, {})
78 | // runOnUI {
79 | //
80 | // }
81 | // runAfter(2000) {
82 | //
83 | // }
84 | // runAfter(millis = 2000, thread = RunnableThread.BACKGROUND) {
85 | //
86 | // }
87 | // runAfter(millis = 2000, thread = RunnableThread.CURRENT) {
88 | //
89 | // }
90 | // runAfter(millis = 2000) {
91 | //
92 | // }
93 | //
94 | // isUiThread()
95 | // GlobalSharedPreferences.initialize(application, "")
96 | //
97 | //
98 | // pref {
99 | // //put key(String), value(Any)
100 | // //String
101 | // put("key", "value")
102 | // //Int
103 | // put("key", 1)
104 | // //Long
105 | // put("key", 1L)
106 | // //Float
107 | // put("key", 1.5131F)
108 | //
109 | // "key" += 5
110 | // this += "keyPair" to 6L
111 | //
112 | // //remove
113 | // remove("keyToRemove")
114 | // this - ""
115 | //
116 | // }
117 | // "key" in GlobalSharedPreferences
118 | // (GlobalSharedPreferences - "").apply()
119 | //
120 | // val bundle = bundle {
121 | // //put key(String), value(Any)
122 | // //String
123 | // put("key", "value")
124 | // //Int
125 | // put("key", 1)
126 | // //Long
127 | // put("key", 1L)
128 | // //Float
129 | // put("key", 1.5131F)
130 | // //parcelable
131 | // put("key", Parcelable) //Some parcelable object
132 | // //parcelable array
133 | // put("key", Array()) //Some parcelable Array
134 | // //parcelable arrayList
135 | // put("key", ArrayList())//Some parcelable ArrayList
136 | //
137 | // "key" += 5
138 | // this += "keyPair" to 6L
139 | //
140 | // //remove
141 | // remove("keyToRemove")
142 | // this - ""
143 | //
144 | // }
145 | // "key" in bundle
146 | //
147 | // val re = Recy(this)
148 | // re + UserKT()
149 | // re - UserKT()
150 | // for (count in 0..100) {
151 | //
152 | // }
153 |
154 | // fragment(layoutRes = R.layout.activity_main) {
155 | //
156 | // arguments = bundle
157 | // var name: TextView
158 | // onViewCreated { view, context, savedInstanceState ->
159 | // name = view.findViewById(R.id.text)
160 | //
161 | // }
162 | // }
163 | // 5.toDp()
164 | //
165 | // val group = LinearLayout(this)
166 | // group += TextView(this)
167 | // group += TextView(this)
168 | // group += TextView(this)
169 | // group += TextView(this)
170 | // "in" in TextView(this)
171 | // group -= TextView(this)
172 | // group[0]
173 | // for (view in group.iterator()) {
174 | //
175 | // }
176 | // group.first()
177 | // group.last()
178 | // group.forEach { }
179 | // group.forEachIndexed { i, view -> }
180 | // group.forEachRevered { }
181 | // group.forEachReveredIndexed { i, view -> }
182 | //
183 | // group.inflate(R.layout.some_layout)
184 | // this.inflate(R.layout.some_layout, false, group)
185 | //
186 | // View(this).onClick {
187 | //
188 | // }
189 | // View(this).onLongClick {
190 | //
191 | // }
192 | // View(this).hide()
193 | // View(this).hide()
194 | // View(this).show()
195 | // View(this).invisible()
196 | // View(this).toggleVisibility()
197 | // View(this).isVisible()
198 | //
199 | //
200 | //
201 | // isVersionAbove(23)
202 | //
203 | // val customRecyclerAdapter = CustomRecyclerAdapter(this, ArrayList())
204 | // customRecyclerAdapter - "" //removing item and notifying the adapter if you are on uiThread
205 | // customRecyclerAdapter - 2 //removing item and notifying the adapter if you are on uiThread
206 | // customRecyclerAdapter + "" //adding item and notifying the adapter if you are on uiThread
207 | // customRecyclerAdapter.add("",5)
208 | // customRecyclerAdapter[""] //getItem by object
209 | // customRecyclerAdapter[12] //getItem by position
210 | // customRecyclerAdapter - (1..4) //removing position range and notifying the adapter if you are on uiThread
211 | // customRecyclerAdapter - (listOf("", "")) //removing list of objects and notifying the adapter if you are on uiThread
212 | // customRecyclerAdapter.setItem(5, "gg")
213 | // customRecyclerAdapter.clear()
214 | // customRecyclerAdapter.count()
215 | // customRecyclerAdapter.setItems(listOf("", "", "", "", "")) //replace the current list and notifying the adapter if you are on uiThread
216 | // customRecyclerAdapter.isEmpty()
217 | // customRecyclerAdapter.isNotEmpty()
218 | //
219 | // ColorGenerator.DEFAULT_COLOR_LIST
220 | // ColorGenerator.instance.randomColor
221 | //
222 | // ColorGenerator.MATERIAL_COLOR_LIST
223 | // ColorGenerator.materialInstance.randomColor
224 | //
225 | // val testMap = mapOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9)
226 | // val testSet = setOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9)
227 | // val testList = listOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9)
228 | // val testArrayList = ArrayList()
229 | //
230 | // testMap.isNullOrEmpty()
231 | // testMap.isNotNullOrEmpty()
232 | //
233 | // testSet.isNullOrEmpty()
234 | // testSet.isNotNullOrEmpty()
235 | //
236 | // testArrayList.isNullOrEmpty()
237 | // testArrayList.isNotNullOrEmpty()
238 | // testArrayList addIfNotExist 5
239 | // testArrayList removeIfExist 5
240 | //
241 | //
242 | // testList.isNullOrEmpty()
243 | // testList.isNotNullOrEmpty()
244 | // testList / 3 //returns a map of page number and the amount of items given in this case 3
245 | // testList.random() //returns a random element from the list
246 | //
247 |
248 |
249 | }
250 | }
251 | class NewRunnableThread: RunnableThread {
252 | override fun run(vararg functions: () -> Unit) {
253 | for (func in functions) {
254 | Thread({ func.invoke() }).start()
255 | }
256 | }
257 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
17 |
22 |
27 |
32 |
37 |
42 |
47 |
52 |
57 |
62 |
67 |
72 |
77 |
82 |
87 |
92 |
97 |
102 |
107 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Extentions
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/goldzweigapps/com/extentions/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.extentions
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.2.30'
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.0'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
13 | classpath 'com.novoda:bintray-release:0.8.0'
14 | // classpath 'com.novoda:bintray-release:0.5.0'
15 | // NOTE: Do not place your application dependencies here; they belong
16 | // in the individual module build.gradle files
17 | }
18 | }
19 |
20 |
21 | allprojects {
22 | repositories {
23 | google()
24 | jcenter()
25 | // maven { url 'https://dl.bintray.com/kotlin/kotlin-eap-1.2' }
26 | mavenCentral()
27 | }
28 | tasks.withType(Javadoc).all {
29 | enabled = false
30 | }
31 | }
32 |
33 | task clean(type: Delete) {
34 | delete rootProject.buildDir
35 | }
36 | //tasks.withType(Javadoc).all {
37 | // enabled = false
38 | //}
39 | ext {
40 | versions = [
41 | support : '27.1.1',
42 | mockito : "2.8.9",
43 | junit : "4.12"
44 | ]
45 | userOrg = 'gilgoldzweig'
46 | publishVersion = '1.3.1'
47 | groupId = 'com.github.gilgoldzweig.kotlinify'
48 | website = 'https://github.com/gilgoldzweig/Kotlinify'
49 | }
50 |
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/core/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 | apply plugin: 'com.novoda.bintray-release'
5 |
6 | group = 'com.github.gilgoldzweig'
7 |
8 | publish {
9 | userOrg = "$rootProject.userOrg"
10 | groupId = "$rootProject.groupId"
11 | publishVersion = "$rootProject.publishVersion"
12 | website = "$rootProject.website"
13 | artifactId = 'core'
14 | desc = 'The core module provides the following classes and extensions.'
15 | }
16 |
17 | android {
18 | compileSdkVersion 27
19 | buildToolsVersion "27.0.3"
20 | defaultConfig {
21 | minSdkVersion 14
22 | targetSdkVersion 27
23 | versionCode 1
24 | versionName "1.0"
25 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
26 |
27 | }
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 | }
35 | dependencies {
36 | implementation fileTree(dir: 'libs', include: ['*.jar'])
37 |
38 | testImplementation 'junit:junit:4.12'
39 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
40 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
41 |
42 | implementation "com.android.support:appcompat-v7:$rootProject.versions.support"
43 | implementation "com.android.support:design:$rootProject.versions.support"
44 | implementation "com.android.support:recyclerview-v7:$rootProject.versions.support"
45 |
46 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
47 | implementation "org.jetbrains.kotlin:kotlin-reflect:1.2.30"
48 | }
--------------------------------------------------------------------------------
/core/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/gilgoldzweig/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/bundles/Bundlify.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.bundles
2 |
3 | import android.os.Bundle
4 | import android.os.Parcelable
5 | import kotlin.reflect.KClass
6 |
7 | /**
8 | * Created by gilgoldzweig on 12/09/2017.
9 | */
10 | @Suppress("unused")
11 | class Bundlify {
12 | var bundle = Bundle()
13 |
14 | //region get
15 | fun getAll() = bundle
16 |
17 | fun String.getStringArray(): Array =
18 | bundle.getStringArray(this)
19 |
20 | fun String.getStringArrayList(): ArrayList =
21 | bundle.getStringArrayList(this)
22 |
23 | fun String.getInt() = bundle.getInt(this)
24 |
25 | fun String.getLong() = bundle.getLong(this)
26 |
27 | fun String.getFloat() = bundle.getFloat(this)
28 |
29 | fun String.getBoolean() = bundle.getBoolean(this)
30 |
31 | fun String.getString(): String = bundle.getString(this)
32 |
33 | fun String.getParcelable(): T = bundle.getParcelable(this)
34 | fun String.getParcelableArray() = bundle.getParcelableArray(this) as Array
35 | fun String.getParcelableArrayList(): ArrayList =
36 | bundle.getParcelableArrayList(this)
37 |
38 | fun get(type: KClass, key: String) =
39 | when (type) {
40 | String::class ->
41 | key.getString()
42 | Int::class ->
43 | key.getInt()
44 | Long::class ->
45 | key.getLong()
46 | Boolean::class ->
47 | key.getBoolean()
48 | Float::class ->
49 | key.getFloat()
50 | Parcelable::class ->
51 | key.getParcelable()
52 | Array::class ->
53 | key.getParcelableArray()
54 | Array::class ->
55 | key.getStringArray()
56 | else -> throw ClassCastException("Bundlify only support bundle types")
57 | } as T
58 |
59 | //endregion get
60 |
61 | //region contains
62 | operator fun contains(key: String) = bundle.containsKey(key)
63 | //endregion contains
64 |
65 | //region put
66 | fun put(key: String, value: String): Bundlify {
67 | bundle.putString(key, value)
68 | return this
69 | }
70 |
71 | fun put(key: String, value: Int): Bundlify {
72 | bundle.putInt(key, value)
73 | return this
74 | }
75 |
76 | fun put(key: String, value: Long): Bundlify {
77 | bundle.putLong(key, value)
78 | return this
79 | }
80 |
81 | fun put(key: String, value: Boolean): Bundlify {
82 | bundle.putBoolean(key, value)
83 | return this
84 | }
85 |
86 | fun put(key: String, value: Float): Bundlify {
87 | bundle.putFloat(key, value)
88 | return this
89 | }
90 |
91 | fun put(key: String, value: Parcelable): Bundlify {
92 | bundle.putParcelable(key, value)
93 | return this
94 | }
95 |
96 | fun put(key: String, value: Array): Bundlify {
97 | bundle.putParcelableArray(key, value)
98 | return this
99 | }
100 |
101 | fun put(key: String, value: ArrayList): Bundlify {
102 | bundle.putParcelableArrayList(key, value)
103 | return this
104 | }
105 |
106 | fun put(bundlifyType: BundlifyType): Bundlify {
107 | put(bundlifyType.key, bundlifyType.value)
108 | return this
109 | }
110 |
111 | fun put(key: String, value: Any) {
112 | when (value) {
113 | is String ->
114 | put(key, value)
115 | is Int ->
116 | put(key, value)
117 | is Long ->
118 | put(key, value)
119 | is Boolean ->
120 | put(key, value)
121 | is Float ->
122 | put(key, value)
123 | is Parcelable ->
124 | put(key, value)
125 | is Array<*> ->
126 | put(key, value as Array)
127 | is ArrayList<*> ->
128 | put(key, value as ArrayList)
129 | }
130 | }
131 | private fun putUnit(key: String, value: Any) {
132 | put(key, value)
133 | return Unit
134 | }
135 |
136 | operator fun String.plusAssign(value: Any) = putUnit(this, value)
137 |
138 | operator fun plusAssign(keyValuePair: Pair) =
139 | putUnit(keyValuePair.first, keyValuePair.second)
140 |
141 | operator fun plus(keyValuePair: Pair) = plusAssign(keyValuePair)
142 |
143 | //endregion put
144 |
145 | //region remove
146 | fun remove(key: String): Bundlify {
147 | bundle.remove(key)
148 | return this
149 | }
150 |
151 | operator fun minus(key: String) = remove(key)
152 | //endregion remove
153 | }
154 |
155 | inline fun bundle(bundle: Bundlify.() -> Unit) = Bundlify().apply(bundle).bundle
156 | operator fun Bundle.contains(key: String) = this.containsKey(key)
157 |
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/bundles/BundlifyDelegate.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.bundles
2 |
3 | import kotlin.properties.ReadWriteProperty
4 | import kotlin.reflect.KProperty
5 |
6 | /**
7 | * Created by gilgoldzweig on 16/10/2017.
8 | */
9 | class BundlifyDelegate(val bundlify: Bundlify): ReadWriteProperty {
10 |
11 | override fun getValue(thisRef: Any, property: KProperty<*>) =
12 | bundlify.get(thisRef::class, property.name) as T
13 |
14 | override fun setValue(thisRef: Any, property: KProperty<*>, value: T) =
15 | bundlify.put(property.name, value)
16 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/bundles/BundlifyType.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.bundles
2 |
3 | /**
4 | * Created by gilgoldzweig on 05/11/2017.
5 | */
6 | interface BundlifyType {
7 | var key: String
8 | var value: E
9 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/collections/CollectionExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.collections
2 |
3 | import java.util.*
4 | import kotlin.collections.HashMap
5 |
6 | /**
7 | * Created by gilgoldzweig on 04/09/2017.
8 | */
9 |
10 | private val random = Random()
11 |
12 | //region collections
13 | fun Collection?.isNullOrEmpty(): Boolean = this == null || this.isEmpty()
14 | fun Collection?.isNotNullOrEmpty() = !isNullOrEmpty()
15 | //endregion collections
16 |
17 | //region maps
18 | fun Map?.isNullOrEmpty() = this == null || this.isEmpty()
19 | fun Map?.isNotNullOrEmpty() = !isNullOrEmpty()
20 | //endregion maps
21 |
22 | //region sets
23 | fun Set?.isNullOrEmpty() = this == null || this.isEmpty()
24 | fun Set?.isNotNullOrEmpty() = !isNullOrEmpty()
25 | //endregion sets
26 |
27 | //region lists
28 | fun List?.isNullOrEmpty() = this == null || this.isEmpty()
29 |
30 | fun List?.isNotNullOrEmpty(): Boolean = !isNullOrEmpty()
31 |
32 | fun List.random() = this[random.nextInt(size)]
33 |
34 | operator fun List.div(amount: Int): Map> {
35 | val map = HashMap>()
36 | var startIndexOfCattedList = 0
37 | var page = 0
38 | for (indexOfList in 0 until this.size) {
39 | if ((indexOfList + 1) % amount == 0) {
40 | if (startIndexOfCattedList == 0) {
41 | map.put(page++, subList(startIndexOfCattedList, indexOfList + 1))
42 | } else {
43 | map.put(page++, subList(startIndexOfCattedList, indexOfList))
44 | }
45 | startIndexOfCattedList = indexOfList
46 | }
47 | }
48 | return map
49 | }
50 |
51 | operator fun List.get(e: E) = indexOf(e)
52 | //endregion lists
53 |
54 | //region array lists
55 | operator fun ArrayList.plusAssign(obj: E) = add(size, obj)
56 | infix fun ArrayList.addIfNotExist(obj: E) = if (!contains(obj)) add(obj) else false
57 | infix fun ArrayList.removeIfExist(obj: E) = if (contains(obj)) remove(obj) else false
58 | //endregion array lists
59 |
60 | //region Iterable
61 | fun E.asIterable(hasNext: E.() -> Boolean, next: E.() -> T) =
62 | object : Iterable {
63 | override fun iterator(): Iterator {
64 | return object : Iterator {
65 | override fun hasNext() = hasNext(this@asIterable)
66 | override fun next() = next(this@asIterable)
67 | }
68 | }
69 | }
70 |
71 | fun E.asIterable(hasNext: Boolean, next: (it: E) -> T) =
72 | object : Iterable {
73 | override fun iterator(): Iterator {
74 | return object : Iterator {
75 | override fun hasNext() = hasNext
76 | override fun next() = next(this@asIterable)
77 | }
78 | }
79 | }
80 |
81 | fun E.asIterableIndexed(hasNext: E.(index: Int) -> Boolean,
82 | next: E.(index: Int) -> T,
83 | changeOnNext: (index: Int) -> Int): Iterable {
84 | var index = 0
85 | return object : Iterable {
86 | override fun iterator(): Iterator {
87 | return object : Iterator {
88 | override fun hasNext() = this@asIterableIndexed.hasNext(index)
89 | override fun next(): T {
90 | val element = this@asIterableIndexed.next(index)
91 | index = changeOnNext(index)
92 | return element
93 | }
94 | }
95 | }
96 | }
97 | }
98 |
99 | fun E.asIterableIndexed(hasNext: Boolean,
100 | next: E.(index: Int) -> T,
101 | changeOnNext: (index: Int) -> Int) =
102 | asIterableIndexed({ hasNext }, next, changeOnNext)
103 |
104 | operator fun Iterable.get(e: E) = firstOrNull { it == e }
105 |
106 | operator fun Iterable.get(position: Int) =
107 | filterIndexed { index, _ -> index == position}.firstOrNull()
108 |
109 | //endregion Iterable
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/colors/ColorGenerator.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.colors
2 |
3 | import java.util.*
4 |
5 | class ColorGenerator private constructor(private val mColors: List) {
6 | private val mRandom: Random = Random(System.currentTimeMillis())
7 |
8 | val randomColor: Int
9 | get() = mColors[mRandom.nextInt(mColors.size)]
10 |
11 | @Suppress("unused")
12 | fun getColor(key: Any) =
13 | mColors[Math.abs(key.hashCode()) % mColors.size]
14 |
15 |
16 | companion object {
17 |
18 | private var DEFAULT: ColorGenerator
19 |
20 | private var MATERIAL: ColorGenerator
21 |
22 | var MATERIAL_COLOR_LIST: List = listOf(
23 | 0xffe57373.toInt(),
24 | 0xfff06292.toInt(),
25 | 0xffba68c8.toInt(),
26 | 0xff9575cd.toInt(),
27 | 0xff7986cb.toInt(),
28 | 0xff64b5f6.toInt(),
29 | 0xff4fc3f7.toInt(),
30 | 0xff4dd0e1.toInt(),
31 | 0xff4db6ac.toInt(),
32 | 0xff81c784.toInt(),
33 | 0xffaed581.toInt(),
34 | 0xffff8a65.toInt(),
35 | 0xffd4e157.toInt(),
36 | 0xffffd54f.toInt(),
37 | 0xffffb74d.toInt(),
38 | 0xffa1887f.toInt(),
39 | 0xff90a4ae.toInt()
40 | )
41 | var DEFAULT_COLOR_LIST: List = listOf(
42 | 0xfff16364.toInt(),
43 | 0xfff58559.toInt(),
44 | 0xfff9a43e.toInt(),
45 | 0xffe4c62e.toInt(),
46 | 0xff67bf74.toInt(),
47 | 0xff59a2be.toInt(),
48 | 0xff2093cd.toInt(),
49 | 0xffad62a7.toInt(),
50 | 0xff805781.toInt())
51 |
52 | init {
53 | DEFAULT = create(DEFAULT_COLOR_LIST)
54 | MATERIAL = create(MATERIAL_COLOR_LIST)
55 | }
56 |
57 | fun create(colorList: List) = ColorGenerator(colorList)
58 | val materialInstance by lazy { MATERIAL }
59 | val instance by lazy { DEFAULT }
60 | }
61 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/context/ContextExtension.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.context
2 |
3 | /**
4 | * Created by pablisco/ContextExtensions.kt
5 | * Found in medium article which contains good code and a lot of added value so thank him
6 | * His GitHub gist: https://gist.github.com/pablisco/64775eba5afa982f4cfb2362aa7bd9b4
7 | * The Medium article: https://medium.com/@pablisco/fluent-intents-8006ec63130
8 | */
9 | import android.app.Activity
10 | import android.app.Service
11 | import android.content.ComponentName
12 | import android.content.Context
13 | import android.content.Intent
14 | import android.content.Intent.EXTRA_SUBJECT
15 | import android.content.Intent.EXTRA_TEXT
16 | import android.net.Uri
17 | import kotlin.properties.ReadWriteProperty
18 | import kotlin.reflect.KClass
19 | import kotlin.reflect.KProperty
20 |
21 | fun Context.startActivity(f: Intent.() -> Unit): Unit =
22 | Intent().apply(f).run(this::startActivity)
23 |
24 | inline fun Context.start(noinline intent: Intent.() -> Unit = {}) =
25 | startActivity {
26 | component = componentFor(T::class.java)
27 | intent(this)
28 | }
29 |
30 | fun Context.start(action: String, func: Intent.() -> Unit = {}) =
31 | startActivity {
32 | this.action = action
33 | func(this)
34 | }
35 |
36 | fun Context.chooseActivity(title: String = "", f: Intent.() -> Unit) =
37 | startActivity(Intent.createChooser(Intent().apply(f), title))
38 |
39 | fun Activity.startForResult(requestCode: Int, f: Intent.() -> Unit): Unit =
40 | Intent().apply(f).run { startActivityForResult(this, requestCode) }
41 |
42 |
43 | fun Context.startService(f: Intent.() -> Unit): ComponentName =
44 | Intent().apply(f).run(this::startService)
45 |
46 | inline fun Context.launch(noinline f: Intent.() -> Unit = {}) =
47 | startService(T::class.java, f)
48 |
49 | fun Context.startService(type: Class, f: Intent.() -> Unit): ComponentName =
50 | Intent().apply(f).run(this::startService)
51 |
52 |
53 | fun Context.send(f: Intent.() -> Unit) =
54 | Intent().apply(f).run(this::sendBroadcast)
55 |
56 | fun Context.send(action: String, f: Intent.() -> Unit = {}) =
57 | Intent(action).apply(f).run(this::sendBroadcast)
58 |
59 | fun Context.send(action: String, permission: String, f: Intent.() -> Unit = {}) =
60 | Intent(action).apply(f).run { sendBroadcast(this, permission) }
61 |
62 |
63 | fun Context.componentFor(targetType: KClass<*>): ComponentName =
64 | componentFor(targetType.java)
65 |
66 | fun Context.componentFor(targetType: Class<*>) = ComponentName(this, targetType)
67 |
68 | inline var Intent.url: String
69 | get() = dataString
70 | set(value) {
71 | data = Uri.parse(value)
72 | }
73 |
74 | inline var Intent.subject
75 | get() = getStringExtra(EXTRA_SUBJECT)
76 | set(value) {
77 | putExtra(EXTRA_SUBJECT, value)
78 | }
79 |
80 | var Intent.text by ExtraProperty.string(EXTRA_TEXT)
81 |
82 | sealed class ExtraProperty : ReadWriteProperty {
83 |
84 | companion object {
85 | fun string(name: String) = StringProperty(name)
86 | fun int(name: String) = IntProperty(name)
87 | }
88 |
89 | class StringProperty internal constructor(private val name: String) : ExtraProperty() {
90 | override fun getValue(thisRef: Intent, property: KProperty<*>): String =
91 | thisRef.getStringExtra(name)
92 |
93 | override fun setValue(thisRef: Intent, property: KProperty<*>, value: String) {
94 | thisRef.putExtra(name, value)
95 | }
96 | }
97 |
98 | class IntProperty internal constructor(private val name: String) : ExtraProperty() {
99 | override fun getValue(thisRef: Intent, property: KProperty<*>) =
100 | thisRef.getIntExtra(name, -1)
101 |
102 | override fun setValue(thisRef: Intent, property: KProperty<*>, value: Int) {
103 | thisRef.putExtra(name, value)
104 | }
105 | }
106 |
107 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/database/SQLDatabaseExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.database
2 |
3 | import android.database.sqlite.SQLiteDatabase
4 |
5 | /**
6 | * Created by gilgoldzweig on 08/09/2017.
7 | */
8 | inline fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
9 | beginTransaction()
10 | try {
11 | func()
12 | setTransactionSuccessful()
13 | } finally {
14 | endTransaction()
15 | }
16 |
17 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/exceptions/InitializeException.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.exceptions
2 |
3 | /**
4 | * Created by gilgoldzweig on 17/09/2017.
5 | * custom exception to handle cases where user did not initialized the wanted class
6 | * @param className the name of the class in order to print the right class that caused the exception
7 | * @param initializeFunctionName the name of the initialize function in order to explain to user how to initialize
8 | */
9 | class InitializeException(className: String,
10 | initializeFunctionName: String
11 | ) : RuntimeException("$className must be initialize,\ncall $initializeFunctionName in order to initialize")
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/exceptions/UnsupportedTypeException.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.exceptions
2 |
3 | class UnsupportedTypeException(classType: String) :
4 | RuntimeException("SharedPreferences does not support $classType")
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/exceptions/WrongThreadException.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.exceptions
2 |
3 | /**
4 | * Created by gilgoldzweig on 22/01/2018.
5 | */
6 |
7 | open class WrongThreadException(override val message: String = ""): Exception()
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/notifications/Notification.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.notifications
2 |
3 | import android.app.NotificationChannel
4 | import android.app.NotificationManager
5 | import android.app.PendingIntent
6 | import android.app.RemoteInput
7 | import android.content.Context
8 | import android.graphics.Bitmap
9 | import android.graphics.drawable.Icon
10 | import android.os.Build
11 | import android.os.Bundle
12 | import android.support.annotation.DrawableRes
13 | import android.support.annotation.RequiresApi
14 |
15 |
16 | /**
17 | * Created by gilgoldzweig on 04/09/2017.
18 | */
19 | class Notification(context: Context, channelId: String) :
20 | android.app.Notification.Builder(context) {
21 | var title: String = ""
22 | set(value) {
23 | setContentTitle(value)
24 | }
25 |
26 | var contentText: String = ""
27 | set(value) {
28 | setContentText(value)
29 | }
30 |
31 | var smallIconRes: Int? = null
32 | @DrawableRes
33 | set(value) {
34 | if (value != null) setSmallIcon(value)
35 | }
36 |
37 | var largeIcon: Bitmap? = null
38 | set(value) {
39 | if (value != null) setLargeIcon(value)
40 | }
41 |
42 | var autoCancel: Boolean = true
43 | set(value) {
44 | setAutoCancel(value)
45 | }
46 | var intent: PendingIntent? = null
47 | set(value) {
48 | if (value != null) setContentIntent(value)
49 | }
50 |
51 | val actions = ArrayList()
52 |
53 |
54 |
55 | @RequiresApi(Build.VERSION_CODES.O)
56 | fun channel(id: String = NotificationChannel.DEFAULT_CHANNEL_ID,
57 | name: String = "default channel name",
58 | importance: Int = NotificationManager.IMPORTANCE_DEFAULT,
59 | channel: NotificationChannel.() -> Unit): NotificationChannel {
60 | val notificationChannel = NotificationChannel(id, name, importance)
61 | .apply(channel)
62 | setChannelId(id)
63 | return notificationChannel
64 | }
65 |
66 |
67 | @RequiresApi(Build.VERSION_CODES.N)
68 | inline fun action(init: Action.() -> Unit): android.app.Notification.Action {
69 | val action = Action().apply(init)
70 | val actionBuilder = with(action) {
71 | android.app.Notification.Action.Builder(icon, title, intent)
72 | .setAllowGeneratedReplies(allowGeneratedReplies)
73 | .addRemoteInput(remoteInput)
74 | }
75 | for (extra in action.extras) actionBuilder.addExtras(extra)
76 | val notificationAction = actionBuilder.build()
77 | actions + notificationAction
78 | setActions(*actions.toTypedArray())
79 | return notificationAction
80 | }
81 | }
82 |
83 | @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
84 | inline fun Context.notification(channelId: String, notificationId: Int,
85 | notification: Notification.() -> Unit): android.app.Notification =
86 | Notification(this, channelId)
87 | .apply(notification)
88 | .build()
89 |
90 | @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
91 | inline fun goldzweigapps.com.core.notifications.NotificationManager.notification(channelId: String, notificationId: Int,
92 | notificationFunc: Notification.() -> Unit): Notification {
93 | val notification = Notification(context, channelId)
94 | .apply(notificationFunc)
95 | notifications + notificationId to notification
96 | return notification
97 | }
98 |
99 |
100 |
101 |
102 |
103 | class Action(var title: CharSequence = "",
104 | var icon: Icon? = null,
105 | var intent: PendingIntent? = null,
106 | var allowGeneratedReplies: Boolean = false,
107 | var remoteInput: RemoteInput? = null,
108 | var extras: Array = emptyArray())
109 |
110 |
111 |
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/notifications/NotificationManager.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.notifications
2 |
3 | import android.app.NotificationChannel
4 | import android.app.NotificationChannelGroup
5 | import android.content.Context
6 | import android.os.Build
7 | import android.support.annotation.RequiresApi
8 | import android.app.NotificationManager as AppNotificationMangaer
9 |
10 | /**
11 | * Created by gilgoldzweig on 13/09/2017.
12 | */
13 | class NotificationManager(val context: Context) {
14 | val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE)
15 | as AppNotificationMangaer
16 | val notificationChannels = ArrayList()
17 | val notificationChannelGroups = ArrayList()
18 | val notifications = ArrayList>()
19 |
20 |
21 | @RequiresApi(Build.VERSION_CODES.O)
22 | fun channel(id: String = NotificationChannel.DEFAULT_CHANNEL_ID,
23 | name: String = "default channel name",
24 | importance: Int = AppNotificationMangaer.IMPORTANCE_DEFAULT,
25 | channel: NotificationChannel.() -> Unit): NotificationChannel {
26 | val notificationChannel = NotificationChannel(id, name, importance)
27 | .apply(channel)
28 | notificationChannels + notificationChannel
29 | notificationManager.createNotificationChannels(notificationChannels)
30 | return notificationChannel
31 | }
32 |
33 | @RequiresApi(Build.VERSION_CODES.O)
34 | inline fun channelGroup(id: String = NotificationChannel.DEFAULT_CHANNEL_ID,
35 | name: String = "default channel name",
36 | channel: NotificationChannelGroup.() -> Unit): NotificationChannelGroup {
37 | val notificationsChannelGroup = NotificationChannelGroup(id, name)
38 | .apply(channel)
39 | notificationChannelGroups + notificationsChannelGroup
40 | notificationManager.createNotificationChannelGroups(notificationChannelGroups)
41 | return notificationsChannelGroup
42 | }
43 |
44 | @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
45 | fun showSingle(notificationId: Int, notification: Notification) {
46 | notificationManager.notify(notificationId, notification.build())
47 | }
48 |
49 | @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
50 | fun showAll() {
51 | notifications.forEach { showSingle(it.first, it.second) }
52 | }
53 | }
54 |
55 | inline fun Context.notificationManager(manager: NotificationManager.() -> Unit) =
56 | NotificationManager(this)
57 | .apply(manager)
58 |
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/other/LazyInitializeObject.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.other
2 |
3 | /**
4 | * Created by gilgoldzweig on 05/11/2017.
5 | */
6 | open class LazyInitializeObject {
7 | protected lateinit var type: T
8 |
9 | open fun initialize(type: T) {
10 | try {
11 | this.type
12 | } catch (ex: UninitializedPropertyAccessException) {
13 | this.type = type
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/permissions/PermissionsExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.permissions
2 |
3 | import android.annotation.SuppressLint
4 | import android.annotation.TargetApi
5 | import android.content.Context
6 | import android.content.pm.PackageManager
7 | import android.os.Build
8 | import android.support.v4.content.ContextCompat
9 |
10 | /**
11 | * Created by gilgoldzweig on 04/09/2017.
12 | */
13 | @SuppressLint("NewApi")
14 | fun isVersionAbove(version: Int) = Build.VERSION.SDK_INT >= version
15 |
16 | @TargetApi(Build.VERSION_CODES.M)
17 | fun isMarshmallowOrAbove() = isVersionAbove(Build.VERSION_CODES.M)
18 | fun isLollipopOrAbove() = isVersionAbove(Build.VERSION_CODES.LOLLIPOP)
19 |
20 | infix fun Context.isGranted(permission: String) =
21 | ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
22 |
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/preferences/GlobalSharedPreferences.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.preferences
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import android.content.SharedPreferences
6 |
7 | @Suppress("unused")
8 | object GlobalSharedPreferences {
9 | private lateinit var sharedPreferences: SharedPreferences
10 | private var initialized = false
11 |
12 | /**
13 | * @param application Global context in order use everywhere
14 | * without the need for context every time
15 | * @param sharedPreferencesName custom name for SharedPreferences
16 | * @return instance of the GlobalSharedPreferences
17 | */
18 | fun initialize(application: Application, sharedPreferencesName: String = "DefaultSharedPreferences"):
19 | GlobalSharedPreferences {
20 | sharedPreferences = application.getSharedPreferences(sharedPreferencesName, Context.MODE_PRIVATE)
21 | initialized = true
22 | return this
23 | }
24 |
25 |
26 | //region editor
27 | private val edit: SharedPreferences.Editor by lazy { requiredOrThrow(sharedPreferences.edit()) }
28 | //endregion editor
29 |
30 | //region get
31 | fun getAll(): Map = requiredOrThrow(sharedPreferences.all)
32 |
33 | fun getInt(key: String, defaultValue: Int) =
34 | requiredOrThrow(sharedPreferences.getInt(key, defaultValue))
35 |
36 | fun getLong(key: String, defaultValue: Long) =
37 | requiredOrThrow(sharedPreferences.getLong(key, defaultValue))
38 |
39 | fun getFloat(key: String, defaultValue: Float) =
40 | requiredOrThrow(sharedPreferences.getFloat(key, defaultValue))
41 |
42 | fun getBoolean(key: String, defaultValue: Boolean) =
43 | requiredOrThrow(sharedPreferences.getBoolean(key, defaultValue))
44 |
45 | fun getString(key: String, defaultValue: String): String =
46 | requiredOrThrow(sharedPreferences.getString(key, defaultValue))
47 |
48 | fun getStringSet(key: String, defaultValue: Set): MutableSet? =
49 | requiredOrThrow(sharedPreferences.getStringSet(key, defaultValue))
50 |
51 | infix fun String.forStringSet(defaultValue: Set): MutableSet? =
52 | requiredOrThrow(sharedPreferences.getStringSet(this, defaultValue))
53 |
54 | infix fun String.forInt(defaultValue: Int) =
55 | requiredOrThrow(sharedPreferences.getInt(this, defaultValue))
56 |
57 | infix fun String.forLong(defaultValue: Long) =
58 | requiredOrThrow(sharedPreferences.getLong(this, defaultValue))
59 |
60 | infix fun String.forFloat(defaultValue: Float) =
61 | requiredOrThrow(sharedPreferences.getFloat(this, defaultValue))
62 |
63 | infix fun String.forBoolean(defaultValue: Boolean) =
64 | requiredOrThrow(sharedPreferences.getBoolean(this, defaultValue))
65 |
66 | infix fun String.forString(defaultValue: String): String =
67 | requiredOrThrow(sharedPreferences.getString(this, defaultValue))
68 |
69 | fun get(key: String, defaultValue: T) =
70 | try {
71 | when (defaultValue) {
72 | is String ->
73 | getString(key, defaultValue)
74 | is Int ->
75 | getInt(key, defaultValue)
76 | is Long ->
77 | getLong(key, defaultValue)
78 | is Boolean ->
79 | getBoolean(key, defaultValue)
80 | is Float ->
81 | getFloat(key, defaultValue)
82 | is Set<*> -> {
83 | getStringSet(key, defaultValue as Set)
84 | }
85 | else -> {
86 | throw ClassCastException("GlobalSharedPreferences Only support SharedPreferences types\n type ${defaultValue::class}")
87 | }
88 | } as T
89 | } catch (ex: ClassCastException) {
90 | throw Throwable("""
91 | Exception while performing get from shared preferences
92 | key: $key
93 | default value: $defaultValue
94 | exception: ${ex.message}
95 | ${ex.stackTrace}
96 | """.trimIndent())
97 | }
98 |
99 |
100 | //endregion get
101 |
102 | //region contains
103 | operator fun contains(key: String) = requiredOrThrow(sharedPreferences.contains(key))
104 | //endregion contains
105 |
106 | //region put
107 | fun put(key: String, value: String) {
108 | edit.putString(key, value).commit()
109 | }
110 |
111 | fun put(key: String, value: Int) = also { edit.putInt(key, value).commit() }
112 |
113 | fun put(key: String, value: Long) = also { edit.putLong(key, value).commit() }
114 |
115 | fun put(key: String, value: Boolean) = also { edit.putBoolean(key, value).commit() }
116 |
117 | fun put(key: String, value: Float) = also { edit.putFloat(key, value).commit() }
118 |
119 | fun put(key: String, value: Set) = also { edit.putStringSet(key, value).commit() }
120 |
121 | fun put(key: String, value: Any) =
122 | also {
123 | when (value) {
124 | is String ->
125 | put(key, value)
126 | is Int ->
127 | put(key, value)
128 | is Long ->
129 | put(key, value)
130 | is Boolean ->
131 | put(key, value)
132 | is Float ->
133 | put(key, value)
134 | is Set<*> ->
135 | put(key, value.map { it.toString() }.toSet())
136 | }
137 | }
138 |
139 | private fun putUnit(key: String, value: Any) {
140 | put(key, value)
141 | }
142 |
143 | operator fun String.plusAssign(value: Any) = putUnit(this, value)
144 |
145 | operator fun plusAssign(keyValuePair: Pair) =
146 | putUnit(keyValuePair.first, keyValuePair.second)
147 |
148 | operator fun plus(keyValuePair: Pair) =
149 | put(keyValuePair.first, keyValuePair.second)
150 |
151 | //endregion put
152 |
153 | //region remove
154 | fun remove(key: String) = also { edit.remove(key).commit() }
155 |
156 | operator fun minus(key: String) = remove(key)
157 | //endregion remove
158 |
159 | //region commit/apply
160 | fun commit() = edit.commit()
161 |
162 | fun apply() = edit.apply()
163 | //endregion commit/apply
164 |
165 | /**
166 | * @param returnIfInitialized object to be returned if class is initialized
167 | * @throws InitializeException
168 | */
169 | @Throws(UninitializedPropertyAccessException::class)
170 | private fun requiredOrThrow(returnIfInitialized: T) = if (initialized) {
171 | returnIfInitialized
172 | } else {
173 | throw UninitializedPropertyAccessException("GlobalSharedPreferences")
174 | }
175 |
176 | }
177 |
178 | inline fun pref(sharedPreferences: GlobalSharedPreferences.() -> Unit) = with(GlobalSharedPreferences) {
179 | also {
180 | sharedPreferences()
181 | apply()
182 | }
183 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/preferences/PreferencesProperty.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.preferences
2 |
3 | import goldzweigapps.com.core.threads.RunnableThread
4 | import goldzweigapps.com.core.threads.RunnableThreads
5 | import kotlin.properties.ReadWriteProperty
6 | import kotlin.reflect.KProperty
7 |
8 | class PreferencesProperty internal constructor(private val defaultValue: T,
9 | private val key: String = "",
10 | private val runnableThread: RunnableThread):
11 | ReadWriteProperty {
12 |
13 | private val pref = GlobalSharedPreferences
14 |
15 | override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
16 | val prefsKey = if (key.isEmpty()) property.name else key
17 | when (runnableThread) {
18 |
19 | RunnableThreads.BACKGROUND ->
20 | pref.put(prefsKey, value).apply()
21 |
22 | RunnableThreads.CURRENT ->
23 | pref.put(prefsKey, value)
24 |
25 | else ->
26 | runnableThread.run({ pref.put(prefsKey, value).commit() })
27 | }
28 | }
29 |
30 | override fun getValue(thisRef: Any, property: KProperty<*>) =
31 | pref.get(if (key.isEmpty()) property.name else key, defaultValue)
32 |
33 | }
34 | fun preferences(defaultValue: T,
35 | key: String = "",
36 | thread: RunnableThread = RunnableThreads.CURRENT) =
37 | PreferencesProperty(defaultValue, key, thread)
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/resources/ResourcesExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.resources
2 |
3 | import android.content.Context
4 | import android.content.res.Resources
5 | import android.support.annotation.ColorRes
6 | import android.support.annotation.DrawableRes
7 | import android.support.v4.content.ContextCompat
8 |
9 | /**
10 | * Created by gilgoldzweig on 04/09/2017.
11 | */
12 |
13 | fun Int.dpToPx() = (this * Resources.getSystem().displayMetrics.density).toInt()
14 |
15 | fun Int.PxToDp() = (this / Resources.getSystem().displayMetrics.density).toInt()
16 |
17 | fun Context.getDrawable(@DrawableRes drawableRes: Int) =
18 | ContextCompat.getDrawable(this, drawableRes)
19 |
20 | fun Context.color(@ColorRes drawableRes: Int) =
21 | ContextCompat.getColor(this, drawableRes)
22 |
23 |
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/streams/StreamsExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.streams
2 |
3 | import java.io.InputStream
4 | import java.util.*
5 |
6 | /**
7 | * Created by gilgoldzweig on 21/11/2017.
8 | */
9 | fun InputStream.toString(): String {
10 | val s = Scanner(this)
11 | .useDelimiter("\\A")
12 | return if (s.hasNext()) s.next() else ""
13 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/support/GenericRecyclerAdapter.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.support
2 |
3 | import android.content.Context
4 | import android.support.annotation.LayoutRes
5 | import android.support.v7.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import goldzweigapps.com.core.support.GenericRecyclerViewAdapterExtensions
10 |
11 | abstract class GenericRecyclerAdapter(context: Context,
12 | genericList: MutableList = ArrayList(),
13 | @LayoutRes private val layoutRes: Int) :
14 | GenericRecyclerViewAdapterExtensions.GenericViewHolder>(genericList) {
15 |
16 | private var layoutInflater: LayoutInflater = LayoutInflater.from(context)
17 |
18 | //region setup and binding
19 | inner class GenericViewHolder(private val v: View) : RecyclerView.ViewHolder(v) {
20 |
21 | fun onBind(currentElementPosition: Int, currentElement: E) {
22 | v.onBind(currentElementPosition, currentElement, this)
23 | }
24 | }
25 |
26 | override fun getItemCount() = elements.size
27 |
28 | open fun count() = itemCount
29 |
30 | override fun onCreateViewHolder(p0: ViewGroup, p1: Int) =
31 | GenericViewHolder(layoutInflater.inflate(layoutRes, p0, false))
32 |
33 | override fun onBindViewHolder(holder: GenericViewHolder, p1: Int) =
34 | if (elements.isNotEmpty())
35 | holder.onBind(p1, elements[p1]) else Unit
36 |
37 | abstract fun View.onBind(currentElementPosition: Int, currentElement: E, holder: GenericViewHolder)
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/support/GenericRecyclerViewAdapterExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.support
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import goldzweigapps.com.core.threads.isUiThread
5 |
6 | abstract class GenericRecyclerViewAdapterExtensions(var elements: MutableList) :
7 | RecyclerView.Adapter() {
8 |
9 | override fun getItemCount() = elements.size
10 |
11 | open fun replaceList(newGenericList: List) {
12 | elements.clear()
13 | elements.addAll(newGenericList)
14 | if (isUiThread()) notifyDataSetChanged()
15 | }
16 |
17 | open fun setItems(newGenericList: List) = replaceList(newGenericList)
18 |
19 | open fun setItem(position: Int, newGenericItem: E) {
20 | if (position in 0..elements.size) {
21 | elements[position] = newGenericItem
22 | if (isUiThread()) notifyItemChanged(position)
23 | }
24 | }
25 |
26 | open fun add(itemToAdd: E, position: Int = elements.size) {
27 | elements.add(position, itemToAdd)
28 | if (isUiThread()) notifyItemInserted(position)
29 | }
30 |
31 | open fun addRange(itemsToAdd: List, positionToInsert: Int = elements.size) {
32 | elements.addAll(positionToInsert, itemsToAdd)
33 | if (isUiThread()) notifyItemRangeInserted(positionToInsert, itemsToAdd.size)
34 | }
35 |
36 | open fun removeRange(itemsToRemove: List) {
37 | val startPosition = elements.indexOf(itemsToRemove[0])
38 | elements.removeAll(itemsToRemove)
39 | if (isUiThread()) notifyItemRangeRemoved(startPosition, itemsToRemove.size)
40 | }
41 |
42 | open fun removeRange(rangeToRemove: IntRange) {
43 | removeRange(elements.subList(rangeToRemove.start, rangeToRemove.last))
44 | }
45 |
46 | open fun remove(itemToRemove: E) {
47 | val removePosition = elements.indexOf(itemToRemove)
48 | if (removePosition != -1) {
49 | elements.removeAt(removePosition)
50 | if (isUiThread()) notifyItemRemoved(removePosition)
51 | }
52 | }
53 |
54 | open fun remove(removePosition: Int) {
55 | if (removePosition != -1) {
56 | elements.removeAt(removePosition)
57 | if (isUiThread()) notifyItemRemoved(removePosition)
58 | }
59 | }
60 |
61 | open fun clear() {
62 | elements.clear()
63 | if (isUiThread()) notifyDataSetChanged()
64 | }
65 |
66 | open fun isEmpty() = elements.isEmpty()
67 |
68 | open fun isNotEmpty() = !isEmpty()
69 |
70 | open operator fun minus(rangeToRemove: IntRange) = removeRange(rangeToRemove)
71 |
72 | open operator fun minus(itemsToRemove: List) = removeRange(itemsToRemove)
73 | open operator fun minus(itemToRemove: E) = remove(itemToRemove)
74 | open operator fun minus(removePosition: Int) = remove(removePosition)
75 |
76 | open operator fun plus(itemsToAdd: List) = addRange(itemsToAdd)
77 |
78 | open operator fun plus(itemToAdd: E) = add(itemToAdd)
79 | open operator fun plus(itemToAddInPosition: Pair) =
80 | with(itemToAddInPosition) { add(first, second) }
81 |
82 | open operator fun get(position: Int) = elements[position]
83 |
84 | open operator fun get(item: E) = elements.indexOf(item)
85 | }
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/threads/ThreadsExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.threads
2 |
3 | import android.os.AsyncTask
4 | import android.os.Build
5 | import android.os.Handler
6 | import android.os.Looper
7 |
8 |
9 | /**
10 | * Created by gilgoldzweig on 04/09/2017.
11 | */
12 | private val handler = Handler()
13 |
14 | /**
15 | * @return current thread is UI thread or not
16 | */
17 | fun isUiThread() =
18 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
19 | Looper.getMainLooper().isCurrentThread
20 | else
21 | Thread.currentThread() == Looper.getMainLooper().thread
22 |
23 | /**
24 | * run a function after a provided millis
25 | * @param millis millisecond to wait before running the function
26 | * @param thread run the function on selected thread
27 | * @param func function to run after provided time
28 | * runAfter(2000) {
29 | * //running this part after 2000 millis in current thread
30 | * }
31 | * @return true for success and false for failure
32 | */
33 | fun runAfter(millis: Long,
34 | thread: RunnableThread = RunnableThreads.CURRENT,
35 | func: () -> Unit) =
36 | handler.postDelayed({ thread.run(func) }, millis)
37 |
38 | fun run(thread: RunnableThread = RunnableThreads.CURRENT, func: () -> Unit) =
39 | thread.run(func)
40 |
41 |
42 | /**
43 | * run a function on ui thread
44 | * @param func
45 | * runOnUI {
46 | * //running this part on ui thread
47 | * }
48 | * @return true for success and false for failure
49 | */
50 | fun runOnUI(func: () -> Unit) = RunnableThreads.UI.run(func)
51 |
52 | /**
53 | * run a vararg functions on background thread
54 | * @param functions
55 | * runInBackground ({
56 | * //running this part in background
57 | * },{
58 | * //running also this part in background
59 | * },{
60 | * //running also this part in background
61 | * })
62 | * @return Unit
63 | */
64 | fun runInBackground(vararg functions: () -> Unit) =
65 | RunnableThreads.BACKGROUND.run(*functions)
66 |
67 | /**
68 | * running a single function in background same as runInBackground(vararg functions: () -> Unit)
69 | * but with an easier lambda access
70 | * on background thread
71 | * @param func
72 | * runInBackground {
73 | * //running this part in background
74 | * }
75 | * @return Unit
76 | */
77 | fun runInBackground(func: () -> Unit) = RunnableThreads.BACKGROUND.run(func)
78 |
79 | class BackgroundReturnTask(val returnValue: (R) -> Unit) : AsyncTask<() -> R, Any, Any>() {
80 | var values: List = ArrayList()
81 | override fun doInBackground(vararg params: (() -> R)): Any {
82 | params.forEach { values += it.invoke() }
83 | return false
84 | }
85 |
86 | override fun onPostExecute(result: Any?) {
87 | super.onPostExecute(result)
88 | values.forEach(returnValue::invoke)
89 | }
90 | }
91 |
92 | fun runInBackground(func: () -> R, returnValue: (R) -> Unit) {
93 | BackgroundReturnTask(returnValue).execute(func)
94 | }
95 |
96 | interface RunnableThread {
97 | fun run(vararg functions: () -> Unit)
98 | }
99 |
100 | sealed class RunnableThreads: RunnableThread {
101 | object UI : RunnableThreads() {
102 | override fun run(vararg functions: () -> Unit) {
103 | for (function in functions) {
104 | if (!isUiThread()) {
105 | handler.post(function::invoke)
106 | } else {
107 | function.invoke()
108 | }
109 | }
110 | }
111 | }
112 | object BACKGROUND : RunnableThreads() {
113 | override fun run(vararg functions: () -> Unit) {
114 | functions.forEach { Thread(it::invoke).start() }
115 | }
116 | }
117 | object CURRENT : RunnableThreads() {
118 | override fun run(vararg functions: () -> Unit) {
119 | for (function in functions) function.invoke()
120 | }
121 | }
122 | }
123 |
124 |
--------------------------------------------------------------------------------
/core/src/main/java/goldzweigapps/com/core/views/ViewsExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core.views
2 |
3 | import android.content.Context
4 | import android.support.annotation.LayoutRes
5 | import android.support.annotation.StringRes
6 | import android.support.design.widget.Snackbar
7 | import android.support.v7.widget.LinearLayoutManager
8 | import android.text.Editable
9 | import android.text.TextWatcher
10 | import android.view.LayoutInflater
11 | import android.view.View
12 | import android.view.ViewGroup
13 | import android.widget.EditText
14 | import android.widget.TextView
15 | import goldzweigapps.com.core.collections.asIterableIndexed
16 |
17 | /**
18 | * Created by gilgoldzweig on 04/09/2017.
19 | */
20 |
21 | //region view visibility
22 | fun View.toggleVisibility() {
23 | visibility = if (isVisible()) View.GONE else View.VISIBLE
24 | }
25 |
26 | fun View.isVisible() = visibility == View.VISIBLE
27 |
28 | fun View.hide() {
29 | visibility = View.GONE
30 | }
31 |
32 | fun View.show() {
33 | visibility = View.VISIBLE
34 | }
35 |
36 | fun View.invisible() {
37 | visibility = View.INVISIBLE
38 | }
39 | //endregion view visibility
40 |
41 | fun View.onClick(onClick: () -> Unit) = setOnClickListener { onClick() }
42 |
43 | fun View.onLongClick(onLongClick: () -> Unit) = setOnLongClickListener {
44 | onLongClick()
45 | false
46 | }
47 |
48 | fun EditText.onTextChange(onTextChange: (text: CharSequence) -> Unit) {
49 | addTextChangedListener(object : TextWatcher {
50 | override fun afterTextChanged(s: Editable?) = Unit
51 |
52 | override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
53 |
54 | override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) =
55 | onTextChange(s ?: "")
56 | })
57 | }
58 |
59 | typealias ActionString = Pair
60 | typealias ActionResId = Pair
61 |
62 | val Context.linearLayoutManager: LinearLayoutManager
63 | get() = LinearLayoutManager(this)
64 |
65 | val Context.horizontalLinearLayoutManager: LinearLayoutManager
66 | get() = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
67 |
68 | fun View.snackBar(message: CharSequence, length: Int = Snackbar.LENGTH_LONG, action: ActionString? = null) {
69 | val snackBar = Snackbar.make(this, message, length)
70 | action?.let {
71 | snackBar.setAction(it.first, it.second)
72 | }
73 | snackBar.show()
74 | }
75 | fun View.snackBar(@StringRes message: Int, length: Int = Snackbar.LENGTH_LONG, action: ActionResId? = null) {
76 | val snackBar = Snackbar.make(this, message, length)
77 | action?.let {
78 | snackBar.setAction(it.first, it.second)
79 | }
80 | snackBar.show()
81 | }
82 |
83 | fun View.height(height: Int) {
84 | layoutParams.height = height
85 | }
86 | fun View.width(width: Int) {
87 | layoutParams.height = height
88 | }
89 |
90 | operator fun TextView.plusAssign(valueToAdd: String) {
91 | text = "$text$valueToAdd"
92 | }
93 | operator fun TextView.minusAssign(valueToRemove: String) {
94 | text = text.removePrefix(valueToRemove)
95 | }
96 | operator fun TextView.contains(value: String) = value in text
97 |
98 | @Throws(IndexOutOfBoundsException::class)
99 | operator fun TextView.get(index: Int): Char {
100 | return if (index in 0..text.length) {
101 | text[index]
102 | } else {
103 | throw IndexOutOfBoundsException("""
104 | Index: $index
105 | Start: 0
106 | End: ${text.length}
107 | """.trimIndent())
108 | }
109 | }
110 |
111 | operator fun TextView.get(char: Char, ignoreCase: Boolean = false) =
112 | text.toString().indexOf(char, 0, ignoreCase)
113 |
114 | fun ViewGroup.inflate(@LayoutRes layoutRes: Int,
115 | attachToRoot: Boolean = false) =
116 | LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
117 |
118 | fun Context.inflate(@LayoutRes layoutRes: Int,
119 | attachToRoot: Boolean = false,
120 | root: ViewGroup? = null) =
121 | LayoutInflater.from(this).inflate(layoutRes, root, attachToRoot)
122 |
123 | //region ViewGroup operators
124 | /**
125 | * [position] = getChildAt(position)
126 | */
127 | operator fun ViewGroup.get(position: Int): View? = getChildAt(position)
128 |
129 | /**
130 | * [view] = indexOfChild(view)
131 | */
132 | operator fun ViewGroup.get(view: View) = indexOfChild(view)
133 |
134 | /**
135 | * -=
136 | */
137 | operator fun ViewGroup.minusAssign(child: View) = removeView(child)
138 |
139 | /**
140 | * +=
141 | */
142 | operator fun ViewGroup.plusAssign(child: View) = addView(child)
143 |
144 | /**
145 | * if (view in views)
146 | */
147 | operator fun ViewGroup.contains(child: View) = get(child) != -1
148 |
149 | /**
150 | * for (view in views.iterator)
151 | * @param T Any layout that extends ViewGroup for example LinearLayout
152 | */
153 | operator fun T.iterator(): Iterable {
154 | return asIterableIndexed({ it < childCount }, {
155 | getChildAt(it)
156 | }, {
157 | it.inc()
158 | })
159 | }
160 | //endregion ViewGroup operators
161 |
162 | //region ViewGroup iterations
163 | fun ViewGroup.first() = this[0]
164 |
165 | fun ViewGroup.last() = this[childCount]
166 |
167 | inline fun ViewGroup.forEach(action: (View) -> Unit) {
168 | for (i in 0 until childCount) {
169 | action(getChildAt(i))
170 | }
171 | }
172 |
173 | inline fun ViewGroup.forEachIndexed(action: (Int, View) -> Unit) {
174 | for (i in 0 until childCount) {
175 | action(i, getChildAt(i))
176 | }
177 | }
178 |
179 | inline fun ViewGroup.forEachRevered(action: (View) -> Unit) {
180 | for (i in childCount downTo 0) {
181 | action(getChildAt(i))
182 | }
183 | }
184 |
185 | inline fun ViewGroup.forEachReveredIndexed(action: (Int, View) -> Unit) {
186 | for (i in childCount downTo 0) {
187 | action(i, getChildAt(i))
188 | }
189 | }
190 | //endregion ViewGroup iterations
--------------------------------------------------------------------------------
/core/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Library
3 |
4 |
--------------------------------------------------------------------------------
/core/src/test/java/goldzweigapps/com/core/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.core;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | @Test
18 | public void intIterable_isCounting() throws Exception {
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilgoldzweig/Kotlinify/5b45da2be009d00cc29beabe4794b59b681aacf5/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Apr 07 15:02:32 IDT 2018
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-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/jackson/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/jackson/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 | apply plugin: 'com.novoda.bintray-release'
5 | group = 'com.github.gilgoldzweig'
6 | android {
7 | compileSdkVersion 27
8 | buildToolsVersion "27.0.3"
9 |
10 |
11 | defaultConfig {
12 | minSdkVersion 14
13 | targetSdkVersion 27
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
18 |
19 | }
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | }
27 | publish {
28 | userOrg = "$rootProject.userOrg"
29 | groupId = "$rootProject.groupId"
30 | publishVersion = "$rootProject.publishVersion"
31 | website = "$rootProject.website"
32 | artifactId = 'jackson'
33 | desc = 'The jackson module provides the following classes and extensions.'
34 | }
35 |
36 | dependencies {
37 | implementation fileTree(dir: 'libs', include: ['*.jar'])
38 | testImplementation 'junit:junit:4.12'
39 |
40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
41 | implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.0"
42 | }
43 |
--------------------------------------------------------------------------------
/jackson/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/gilgoldzweig/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/jackson/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/jackson/src/main/java/goldzweigapps/com/jackson/jacksonExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.jackson
2 |
3 | import com.fasterxml.jackson.core.JsonParser
4 | import com.fasterxml.jackson.databind.ObjectMapper
5 | import com.fasterxml.jackson.module.kotlin.readValue
6 | import java.io.File
7 | import java.io.InputStream
8 | import java.io.Reader
9 | import java.net.URL
10 |
11 | /**
12 | * Created by gilgoldzweig on 13/09/2017.
13 | */
14 | val objectMapper by lazy { ObjectMapper() }
15 |
16 | fun Any.toJson(): String = objectMapper.writeValueAsString(this)
17 | fun Any.toPrettyJson(): String = objectMapper.writerWithDefaultPrettyPrinter()
18 | .writeValueAsString(this)
19 |
20 | inline fun String.fromJson() = objectMapper.readValue(this)
21 | inline fun InputStream.fromJson() = objectMapper.readValue(this)
22 | inline fun JsonParser.fromJson() = objectMapper.readValue(this)
23 | inline fun ByteArray.fromJson() = objectMapper.readValue(this)
24 | inline fun File.fromJson() = objectMapper.readValue(this)
25 | inline fun Reader.fromJson() = objectMapper.readValue(this)
26 | inline fun URL.fromJson() = objectMapper.readValue(this)
27 |
--------------------------------------------------------------------------------
/jackson/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Activites
3 |
4 |
--------------------------------------------------------------------------------
/jackson/src/test/java/goldzweigapps/com/jackson/JacksonUnitTest.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.jackson
2 |
3 | import org.junit.Assert
4 | import org.junit.Test
5 |
6 | /**
7 | * Created by gilgoldzweig on 19/10/2017.
8 | */
9 | class JacksonUnitTest {
10 | val simplePersonTestJson = "{\"firstName\":\"testFirstName\",\"lastName\":\"testFamilyName\",\"age\":41}"
11 | val simplePersonTestPrettyJson = "{\n" +
12 | " \"firstName\" : \"testFirstName\",\n" +
13 | " \"lastName\" : \"testFamilyName\",\n" +
14 | " \"age\" : 41\n" +
15 | "}\n"
16 | @Test
17 | fun tojson_isCurrent() {
18 | Assert.assertEquals(simplePersonTestJson,
19 | PersonTestObject("testFirstName", "testFamilyName", 41)
20 | .toJson())
21 | }
22 | @Test
23 | fun prettyjson_IsCurrect() {
24 | Assert.assertEquals(simplePersonTestJson,
25 | PersonTestObject("testFirstName", "testFamilyName", 41)
26 | .toPrettyJson())
27 | }
28 | }
29 |
30 | data class PersonTestObject(var firstName: String = "",
31 | var lastName: String = "",
32 | var age: Int = 0)
--------------------------------------------------------------------------------
/reactive/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/reactive/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 | apply plugin: 'com.novoda.bintray-release'
5 | group = 'com.github.gilgoldzweig'
6 |
7 | publish {
8 | userOrg = "$rootProject.userOrg"
9 | groupId = "$rootProject.groupId"
10 | publishVersion = "$rootProject.publishVersion"
11 | website = "$rootProject.website"
12 | artifactId = 'reactive'
13 | desc = 'The Reactive module provides the following extensions.'
14 | }
15 | android {
16 | compileSdkVersion 27
17 | buildToolsVersion '27.0.3'
18 |
19 |
20 | defaultConfig {
21 | minSdkVersion 14
22 | targetSdkVersion 27
23 | versionCode 1
24 | versionName "1.0"
25 |
26 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
27 |
28 | }
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | }
36 |
37 | dependencies {
38 | implementation fileTree(dir: 'libs', include: ['*.jar'])
39 | testImplementation 'junit:junit:4.12'
40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
41 |
42 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
43 | implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
44 | }
45 |
--------------------------------------------------------------------------------
/reactive/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/gilgoldzweig/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/reactive/src/androidTest/java/goldzweigapps/com/reactive/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.reactive;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("goldzweigapps.com.reactive.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/reactive/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/reactive/src/main/java/goldzweigapps/com/reactive/ReactiveExtensions.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.reactive
2 |
3 | import io.reactivex.*
4 | import io.reactivex.android.schedulers.AndroidSchedulers
5 | import io.reactivex.schedulers.Schedulers
6 |
7 | /**
8 | * Created by gilgoldzweig on 30/08/2017.
9 | * some small extensions function to allow easier usage with Reactive in android
10 | */
11 | private val mainThread = AndroidSchedulers.mainThread()
12 | private val newThread = Schedulers.newThread()
13 | private val ioThread = Schedulers.io()
14 |
15 | /**
16 | * observe on main thread
17 | * subscribe on new thread
18 | * unsubsidised on error and on complete and removes the need to handle it afterwards
19 | * @usage
20 | * someObservable
21 | * .runSafeOnMain()
22 | * .subscribe({}, {])
23 | */
24 | fun Observable.runSafeOnMain(): Observable =
25 | observeOn(mainThread)
26 | .subscribeOn(newThread)
27 | .doOnError({ unsubscribeOn(newThread) })
28 | .doOnComplete { unsubscribeOn(newThread) }
29 |
30 |
31 | fun Observable.runSafeOnIO(): Observable =
32 | observeOn(ioThread)
33 | .subscribeOn(newThread)
34 | .doOnError({ unsubscribeOn(newThread) })
35 | .doOnComplete { unsubscribeOn(newThread) }
36 |
37 | fun Flowable.runSafeOnMain(): Flowable =
38 | observeOn(mainThread)
39 | .subscribeOn(newThread)
40 | .doOnError({ unsubscribeOn(newThread) })
41 | .doOnComplete { unsubscribeOn(newThread) }
42 |
43 | fun Flowable.runSafeOnIO(): Flowable =
44 | observeOn(ioThread)
45 | .subscribeOn(newThread)
46 | .doOnError({ unsubscribeOn(newThread) })
47 | .doOnComplete { unsubscribeOn(newThread) }
48 |
49 | fun Single.runSafeOnMain(): Single =
50 | observeOn(mainThread)
51 | .subscribeOn(newThread)
52 | .doOnError({ unsubscribeOn(newThread) })
53 | .doOnSuccess { unsubscribeOn(newThread) }
54 |
55 | fun Single.runSafeOnIO(): Single =
56 | observeOn(ioThread)
57 | .subscribeOn(newThread)
58 | .doOnError({ unsubscribeOn(newThread) })
59 | .doOnSuccess { unsubscribeOn(newThread) }
60 |
61 | fun Completable.runSafeOnMain(): Completable =
62 | observeOn(mainThread)
63 | .subscribeOn(newThread)
64 | .doOnError({ unsubscribeOn(newThread) })
65 | .doOnComplete({ unsubscribeOn(newThread) })
66 |
67 | fun Completable.runSafeOnIO(): Completable =
68 | observeOn(ioThread)
69 | .subscribeOn(newThread)
70 | .doOnError({ unsubscribeOn(newThread) })
71 | .doOnComplete({ unsubscribeOn(newThread) })
72 |
73 |
74 | fun Maybe.runSafeOnMain(): Maybe =
75 | observeOn(mainThread)
76 | .subscribeOn(newThread)
77 | .doOnError({ unsubscribeOn(newThread) })
78 | .doOnSuccess { unsubscribeOn(newThread) }
79 |
80 | fun Maybe.runSafeOnIO(): Maybe =
81 | observeOn(ioThread)
82 | .subscribeOn(newThread)
83 | .doOnError({ unsubscribeOn(newThread) })
84 | .doOnSuccess { unsubscribeOn(newThread) }
85 |
86 |
--------------------------------------------------------------------------------
/reactive/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Reactive
3 |
4 |
--------------------------------------------------------------------------------
/reactive/src/test/java/goldzweigapps/com/reactive/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.reactive;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':reactive', ':jackson', ':core', ':timber'
2 |
--------------------------------------------------------------------------------
/timber/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/timber/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 | apply plugin: 'com.novoda.bintray-release'
5 | group = 'com.github.gilgoldzweig'
6 |
7 |
8 | android {
9 | compileSdkVersion 27
10 | buildToolsVersion "27.0.3"
11 |
12 |
13 | defaultConfig {
14 | minSdkVersion 14
15 | targetSdkVersion 27
16 | versionCode 1
17 | versionName "1.0"
18 |
19 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
20 |
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 |
30 | }
31 | publish {
32 | userOrg = "$rootProject.userOrg"
33 | groupId = "$rootProject.groupId"
34 | publishVersion = "$rootProject.publishVersion"
35 | website = "$rootProject.website"
36 | artifactId = 'timber'
37 | desc = 'Custom edition of JakeWharton/timber'
38 | }
39 | dependencies {
40 | implementation fileTree(dir: 'libs', include: ['*.jar'])
41 |
42 | testImplementation 'junit:junit:4.12'
43 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
44 | exclude group: 'com.android.support', module: 'support-annotations'
45 | })
46 |
47 | implementation "com.android.support:appcompat-v7:$rootProject.versions.support"
48 |
49 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
50 |
51 | }
--------------------------------------------------------------------------------
/timber/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/timber/src/androidTest/java/goldzweigapps/com/timber/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.timber;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("goldzweigapps.com.timber.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/timber/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/timber/src/main/java/goldzweigapps/com/timber/Timber.kt:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.timber
2 |
3 | import android.util.Log
4 | import java.io.PrintWriter
5 | import java.io.StringWriter
6 | import java.lang.*
7 | import java.util.*
8 | import java.util.Collections.unmodifiableList
9 | import java.util.regex.Pattern
10 |
11 | @Suppress("unused")
12 | object Timber {
13 |
14 | /**
15 | * A facade for handling logging calls. Install instances via [Timber.plant()][.plant].
16 | */
17 | abstract class Tree {
18 | internal val explicitTag = ThreadLocal()
19 |
20 | internal open val tag: String?
21 | get() {
22 | val tag = explicitTag.get()
23 | if (tag != null) {
24 | explicitTag.remove()
25 | }
26 | return tag
27 | }
28 |
29 | /**
30 | * Log a verbose message workWith optional format args.
31 | */
32 | open fun v(message: Any?, vararg args: Any) {
33 | prepareLog(Log.VERBOSE, null, message, *args)
34 | }
35 |
36 | /**
37 | * Log a verbose exception and a message workWith optional format args.
38 | */
39 | open fun v(t: Throwable, message: Any, vararg args: Any) {
40 | prepareLog(Log.VERBOSE, t, message, *args)
41 | }
42 |
43 | /**
44 | * Log a verbose exception.
45 | */
46 | open fun v(t: Throwable) {
47 | prepareLog(Log.VERBOSE, t, null)
48 | }
49 |
50 | /**
51 | * Log a debug message workWith optional format args.
52 | */
53 | open fun d(message: Any, vararg args: Any) {
54 | prepareLog(Log.DEBUG, null, message, *args)
55 | }
56 |
57 | /**
58 | * Log a debug exception and a message workWith optional format args.
59 | */
60 | open fun d(t: Throwable, message: Any, vararg args: Any) {
61 | prepareLog(Log.DEBUG, t, message, *args)
62 | }
63 |
64 | /**
65 | * Log a debug exception.
66 | */
67 | open fun d(t: Throwable) {
68 | prepareLog(Log.DEBUG, t, null)
69 | }
70 |
71 | /**
72 | * Log an info message workWith optional format args.
73 | */
74 | open fun i(message: Any, vararg args: Any) {
75 | prepareLog(Log.INFO, null, message, *args)
76 | }
77 |
78 | /**
79 | * Log an info exception and a message workWith optional format args.
80 | */
81 | open fun i(t: Throwable, message: Any, vararg args: Any) {
82 | prepareLog(Log.INFO, t, message, *args)
83 | }
84 |
85 | /**
86 | * Log an info exception.
87 | */
88 | open fun i(t: Throwable) {
89 | prepareLog(Log.INFO, t, null)
90 | }
91 |
92 | /**
93 | * Log a warning message workWith optional format args.
94 | */
95 | open fun w(message: Any, vararg args: Any) {
96 | prepareLog(Log.WARN, null, message, *args)
97 | }
98 |
99 | /**
100 | * Log a warning exception and a message workWith optional format args.
101 | */
102 | open fun w(t: Throwable, message: Any, vararg args: Any) {
103 | prepareLog(Log.WARN, t, message, *args)
104 | }
105 |
106 | /**
107 | * Log a warning exception.
108 | */
109 | open fun w(t: Throwable) {
110 | prepareLog(Log.WARN, t, null)
111 | }
112 |
113 | /**
114 | * Log an error message workWith optional format args.
115 | */
116 | open fun e(message: Any, vararg args: Any) {
117 | prepareLog(Log.ERROR, null, message, *args)
118 | }
119 |
120 | /**
121 | * Log an error exception and a message workWith optional format args.
122 | */
123 | open fun e(t: Throwable, message: Any, vararg args: Any) {
124 | prepareLog(Log.ERROR, t, message, *args)
125 | }
126 |
127 | /**
128 | * Log an error exception.
129 | */
130 | open fun e(t: Throwable) {
131 | prepareLog(Log.ERROR, t, null)
132 | }
133 |
134 | /**
135 | * Log an assert message workWith optional format args.
136 | */
137 | open fun wtf(message: Any, vararg args: Any) {
138 | prepareLog(Log.ASSERT, null, message, *args)
139 | }
140 |
141 | /**
142 | * Log an assert exception and a message workWith optional format args.
143 | */
144 | open fun wtf(t: Throwable, message: Any, vararg args: Any) {
145 | prepareLog(Log.ASSERT, t, message, *args)
146 | }
147 |
148 | /**
149 | * Log an assert exception.
150 | */
151 | open fun wtf(t: Throwable) {
152 | prepareLog(Log.ASSERT, t, null)
153 | }
154 |
155 | /**
156 | * Log at `priority` a message workWith optional format args.
157 | */
158 | open fun log(priority: Int, message: Any, vararg args: Any) {
159 | prepareLog(priority, null, message, *args)
160 | }
161 |
162 | /**
163 | * Log at `priority` an exception and a message workWith optional format args.
164 | */
165 | open fun log(priority: Int, t: Throwable, message: Any, vararg args: Any) {
166 | prepareLog(priority, t, message, *args)
167 | }
168 |
169 | /**
170 | * Log at `priority` an exception.
171 | */
172 | open fun log(priority: Int, t: Throwable) {
173 | prepareLog(priority, t, null)
174 | }
175 |
176 | private fun prepareLog(priority: Int, t: Throwable?, messageObject: Any?, vararg args: Any) {
177 | var message: String? = messageObject.toString()
178 | // Consume tag even when message is not loggable so that next message is correctly tagged.
179 | val tag = tag
180 | if (message != null && message.isEmpty()) {
181 | message = null
182 | }
183 | if (message == null) {
184 | if (t == null) {
185 | return // Swallow message if it's null and there's no throwable.
186 | }
187 | message = getStackTraceString(t)
188 | } else {
189 | if (args.isNotEmpty()) {
190 | message = formatMessage(message, args)
191 | }
192 | if (t != null) {
193 | message += "\n" + getStackTraceString(t)
194 | }
195 | }
196 |
197 | log(priority, tag, message, t)
198 | }
199 |
200 | /**
201 | * Formats a log message workWith optional arguments.
202 | */
203 | private fun formatMessage(message: String, args: Array): String =
204 | String.format(message, *args)
205 |
206 | private fun getStackTraceString(t: Throwable): String {
207 | // Don't replace this workWith Log.getStackTraceString() - it hides
208 | // UnknownHostException, which is not what we want.
209 | val sw = StringWriter(256)
210 | val pw = PrintWriter(sw, false)
211 | t.printStackTrace(pw)
212 | pw.flush()
213 | return sw.toString()
214 | }
215 |
216 | /**
217 | * Write a log message to its destination. Called for all level-specific methods by default.
218 | *
219 | * @param priority Log level. See [Log] for constants.
220 | * @param tag Explicit or inferred tag. May be `null`.
221 | * @param message Formatted log message. May be `null`, but then `t` will not be.
222 | * @param t Accompanying exceptions. May be `null`, but then `message` will not be.
223 | */
224 | protected abstract fun log(priority: Int, tag: String?, message: Any, t: Throwable?)
225 | }
226 |
227 | /**
228 | * A [Tree] for debug builds. Automatically infers the tag from the calling class.
229 | */
230 | class DebugTree : Tree() {
231 |
232 | override// DO NOT switch this to Thread.getCurrentThread().getStackTrace()
233 | val tag: String?
234 | get() {
235 | val tag = super.tag
236 | if (tag != null) {
237 | return tag
238 | }
239 | val stackTrace = Throwable().stackTrace
240 | if (stackTrace.size <= CALL_STACK_INDEX) {
241 | throw IllegalStateException(
242 | "Synthetic stacktrace didn't have enough elements: are you using proguard?")
243 | }
244 | return createStackElementTag(stackTrace[CALL_STACK_INDEX])
245 | }
246 |
247 | /**
248 | * Extract the tag which should be used for the message from the `element`. By default
249 | * this will use the class name without any anonymous class suffixes (e.g., `Foo$1`
250 | * becomes `Foo`).
251 | *
252 | *
253 | * Note: This will not be called if a [manual tag][.tag] was specified.
254 | */
255 | private fun createStackElementTag(element: StackTraceElement): String {
256 | var tag = element.className
257 | val m = ANONYMOUS_CLASS.matcher(tag)
258 | if (m.find()) {
259 | tag = m.replaceAll("")
260 | }
261 | tag = tag.substring(tag.lastIndexOf('.') + 1)
262 | return if (tag.length > MAX_TAG_LENGTH) tag.substring(0, MAX_TAG_LENGTH) else tag
263 | }
264 |
265 | /**
266 | * Break up `message` into maximum-length chunks (if needed) and send to either
267 | * [Log.println()][Log.println] or
268 | * [Log.wtf()][Log.wtf] for logging.
269 | *
270 | *
271 | * {@inheritDoc}
272 | */
273 | override fun log(priority: Int, tag: String?, message: Any, t: Throwable?) {
274 | var messageString = message.toString()
275 | if (message is Exception) {
276 | messageString = message.cause.toString()
277 | }
278 |
279 |
280 | if (messageString.length < MAX_LOG_LENGTH) {
281 | if (priority == Log.ASSERT) {
282 | Log.wtf(tag, messageString)
283 | } else {
284 | Log.println(priority, tag, messageString)
285 | }
286 | return
287 | }
288 |
289 | // Split by line, then ensure each line can fit into Log's maximum length.
290 | var i = 0
291 | val length = messageString.length
292 | while (i < length) {
293 | var newline = messageString.indexOf('\n', i)
294 | newline = if (newline != -1) newline else length
295 | do {
296 | val end = Math.min(newline, i + MAX_LOG_LENGTH)
297 | val part = messageString.substring(i, end)
298 | if (priority == Log.ASSERT) {
299 | Log.wtf(tag, part)
300 | } else {
301 | Log.println(priority, tag, part)
302 | }
303 | i = end
304 | } while (i < newline)
305 | i++
306 | }
307 | }
308 |
309 | companion object {
310 | private val MAX_LOG_LENGTH = 4000
311 | private val MAX_TAG_LENGTH = 23
312 | private val CALL_STACK_INDEX = 5
313 | private val ANONYMOUS_CLASS = Pattern.compile("(\\$\\d+)+$")
314 | }
315 | }
316 |
317 |
318 | private val TREE_ARRAY_EMPTY = arrayOfNulls(0)
319 | // Both fields guarded by 'FOREST'.
320 | private val FOREST = ArrayList()
321 | @Volatile private var forestAsArray = TREE_ARRAY_EMPTY
322 | /**
323 | * A [Tree] that delegates to all planted trees in the [forest][.FOREST].
324 | */
325 | internal val TREE_OF_SOULS = object : Tree() {
326 | override fun v(message: Any?, vararg args: Any) {
327 | val forest = forestAsArray
328 |
329 | var i = 0
330 | val count = forest.size
331 | while (i < count) {
332 | forest[i]?.v(message, *args)
333 | i++
334 | }
335 | }
336 |
337 | override fun v(t: Throwable, message: Any, vararg args: Any) {
338 | val forest = forestAsArray
339 |
340 | var i = 0
341 | val count = forest.size
342 | while (i < count) {
343 | forest[i]?.v(t, message, *args)
344 | i++
345 | }
346 | }
347 |
348 | override fun v(t: Throwable) {
349 | val forest = forestAsArray
350 |
351 | var i = 0
352 | val count = forest.size
353 | while (i < count) {
354 | forest[i]?.v(t)
355 | i++
356 | }
357 | }
358 |
359 | override fun d(message: Any, vararg args: Any) {
360 | val forest = forestAsArray
361 |
362 | var i = 0
363 | val count = forest.size
364 | while (i < count) {
365 | forest[i]?.d(message, *args)
366 | i++
367 | }
368 | }
369 |
370 | override fun d(t: Throwable, message: Any, vararg args: Any) {
371 | val forest = forestAsArray
372 |
373 | var i = 0
374 | val count = forest.size
375 | while (i < count) {
376 | forest[i]?.d(t, message, *args)
377 | i++
378 | }
379 | }
380 |
381 | override fun d(t: Throwable) {
382 | val forest = forestAsArray
383 |
384 | var i = 0
385 | val count = forest.size
386 | while (i < count) {
387 | forest[i]?.d(t)
388 | i++
389 | }
390 | }
391 |
392 | override fun i(message: Any, vararg args: Any) {
393 | val forest = forestAsArray
394 |
395 | var i = 0
396 | val count = forest.size
397 | while (i < count) {
398 | forest[i]?.i(message, *args)
399 | i++
400 | }
401 | }
402 |
403 | override fun i(t: Throwable, message: Any, vararg args: Any) {
404 | val forest = forestAsArray
405 |
406 | var i = 0
407 | val count = forest.size
408 | while (i < count) {
409 | forest[i]?.i(t, message, *args)
410 | i++
411 | }
412 | }
413 |
414 | override fun i(t: Throwable) {
415 | val forest = forestAsArray
416 |
417 | var i = 0
418 | val count = forest.size
419 | while (i < count) {
420 | forest[i]?.i(t)
421 | i++
422 | }
423 | }
424 |
425 | override fun w(message: Any, vararg args: Any) {
426 | val forest = forestAsArray
427 |
428 | var i = 0
429 | val count = forest.size
430 | while (i < count) {
431 | forest[i]?.w(message, *args)
432 | i++
433 | }
434 | }
435 |
436 | override fun w(t: Throwable, message: Any, vararg args: Any) {
437 | val forest = forestAsArray
438 |
439 | var i = 0
440 | val count = forest.size
441 | while (i < count) {
442 | forest[i]?.w(t, message, *args)
443 | i++
444 | }
445 | }
446 |
447 | override fun w(t: Throwable) {
448 | val forest = forestAsArray
449 |
450 | var i = 0
451 | val count = forest.size
452 | while (i < count) {
453 | forest[i]?.w(t)
454 | i++
455 | }
456 | }
457 |
458 | override fun e(message: Any, vararg args: Any) {
459 | val forest = forestAsArray
460 |
461 | var i = 0
462 | val count = forest.size
463 | while (i < count) {
464 | forest[i]?.e(message, *args)
465 | i++
466 | }
467 | }
468 |
469 | override fun e(t: Throwable, message: Any, vararg args: Any) {
470 | val forest = forestAsArray
471 |
472 | var i = 0
473 | val count = forest.size
474 | while (i < count) {
475 | forest[i]?.e(t, message, *args)
476 | i++
477 | }
478 | }
479 |
480 | override fun e(t: Throwable) {
481 | val forest = forestAsArray
482 |
483 | var i = 0
484 | val count = forest.size
485 | while (i < count) {
486 | forest[i]?.e(t)
487 | i++
488 | }
489 | }
490 |
491 | override fun wtf(message: Any, vararg args: Any) {
492 | val forest = forestAsArray
493 |
494 | var i = 0
495 | val count = forest.size
496 | while (i < count) {
497 | forest[i]?.wtf(message, *args)
498 | i++
499 | }
500 | }
501 |
502 | override fun wtf(t: Throwable, message: Any, vararg args: Any) {
503 | val forest = forestAsArray
504 |
505 | var i = 0
506 | val count = forest.size
507 | while (i < count) {
508 | forest[i]?.wtf(t, message, *args)
509 | i++
510 | }
511 | }
512 |
513 | override fun wtf(t: Throwable) {
514 | val forest = forestAsArray
515 |
516 | var i = 0
517 | val count = forest.size
518 | while (i < count) {
519 | forest[i]?.wtf(t)
520 | i++
521 | }
522 | }
523 |
524 | override fun log(priority: Int, message: Any, vararg args: Any) {
525 | val forest = forestAsArray
526 |
527 | var i = 0
528 | val count = forest.size
529 | while (i < count) {
530 | forest[i]?.log(priority, message, *args)
531 | i++
532 | }
533 | }
534 |
535 | override fun log(priority: Int, t: Throwable, message: Any, vararg args: Any) {
536 | val forest = forestAsArray
537 |
538 | var i = 0
539 | val count = forest.size
540 | while (i < count) {
541 | forest[i]?.log(priority, t, message, *args)
542 | i++
543 | }
544 | }
545 |
546 | override fun log(priority: Int, t: Throwable) {
547 | val forest = forestAsArray
548 |
549 | var i = 0
550 | val count = forest.size
551 | while (i < count) {
552 | forest[i]?.log(priority, t)
553 | i++
554 | }
555 | }
556 |
557 | override fun log(priority: Int, tag: String?, message: Any, t: Throwable?) {
558 | throw AssertionError("Missing override for log method.")
559 | }
560 | }
561 |
562 | /**
563 | * Log a verbose message workWith optional format args.
564 | */
565 | fun v(message: Any, vararg args: Any) {
566 | TREE_OF_SOULS.v(message, *args)
567 | }
568 |
569 | /**
570 | * Log a verbose exception and a message workWith optional format args.
571 | */
572 | fun v(t: Throwable, message: Any, vararg args: Any) {
573 | TREE_OF_SOULS.v(t, message, *args)
574 | }
575 |
576 | /**
577 | * Log a verbose exception.
578 | */
579 | fun v(t: Throwable) {
580 | TREE_OF_SOULS.v(t)
581 | }
582 |
583 | /**
584 | * Log a debug message workWith optional format args.
585 | */
586 | fun d(
587 | message: Any,
588 | vararg args: Any
589 | ) {
590 | TREE_OF_SOULS.d(message, *args)
591 | }
592 |
593 | /**
594 | * Log a debug exception and a message workWith optional format args.
595 | */
596 | fun d(t: Throwable, message: Any, vararg args: Any) {
597 | TREE_OF_SOULS.d(t, message, *args)
598 | }
599 |
600 | /**
601 | * Log a debug exception.
602 | */
603 | fun d(t: Throwable) {
604 | TREE_OF_SOULS.d(t)
605 | }
606 |
607 | /**
608 | * Log an info message workWith optional format args.
609 | */
610 | fun i(message: Any, vararg args: Any) {
611 | TREE_OF_SOULS.i(message, *args)
612 | }
613 |
614 | /**
615 | * Log an info exception and a message workWith optional format args.
616 | */
617 | fun i(t: Throwable, message: Any, vararg args: Any) {
618 | TREE_OF_SOULS.i(t, message, *args)
619 | }
620 |
621 | /**
622 | * Log an info exception.
623 | */
624 | fun i(t: Throwable) {
625 | TREE_OF_SOULS.i(t)
626 | }
627 |
628 | /**
629 | * Log a warning message workWith optional format args.
630 | */
631 | fun w(message: Any, vararg args: Any) {
632 | TREE_OF_SOULS.w(message, *args)
633 | }
634 |
635 | /**
636 | * Log a warning exception and a message workWith optional format args.
637 | */
638 | fun w(t: Throwable, message: Any, vararg args: Any) {
639 | TREE_OF_SOULS.w(t, message, *args)
640 | }
641 |
642 | /**
643 | * Log a warning exception.
644 | */
645 | fun w(t: Throwable) {
646 | TREE_OF_SOULS.w(t)
647 | }
648 |
649 | /**
650 | * Log an error message workWith optional format args.
651 | */
652 | fun e(message: Any, vararg args: Any) {
653 | TREE_OF_SOULS.e(message, *args)
654 | }
655 |
656 | /**
657 | * Log an error exception and a message workWith optional format args.
658 | */
659 | fun e(t: Throwable, message: Any, vararg args: Any) {
660 | TREE_OF_SOULS.e(t, message, *args)
661 | }
662 |
663 | /**
664 | * Log an error exception.
665 | */
666 | fun e(t: Throwable) {
667 | TREE_OF_SOULS.e(t)
668 | }
669 |
670 | /**
671 | * Log an error exception.
672 | */
673 | fun e(e: Exception) {
674 | if (e.cause == null) {
675 | TREE_OF_SOULS.e(e.message ?: "")
676 | } else {
677 | TREE_OF_SOULS.e(e.cause!!)
678 | }
679 | }
680 |
681 | /**
682 | * Log an assert message workWith optional format args.
683 | */
684 | fun wtf(message: Any, vararg args: Any) {
685 | TREE_OF_SOULS.wtf(message, *args)
686 | }
687 |
688 | /**
689 | * Log an assert exception and a message workWith optional format args.
690 | */
691 | fun wtf(t: Throwable, message: Any, vararg args: Any) {
692 | TREE_OF_SOULS.wtf(t, message, *args)
693 | }
694 |
695 | /**
696 | * Log an assert exception.
697 | */
698 | fun wtf(t: Throwable) {
699 | TREE_OF_SOULS.wtf(t)
700 | }
701 |
702 | /**
703 | * Log at `priority` a message workWith optional format args.
704 | */
705 | fun log(priority: Int, message: Any, vararg args: Any) {
706 | TREE_OF_SOULS.log(priority, message, *args)
707 | }
708 |
709 | /**
710 | * Log at `priority` an exception and a message workWith optional format args.
711 | */
712 | fun log(priority: Int, t: Throwable, message: Any, vararg args: Any) {
713 | TREE_OF_SOULS.log(priority, t, message, *args)
714 | }
715 |
716 | /**
717 | * Log at `priority` an exception.
718 | */
719 | fun log(priority: Int, t: Throwable) {
720 | TREE_OF_SOULS.log(priority, t)
721 | }
722 |
723 | /**
724 | * A view into Timber's planted trees as a tree itself. This can be used for injecting a logger
725 | * instance rather than using static methods or to facilitate testing.
726 | */
727 | fun asTree() = TREE_OF_SOULS
728 |
729 | /**
730 | * Set a one-time tag for use on the next logging call.
731 | */
732 | fun tag(tag: String): Tree {
733 | val forest = forestAsArray
734 |
735 | var i = 0
736 | val count = forest.size
737 | while (i < count) {
738 | forest[i]?.explicitTag?.set(tag)
739 | i++
740 | }
741 | return TREE_OF_SOULS
742 | }
743 |
744 | /**
745 | * Add a new logging tree.
746 | */
747 | fun plant(tree: Tree) {
748 | if (tree === TREE_OF_SOULS) {
749 | throw IllegalArgumentException("Cannot plant Timber into itself.")
750 | }
751 | synchronized(FOREST) {
752 | FOREST.add(tree)
753 | forestAsArray = FOREST.toTypedArray()
754 | }
755 | }
756 |
757 | /**
758 | * Adds new logging trees.
759 | */
760 | fun plant(vararg trees: Tree) {
761 |
762 | trees
763 | .filter { it === TREE_OF_SOULS }
764 | .forEach { throw IllegalArgumentException("Cannot plant Timber into itself.") }
765 | synchronized(FOREST) {
766 | Collections.addAll(FOREST, *trees)
767 | forestAsArray = FOREST.toTypedArray()
768 | }
769 | }
770 |
771 |
772 | /**
773 | * Remove a planted tree.
774 | */
775 | fun uproot(tree: Tree) {
776 |
777 | synchronized(FOREST) {
778 | if (!FOREST.remove(tree)) {
779 | throw IllegalArgumentException("Cannot uproot tree which is not planted: " + tree)
780 | }
781 | forestAsArray = FOREST.toTypedArray()
782 | }
783 | }
784 |
785 | /**
786 | * Remove all planted trees.
787 | */
788 | fun uprootAll() {
789 | synchronized(FOREST) {
790 | FOREST.clear()
791 | forestAsArray = TREE_ARRAY_EMPTY
792 | }
793 | }
794 |
795 | /**
796 | * Return a copy of all planted [trees][Tree].
797 | */
798 | fun forest(): List {
799 | synchronized(FOREST) {
800 | return unmodifiableList(ArrayList(FOREST))
801 | }
802 | }
803 |
804 | fun treeCount(): Int {
805 | synchronized(FOREST) {
806 | return FOREST.size
807 | }
808 | }
809 | }
810 |
811 | @Suppress("unused")
812 | fun Any?.d() = Timber.TREE_OF_SOULS.d(this ?: "null")
813 |
814 | @Suppress("unused")
815 | fun Any?.e() = Timber.TREE_OF_SOULS.e(this ?: "null")
816 |
817 | @Suppress("unused")
818 | fun Any?.i() = Timber.TREE_OF_SOULS.i(this ?: "null")
819 |
820 | @Suppress("unused")
821 | fun Any?.wtf() = Timber.TREE_OF_SOULS.wtf(this ?: "null")
822 |
823 | @Suppress("unused")
824 | fun Any?.w() = Timber.TREE_OF_SOULS.w(this ?: "null")
825 |
--------------------------------------------------------------------------------
/timber/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Timber
3 |
4 |
--------------------------------------------------------------------------------
/timber/src/test/java/goldzweigapps/com/timber/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package goldzweigapps.com.timber;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------