Skip to content

Commit

Permalink
Merge branch 'master' into bitmap-extension
Browse files Browse the repository at this point in the history
  • Loading branch information
savepopulation authored Nov 11, 2020
2 parents 107ac24 + ffc2e1c commit 486c1ec
Show file tree
Hide file tree
Showing 49 changed files with 393 additions and 2 deletions.
115 changes: 113 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,120 @@
[![alt text][InstagramIcon]][Instagram]
[![alt text][TelegramIcon]][Telegram]

### #142 Bitmap Extension
### #179 Bitmap Extension
![alt text](/screenshots/BitmapExtension.png)

### #178 BuildScript vs Allprojects
![alt text](/screenshots/BuildscriptVsAllprojects.png)

### [#177 Transient Annotation](/codes/Transient.kt)
![alt text](/screenshots/Transient.png)

### #176 ConstraintLayout Aspect Ratio
![alt text](/screenshots/ConstraintLayoutAspectRatio.png)

### #175 CoroutineScope Vs SupervisorScope
![alt text](/screenshots/CoroutineScopeVssupervisorScope.png)

### #174 Make When Exhaustive
![alt text](/screenshots/WhenExhaustive.png)

### #173 Delegating Setters and Getters
![alt text](/screenshots/DelegatingSettersGetters.jpg)

### #172 Proguard Keep Variants
![alt text](/screenshots/ProguardKeep.png)

### [#171 Kotlin Average Usage](/codes/Average.kt)
![alt text](/screenshots/Average.png)

### #170 View Visiblity Extensions
![alt text](/screenshots/ViewVisiblityExt.png)

### #169 Kotlin Where usage
![alt text](/screenshots/KotlinWhereUsage.jpg)

### #168 Moshi over Gson
![alt text](/screenshots/MoshiOverGson.png)

### #167 Constructor Injection over Field Injection
![alt text](/screenshots/ConstructorInjection.png)

### #166 Localizing Firebase Push Notifications
![alt text](/screenshots/AndroidLocalizedPushNotifications.png)

### #165 Dagger Android Injector
![alt text](/screenshots/DaggerAndroidInjector.png)

### [#164 Transformations switchMap and map LiveData-KTX usage](/codes/LiveDataTransformations.kt)
![alt text](/screenshots/LiveDataTransformations.png)

### #163 Creating Efficient Splash Screen
![alt text](/screenshots/EfficientSplashScreen.png)

### #162 Handling Deep Link with Navigation Component
![alt text](/screenshots/DeepLinkWithNavigationComponent.png)

### #161 Flow vs Observable
![alt text](/screenshots/FlowVsObservable.jpg)

### #160 Newline At End Of File
![alt text](/screenshots/NewlineAtEndOfFile.png)

### #159 Calling Java from Kotlin - Notation For Platform Types
![alt text](/screenshots/NotationForPlatformTypes.png)

### #158 App Background - Foreground Listener
![alt text](/screenshots/AppFgBgListener.png)

### #157 Automatically encrypts keys and values and adheres to the SharedPreference Interface
![alt text](/screenshots/EncryptedSharedPreferences.png)

### #156 Drawable vs Mipmap Folders
![alt text](/screenshots/DrawableVsMipMapFolders.jpg)

### #155 Extension functions for View Model Providers
![alt text](/screenshots/ViewModelExtension.png)

### #154 Relation Between Livedata,MutableLiveData and MediatorLiveData
![alt text](/screenshots/RelationBetweenLivedataAndSubClasses.png)

### #153 Coroutines Continuation Usage
![alt text](/screenshots/CoroutinesContinuationUsage.png)

### #152 Reading-Writing lists from/to RoomDB with Moshi
![alt text](/screenshots/RoomTypeConverter.png)

### #151 Jetpack Compose Sample
![alt text](/screenshots/JetpackCompose.png)

### #150 Launch vs Async
![alt text](/screenshots/LaunchVsAsync.jpg)

### #149 EditText Manual Focus Forward
![alt text](/screenshots/EditTextManualFocusForward.jpg)

### #148 Function Interfaces
![alt text](/screenshots/FunctionInterfaces.jpg)

### #147 DI Impl Costs Chart
![alt text](/screenshots/DiImplCosts.jpg)

### #146 Easy Spannable on Kotlin
![alt text](/screenshots/easyspannableonkotlin.png)

### #145 ApiCalls and Suspend Functions
![alt text](/screenshots/ApiCallsAndSuspendFunctions.png)

### #144 First and Predicate Usage
![alt text](/screenshots/FirstAndPredicate.jpg)

### #143 Luhn Check
![alt text](/screenshots/LuhnCheck.png)

