mirror of
https://github.com/aculix/Channelify.git
synced 2026-06-12 21:08:27 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,48 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
android {
|
||||
compileSdkVersion COMPILE_SDK_VERSION
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion MIN_SDK_VERSION
|
||||
targetSdkVersion TARGET_SDK_VERSION
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
// Kotlin
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
|
||||
|
||||
// AndroidX
|
||||
implementation "androidx.constraintlayout:constraintlayout:$clVersion"
|
||||
|
||||
// Architecture Components
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$archVersion"
|
||||
|
||||
// Material theme
|
||||
implementation "com.google.android.material:material:$materialThemeVersion"
|
||||
|
||||
// Custom Tabs
|
||||
implementation "saschpe.android:customtabs:$saschpeCustomTabs"
|
||||
implementation "androidx.browser:browser:$browserVersion"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
# for DexGuard only
|
||||
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
|
||||
@@ -0,0 +1,6 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="aculix.core">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,17 @@
|
||||
package aculix.core.base
|
||||
|
||||
import aculix.core.extensions.toast
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
/**
|
||||
* Base Fragment which is extended by other fragments
|
||||
* in the app
|
||||
*/
|
||||
open class BaseFragment : Fragment() {
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package aculix.core.base
|
||||
|
||||
import aculix.core.R
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
|
||||
/**
|
||||
* BottomSheetDialogFragment that uses a custom
|
||||
* theme which sets a rounded background to the dialog
|
||||
* and doesn't dim the navigation bar
|
||||
*/
|
||||
open class RoundedBottomSheetDialogFragment : BottomSheetDialogFragment() {
|
||||
|
||||
override fun getTheme(): Int = R.style.BottomSheetDialogTheme
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = BottomSheetDialog(requireContext(), theme)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
import android.widget.ProgressBar
|
||||
import androidx.annotation.StringRes
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
||||
/**
|
||||
* Button enabling/disabling modifiers
|
||||
*/
|
||||
fun MaterialButton.disableButton() {
|
||||
isEnabled = false
|
||||
}
|
||||
|
||||
fun MaterialButton.enableButton() {
|
||||
isEnabled = true
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disables the button and hides the text. Shows the progressbar inside
|
||||
* the button
|
||||
*/
|
||||
fun MaterialButton.showProgressBarInButton(progressBar: ProgressBar) {
|
||||
text = ""
|
||||
disableButton()
|
||||
progressBar.makeVisible()
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the button and shows the button text. Hides the progressbar
|
||||
* from the button
|
||||
*/
|
||||
fun MaterialButton.hideProgressBarFromButton(progressBar: ProgressBar, @StringRes buttonText: Int) {
|
||||
progressBar.makeInvisible()
|
||||
text = resources.getString(buttonText)
|
||||
enableButton()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
import com.google.android.material.chip.Chip
|
||||
|
||||
fun Chip.check() {
|
||||
isChecked = true
|
||||
}
|
||||
|
||||
fun Chip.unCheck() {
|
||||
isChecked = false
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
|
||||
import aculix.core.R
|
||||
import android.app.Activity
|
||||
import android.app.DownloadManager
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.util.DisplayMetrics
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.core.content.ContextCompat
|
||||
import saschpe.android.customtabs.CustomTabsHelper
|
||||
import saschpe.android.customtabs.WebViewFallback
|
||||
|
||||
|
||||
/**
|
||||
* Relaunches the current activity
|
||||
*/
|
||||
fun Context.relaunchActivity(context: Activity, intent: Intent) {
|
||||
context.finish()
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the toast message
|
||||
*/
|
||||
fun Context.toast(message: String, length: Int = Toast.LENGTH_SHORT) {
|
||||
Toast.makeText(this, message, length).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the passed URL in the Chrome Custom Tabs
|
||||
*/
|
||||
fun Context.openUrl(url: String, @ColorRes toolbarColor: Int) {
|
||||
val customTabsIntent = CustomTabsIntent.Builder()
|
||||
.addDefaultShareMenuItem()
|
||||
.setToolbarColor(ContextCompat.getColor(this, toolbarColor))
|
||||
.setShowTitle(true)
|
||||
.build()
|
||||
|
||||
// This is optional but recommended
|
||||
CustomTabsHelper.addKeepAliveExtra(this, customTabsIntent.intent)
|
||||
|
||||
CustomTabsHelper.openCustomTab(
|
||||
this,
|
||||
customTabsIntent,
|
||||
Uri.parse(url),
|
||||
WebViewFallback() // Opens in system browser if Chrome isn't installed on device
|
||||
)
|
||||
}
|
||||
|
||||
fun Context.openAppInGooglePlay(appPackageName: String) {
|
||||
try {
|
||||
// Try to open in the Google Play app
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$appPackageName")))
|
||||
} catch (exception: android.content.ActivityNotFoundException) {
|
||||
// Google Play app is not installed. Open URL in the browser.
|
||||
openUrl("https://play.google.com/store/apps/details?id=$appPackageName", R.color.customTabToolbarColor)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.copyTextToClipboard(textToCopy: String, textCopiedMessage: String) {
|
||||
val clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipData = ClipData.newPlainText("Copied Text", textToCopy)
|
||||
clipboardManager.setPrimaryClip(clipData)
|
||||
toast(textCopiedMessage)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun Context.isInternetAvailable(): Boolean {
|
||||
var result = false
|
||||
|
||||
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
cm.run {
|
||||
cm.getNetworkCapabilities(cm.activeNetwork)?.run {
|
||||
result = when {
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cm.run {
|
||||
cm.activeNetworkInfo?.run {
|
||||
if (type == ConnectivityManager.TYPE_WIFI) {
|
||||
result = true
|
||||
} else if (type == ConnectivityManager.TYPE_MOBILE) {
|
||||
result = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an Intent for sharing text
|
||||
*/
|
||||
fun Context.startShareTextIntent(shareTitle: String, shareText: String) {
|
||||
val shareIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_TEXT, shareText)
|
||||
type = "text/plain"
|
||||
}
|
||||
|
||||
startActivity(Intent.createChooser(shareIntent, shareTitle))
|
||||
}
|
||||
|
||||
fun Context.startEmailIntent(toEmail: String, emailSubject: String?) {
|
||||
// Open Email app with subject and to field pre-filled
|
||||
val emailIntent = Intent(Intent.ACTION_SENDTO).apply {
|
||||
data = Uri.parse("mailto:$toEmail") // only email apps should handle this
|
||||
putExtra(Intent.EXTRA_SUBJECT, emailSubject) // Email subject
|
||||
}
|
||||
|
||||
// Check if an Email app is installed on the device
|
||||
if (emailIntent.resolveActivity(packageManager) != null) {
|
||||
startActivity(emailIntent)
|
||||
} else {
|
||||
toast(getString(R.string.text_no_email_app_found))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.widget.EditText
|
||||
|
||||
/**
|
||||
* Adds TextWatcher to the EditText
|
||||
*/
|
||||
fun EditText.onTextChanged(listener: (String) -> Unit) {
|
||||
this.addTextChangedListener(object : TextWatcher {
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
listener(s.toString())
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||
// We only need the value of EditText after the user stops typing
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
// We only need the value of EditText after the user stops typing
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
import aculix.core.helper.BaseViewModelFactory
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.webkit.URLUtil
|
||||
import android.widget.ImageView
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModel
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Checks if the passed permissions are granted or not
|
||||
*
|
||||
* @param permissions List of permissions to be checked
|
||||
*/
|
||||
fun Fragment.hasPermissions(context: Context?, vararg permissions: String): Boolean {
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null) {
|
||||
for (permission in permissions) {
|
||||
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun Fragment.isInternetAvailable(context: Context): Boolean {
|
||||
var result = false
|
||||
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
cm.run {
|
||||
cm.getNetworkCapabilities(cm.activeNetwork)?.run {
|
||||
result = when {
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cm.run {
|
||||
cm.activeNetworkInfo?.run {
|
||||
if (type == ConnectivityManager.TYPE_WIFI) {
|
||||
result = true
|
||||
} else if (type == ConnectivityManager.TYPE_MOBILE) {
|
||||
result = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
|
||||
/**
|
||||
* Converts a Vector drawable to a Bitmap
|
||||
*
|
||||
* @param tintColor Tint color to be applied to the Vector drawable
|
||||
*
|
||||
*@return Converted Bitmap
|
||||
*/
|
||||
fun Int.toBitmap(context: Context, @ColorRes tintColor: Int? = null): Bitmap? {
|
||||
|
||||
// retrieve the actual drawable
|
||||
val drawable = ContextCompat.getDrawable(context, this) ?: return null
|
||||
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
|
||||
val bm = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
|
||||
|
||||
// add the tint if it exists
|
||||
tintColor?.let {
|
||||
DrawableCompat.setTint(drawable, ContextCompat.getColor(context, it))
|
||||
}
|
||||
// draw it onto the bitmap
|
||||
val canvas = Canvas(bm)
|
||||
drawable.draw(canvas)
|
||||
return bm
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* Formats the number in thousands, millions, billions etc.
|
||||
*/
|
||||
@SuppressLint("DefaultLocale")
|
||||
fun Long.getFormattedNumberInString(): String {
|
||||
if (this < 1000) return this.toString()
|
||||
val exp = (ln(this.toDouble()) / ln(1000.0)).toInt()
|
||||
return java.lang.String.format(
|
||||
"%.1f %c",
|
||||
this / 1000.0.pow(exp.toDouble()),
|
||||
"KMBTPE"[exp - 1]
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
/**
|
||||
* Creates a 64 bit hash string from the given charsequences
|
||||
* @hide
|
||||
*/
|
||||
fun CharSequence.to64BitHash(): Long {
|
||||
var result = -0x340d631b7bdddcdbL
|
||||
val len = this.length
|
||||
for (i in 0 until len) {
|
||||
result = result xor this[i].toLong()
|
||||
result *= 0x100000001b3L
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.annotation.StringRes
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
/**
|
||||
* Visibility modifiers and check functions
|
||||
*/
|
||||
|
||||
fun View.isVisibile(): Boolean = this.visibility == View.VISIBLE
|
||||
|
||||
fun View.isGone(): Boolean = this.visibility == View.GONE
|
||||
|
||||
fun View.isInvisible(): Boolean = this.visibility == View.INVISIBLE
|
||||
|
||||
fun View.makeVisible() {
|
||||
this.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun View.makeGone() {
|
||||
this.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun View.makeInvisible() {
|
||||
this.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the soft input keyboard from the screen
|
||||
*/
|
||||
fun View.dismissKeyboard(context: Context?) {
|
||||
val inputMethodManager =
|
||||
context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(this.windowToken, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the soft keyboard on the screen
|
||||
*/
|
||||
fun View.showKeyboard(context: Context?) {
|
||||
val inputMethodManager =
|
||||
context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.showSoftInput(this, InputMethodManager.SHOW_FORCED)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension functions to show Snackbar along with the action
|
||||
*/
|
||||
inline fun View.showSnackbar(
|
||||
@StringRes messageRes: Int, length: Int = Snackbar.LENGTH_LONG,
|
||||
f: Snackbar.() -> Unit
|
||||
) {
|
||||
showSnackbar(resources.getString(messageRes), length, f)
|
||||
}
|
||||
|
||||
inline fun View.showSnackbar(
|
||||
message: String,
|
||||
length: Int = Snackbar.LENGTH_LONG,
|
||||
f: Snackbar.() -> Unit
|
||||
) {
|
||||
val snack = Snackbar.make(this, message, length)
|
||||
snack.f()
|
||||
snack.show()
|
||||
}
|
||||
|
||||
fun Snackbar.action(@StringRes actionRes: Int, color: Int? = null, listener: (View) -> Unit) {
|
||||
action(view.resources.getString(actionRes), color, listener)
|
||||
}
|
||||
|
||||
fun Snackbar.action(action: String, color: Int? = null, listener: (View) -> Unit) {
|
||||
setAction(action, listener)
|
||||
color?.let { setActionTextColor(color) }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package aculix.core.extensions
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
||||
// Inflates the layout in RecyclerView Adapter
|
||||
fun ViewGroup.inflate(layoutRes: Int): View {
|
||||
return LayoutInflater.from(context).inflate(layoutRes,this, false);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package aculix.core.helper
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
||||
/**
|
||||
* ViewModel factory to create ViewModels and also allows to pass
|
||||
* values to the ViewModel constructor
|
||||
*/
|
||||
class BaseViewModelFactory<T>(val creator: () -> T) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return creator() as T
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package aculix.core.helper
|
||||
|
||||
/**
|
||||
* An app wide wrapper class that is returned by the Livedata as a result
|
||||
* and can be used with when expression in an activity or fragment
|
||||
*/
|
||||
sealed class ResultWrapper {
|
||||
|
||||
object Loading : ResultWrapper()
|
||||
|
||||
data class Error(val errorMessage: String) : ResultWrapper()
|
||||
|
||||
data class Success<T>(val data: T) : ResultWrapper()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package aculix.core.helper
|
||||
|
||||
import aculix.core.R
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
|
||||
class SimpleDividerItemDecoration(context: Context, private val paddingLeft: Int = 16, private val paddingRight: Int = 16) : RecyclerView.ItemDecoration() {
|
||||
|
||||
private val mDivider: Drawable? = ContextCompat.getDrawable(context, R.drawable.bg_line_divider)
|
||||
private val density = context.resources.displayMetrics.density
|
||||
|
||||
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
||||
val left = Math.round(density * paddingLeft)
|
||||
val right = parent.width - Math.round(density * paddingRight)
|
||||
|
||||
val childCount = parent.childCount
|
||||
for (i in 0 until childCount) {
|
||||
val child = parent.getChildAt(i)
|
||||
|
||||
val params = child.layoutParams as RecyclerView.LayoutParams
|
||||
|
||||
val top = child.bottom + params.bottomMargin
|
||||
val bottom = top + mDivider!!.intrinsicHeight
|
||||
|
||||
mDivider.setBounds(left, top, right, bottom)
|
||||
mDivider.draw(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="1417.32"
|
||||
android:viewportHeight="1417.32">
|
||||
<path
|
||||
android:pathData="M0,0h1417.32v1417.32h-1417.32z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="4.07"
|
||||
android:startX="1226.85"
|
||||
android:endY="1508.85"
|
||||
android:endX="120.16"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FFE27C3A"/>
|
||||
<item android:offset="0.24" android:color="#FFE57735"/>
|
||||
<item android:offset="0.54" android:color="#FFEC6926"/>
|
||||
<item android:offset="0.86" android:color="#FFF8530D"/>
|
||||
<item android:offset="1" android:color="#FFFF4600"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners
|
||||
android:topLeftRadius="@dimen/bottom_sheet_corner_radius"
|
||||
android:topRightRadius="@dimen/bottom_sheet_corner_radius" />
|
||||
|
||||
<solid android:color="?attr/colorSurface" />
|
||||
</shape>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<size
|
||||
android:width="1dp"
|
||||
android:height="1dp" />
|
||||
|
||||
<solid android:color="#eeeeee" />
|
||||
</shape>
|
||||
@@ -0,0 +1,33 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="2115.403"
|
||||
android:viewportHeight="2115.403">
|
||||
<group android:translateX="349.0415"
|
||||
android:translateY="349.0415">
|
||||
<path
|
||||
android:pathData="M1006.08,989.14H356.68a133,133 0,0 1,-107 -212l96.12,-130.13A474.78,474.78 0,0 1,727.72 454.37h278.36a22.21,22.21 0,0 1,0 44.41H727.72A430.38,430.38 0,0 0,381.57 673.43L285.45,803.56c-20.28,27.46 -23.21,62 -7.83,92.51s44.93,48.67 79.06,48.67h649.4a22.2,22.2 0,0 1,0 44.4Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M388.13,735.9l53.27,-69.74s108,-127.08 247.33,-127.08h22.32c14,0 18.19,19 5.54,24.85 -57.72,26.79 -132.5,77.93 -145,166A31.26,31.26 0,0 1,542.15 757l-139.89,6A16.87,16.87 0,0 1,388.13 735.9Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M1071.9,587.2H856.52a22.21,22.21 0,1 1,0 -44.41H1071.9a22.21,22.21 0,0 1,0 44.41Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M923.82,691.71H782.39a22.21,22.21 0,0 1,0 -44.41H923.82a22.21,22.21 0,1 1,0 44.41Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M1171.52,691.71H1006.08a22.21,22.21 0,1 1,0 -44.41h165.44a22.21,22.21 0,0 1,0 44.41Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M1133.82,796.22H832.28a22.21,22.21 0,0 1,0 -44.41h301.54a22.21,22.21 0,1 1,0 44.41Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M902.29,900.73h-70a22.21,22.21 0,0 1,0 -44.41h70a22.21,22.21 0,0 1,0 44.41Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M1133.82,900.73H983.05a22.21,22.21 0,0 1,0 -44.41h150.77a22.21,22.21 0,1 1,0 44.41Z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.9,13.98l2.1,2.53 3.1,-3.99c0.2,-0.26 0.6,-0.26 0.8,0.01l3.51,4.68c0.25,0.33 0.01,0.8 -0.4,0.8H6.02c-0.42,0 -0.65,-0.48 -0.39,-0.81L8.12,14c0.19,-0.26 0.57,-0.27 0.78,-0.02z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:inset="16dp">
|
||||
<layer-list>
|
||||
<item android:drawable="@drawable/ic_place_holder" />
|
||||
</layer-list>
|
||||
|
||||
</inset>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="customTabToolbarColor">#212121</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- BottomSheet -->
|
||||
<dimen name="bottom_sheet_corner_radius">16dp</dimen>
|
||||
<dimen name="bottom_sheet_top_padding">16dp</dimen>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<resources>
|
||||
<string name="app_name">Core</string>
|
||||
<string name="text_no_email_app_found">No Email application installed on the device</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- BottomSheet -->
|
||||
<style name="BottomSheet" parent="@style/Widget.MaterialComponents.BottomSheet.Modal">
|
||||
<item name="android:background">@drawable/bg_bottom_sheet</item>
|
||||
</style>
|
||||
|
||||
<style name="BaseBottomSheetDialog" parent="@style/Theme.MaterialComponents.BottomSheetDialog">
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="bottomSheetStyle">@style/BottomSheet</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomSheetDialogTheme" parent="BaseBottomSheetDialog" >
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
Reference in New Issue
Block a user