### #142 List Impl. Discuss
![alt text](/screenshots/ListImplDiscuss.png)

### #141 How to Read From Json
![alt text](/screenshots/ReadFromJson.png)

Expand Down Expand Up @@ -120,7 +231,7 @@
### #106 Fragment Argument Delegate
![alt text](/screenshots/FragmentArgumentDelegate.png)

### #105 Db Entity Mapper
### #105 Db Entity Mapper
![alt text](/screenshots/DbEntityMapper.png)

### #104 Rx Debounce with Kotlin Coroutines
Expand Down
7 changes: 7 additions & 0 deletions codes/Average.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
val list = arrayListOf<Double>(2.0, 3.0, 7.0)
var sum = 0
list.forEach{
sum += it.toInt()
}
println(sum/list.size) // 4
println(list.average().toInt()) // 4
42 changes: 42 additions & 0 deletions codes/CorouitinesContinuation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package katas.`3kyu`

import java.util.*
import kotlin.coroutines.*

fun plus(o1: Optional<Int>, o2: Optional<Int>): Optional<Int> = `for` {
val i1: Int = bind(o1)
val i2: Int = bind(o2)
yield(i1 + i2)
}

suspend fun <T> bind(value: Optional<T>): T {
return suspendCoroutine { cont ->
if (value.isPresent)
cont.resumeWith(Result.success(value.get()))
else
cont.resumeWith(Result.failure(fail()))
}
}

fun <T> yield(value: T) = Optional.of(value)

fun <T> `for`(lambda: suspend () -> Optional<T>): Optional<T> {
var ret: Optional<T> = Optional.empty()
val completion: Continuation<Optional<T>> = object : Continuation<Optional<T>> {
override val context: CoroutineContext = EmptyCoroutineContext

override fun resumeWith(result: Result<Optional<T>>) {
ret = result.getOrElse {
when (it) {
is NoSuchElementException -> Optional.empty()
else -> throw it
}
}
}
}
lambda.startCoroutine(completion)
return ret
}

fun fail() = Exception()

30 changes: 30 additions & 0 deletions codes/DeepLinkWithNavigationComponent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Step 1: Add deep link element inside fragment of navigation graph
<deepLink app:uri="test://fetch/account" />

// Step 2: To enable implicit deep linking, Add a single <nav-graph> element to an activity that points to an existing navigation graph
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">

<application ... >

<activity name=".MainActivity" ...>
...

<nav-graph android:value="@navigation/nav_graph" />

...

</activity>
</application>
</manifest>


// Step 3 (Optional): Also you can handle parameters of deep link with placeholder
<deepLink app:uri="test://fetch/account?displayName={display_name}" />

// Step 4: To read data from placeholder, you need add an argument below deep link element
<argument android:name="display_name" app:argType="string"/>

// Step 5: Now you can use deep link placeholder's data in fragment with arguments
val displayName = arguments?.get("display_name") as String
34 changes: 34 additions & 0 deletions codes/EasySpannableOnKotlin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
val spanned = spannable {
bold("Sample Bold") +
italic("And Italic Text") +
color(Color.BLUE, "Blue Colored Text")
}

val nested = spannable{ bold(italic("nested ")) + url("www.google.com", "text") }

textView.text = spanned + nested

// Spannable.kt extension for further manipulations

import android.text.Spannable
import android.text.SpannableString
import android.text.TextUtils
import android.text.style.*

fun spannable(func: () -> SpannableString) = func()
private fun span(s: CharSequence, o: Any) = (if (s is String) SpannableString(s) else s as? SpannableString
?: SpannableString("")).apply { setSpan(o, 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) }

operator fun SpannableString.plus(s: SpannableString) = SpannableString(TextUtils.concat(this, s))
operator fun SpannableString.plus(s: String) = SpannableString(TextUtils.concat(this, s))

fun bold(s: CharSequence) = span(s, StyleSpan(android.graphics.Typeface.BOLD))
fun italic(s: CharSequence) = span(s, StyleSpan(android.graphics.Typeface.ITALIC))
fun underline(s: CharSequence) = span(s, UnderlineSpan())
fun strike(s: CharSequence) = span(s, StrikethroughSpan())
fun sup(s: CharSequence) = span(s, SuperscriptSpan())
fun sub(s: CharSequence) = span(s, SubscriptSpan())
fun size(size: Float, s: CharSequence) = span(s, RelativeSizeSpan(size))
fun color(color: Int, s: CharSequence) = span(s, ForegroundColorSpan(color))
fun background(color: Int, s: CharSequence) = span(s, BackgroundColorSpan(color))
fun url(url: String, s: CharSequence) = span(s, URLSpan(url))
21 changes: 21 additions & 0 deletions codes/EncryptedSharedPreferences.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Step 1: Create or retrieve the Master Key for encryption/decryption
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

// Step 2: Initialize/open an instance of EncryptedSharedPreferences
val sharedPreferences = EncryptedSharedPreferences.create(
"secret_shared_prefs",
masterKeyAlias,
applicationContext,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)


// Step 3: Save data to the EncryptedSharedPreferences as usual
sharedPreferences.edit()
.putString("KEY_VALUE", saveText.text.toString())
.apply()


// Step 4: Read data from EncryptedSharedPreferences as usual
val value = sharedPreferences.getString("KEY_VALUE", "")
15 changes: 15 additions & 0 deletions codes/JetPackCompose.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
Your Activity, in the onCreate method,
setContent{
//call the composable method
setTextIntoTheColumn("TextView Text1", "TextView Text2")
}
*/

@Composable
fun setTextIntoTheColumn(messageOne: String, messageTwo: String) {
Column {
Text(text = messageOne)
Text(text = messageTwo)
}
}
46 changes: 46 additions & 0 deletions codes/LiveDataTransformations.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Transformations switchMap and map LiveData-KTX usage

/* These methods permit functional composition and delegation of LiveData instances. The transformations are calculated
* lazily, and will run only when the returned LiveData is observed. Lifecycle behavior is propagated from the input
* source LiveData to the returned one. - more info.: developer.android.com/reference/androidx/lifecycle/Transformations
*/

class DashboardFragmentViewModel @Inject internal constructor(private val currentWeatherUseCase: CurrentWeatherUseCase) : BaseViewModel() {

private val _currentWeatherParams: MutableLiveData<CurrentWeatherUseCase.CurrentWeatherParams> = MutableLiveData()
fun getCurrentWeatherViewState() = currentWeatherViewState

private val currentWeatherViewState: LiveData<CurrentWeatherViewState> = _currentWeatherParams.switchMap { params ->
currentWeatherUseCase.execute(params) // When _currentWeatherParams triggered `switchMap` returns useCase.execute()
}

fun setCurrentWeatherParams(params: CurrentWeatherUseCase.CurrentWeatherParams) {
if (_currentWeatherParams.value == params)
return
_currentWeatherParams.postValue(params)
}
}


class CurrentWeatherUseCase @Inject internal constructor(private val repository: CurrentWeatherRepository) : UseCaseLiveData<CurrentWeatherViewState, CurrentWeatherUseCase.CurrentWeatherParams, CurrentWeatherRepository>() {

override fun buildUseCaseObservable(params: CurrentWeatherParams?): LiveData<CurrentWeatherViewState> {
return repository.loadCurrentWeatherByGeoCords(
params?.lat?.toDouble() ?: 0.0,
params?.lon?.toDouble() ?: 0.0,
params?.fetchRequired
?: false,
units = params?.units ?: Constants.Coords.METRIC
).map { // When loadCurrentWeatherByGeoCords triggered `map` returns onCurrentWeatherResultReady()
onCurrentWeatherResultReady(it)
}
}

private fun onCurrentWeatherResultReady(resource: Resource<CurrentWeatherEntity>): CurrentWeatherViewState {
return CurrentWeatherViewState(
status = resource.status,
error = resource.message,
data = resource.data
)
}
}
46 changes: 46 additions & 0 deletions codes/RoomTypeConverter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Reading-Writing lists from/to RoomDB with Moshi

object DataConverter {

@TypeConverter
@JvmStatic
fun stringToList(data: String?): List<ListItem>? {
if (data == null) {
return emptyList()
}

val moshi = Moshi.Builder().build()
val type = Types.newParameterizedType(List::class.java, ListItem::class.java)
val adapter = moshi.adapter<List<ListItem>>(type)
return adapter.fromJson(data)
}

@TypeConverter
@JvmStatic
fun listToString(objects: List<ListItem>): String {
val moshi = Moshi.Builder().build()
val type = Types.newParameterizedType(List::class.java, ListItem::class.java)
val adapter = moshi.adapter<List<ListItem>>(type)
return adapter.toJson(objects)
}
}

// -- Don't forget to add your TypeConverter to Database. --

@Database(
entities = [
ForecastEntity::class,
CurrentWeatherEntity::class,
CitiesForSearchEntity::class
],
version = 2
)
@TypeConverters(DataConverter::class)
abstract class WeatherDatabase : RoomDatabase() {

abstract fun forecastDao(): ForecastDao

abstract fun currentWeatherDao(): CurrentWeatherDao

abstract fun citiesForSearchDao(): CitiesForSearchDao
}
Loading

0 comments on commit 486c1ec

Please sign in to comment.