Updated on 2026-08-14
This commit is contained in:
parent
e83c9bc495
commit
2b768f1b00
784 changed files with 2066 additions and 106417 deletions
|
|
@ -0,0 +1,3 @@
|
|||
package com.tangem.tap.common.entities
|
||||
|
||||
abstract class Button(val enabled: Boolean)
|
||||
15
app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt
Normal file
15
app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
fun Bitmap.toByteArray(): ByteArray {
|
||||
val stream = ByteArrayOutputStream()
|
||||
this.compress(Bitmap.CompressFormat.JPEG, 20, stream)
|
||||
return stream.toByteArray()
|
||||
}
|
||||
|
||||
fun ByteArray.toBitmap(): Bitmap {
|
||||
return BitmapFactory.decodeByteArray(this, 0, this.size)
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.features.home.HomeFragment
|
||||
import com.tangem.tap.features.wallet.ui.WalletFragment
|
||||
import com.tangem.wallet.R
|
||||
|
||||
fun FragmentActivity.openFragment(screen: AppScreen, addToBackStack: Boolean = true) {
|
||||
val transaction = this.supportFragmentManager.beginTransaction()
|
||||
.replace(
|
||||
R.id.fragment_container,
|
||||
fragmentFactory(screen),
|
||||
screen.name
|
||||
)
|
||||
if (addToBackStack && screen != AppScreen.Home) transaction.addToBackStack(null)
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
fun FragmentActivity.popBackTo(screen: AppScreen?, inclusive: Boolean = false) {
|
||||
val inclusiveFlag = if (inclusive) FragmentManager.POP_BACK_STACK_INCLUSIVE else 0
|
||||
this.supportFragmentManager.popBackStack(screen?.name, inclusiveFlag)
|
||||
}
|
||||
|
||||
fun FragmentActivity.getPreviousScreen(): AppScreen? {
|
||||
val indexOfLastFragment = this.supportFragmentManager.backStackEntryCount - 1
|
||||
val tag = this.supportFragmentManager.getBackStackEntryAt(indexOfLastFragment).name
|
||||
return tag?.let { AppScreen.valueOf(tag) }
|
||||
}
|
||||
|
||||
private fun fragmentFactory(screen: AppScreen): Fragment {
|
||||
return when (screen) {
|
||||
AppScreen.Home -> HomeFragment()
|
||||
AppScreen.Wallet -> WalletFragment()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.EncodeHintType
|
||||
import com.google.zxing.qrcode.QRCodeWriter
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
|
||||
import java.util.*
|
||||
|
||||
|
||||
fun String.toQrCode(): Bitmap {
|
||||
val hintMap = Hashtable<EncodeHintType, Any>()
|
||||
hintMap[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M // H = 30% damage
|
||||
hintMap[EncodeHintType.MARGIN] = 2
|
||||
|
||||
val qrCodeWriter = QRCodeWriter()
|
||||
|
||||
val size = 256
|
||||
|
||||
val bitMatrix = qrCodeWriter.encode(this, BarcodeFormat.QR_CODE, size, size, hintMap)
|
||||
val width = bitMatrix.width
|
||||
val bmp = Bitmap.createBitmap(width, width, Bitmap.Config.RGB_565)
|
||||
for (x in 0 until width) {
|
||||
for (y in 0 until width) {
|
||||
bmp.setPixel(y, x, if (bitMatrix.get(x, y)) Color.BLACK else Color.WHITE)
|
||||
}
|
||||
}
|
||||
return bmp
|
||||
}
|
||||
127
app/src/main/java/com/tangem/tap/common/extensions/UI.kt
Normal file
127
app/src/main/java/com/tangem/tap/common/extensions/UI.kt
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.text.Spannable
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
||||
fun Fragment.getDrawable(@DrawableRes drawableResId: Int): Drawable? {
|
||||
return ContextCompat.getDrawable(requireContext(), drawableResId)
|
||||
}
|
||||
|
||||
fun View.show(show: Boolean) {
|
||||
if (show) this.visibility = View.VISIBLE else this.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun View.show() {
|
||||
this.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun View.hide() {
|
||||
this.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun View.makeInvisible() {
|
||||
this.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
fun Context.dpToPixels(dp: Int): Int =
|
||||
TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), this.resources.displayMetrics
|
||||
).toInt()
|
||||
|
||||
fun MaterialCardView.setMargins(
|
||||
marginLeftDp: Int = 16,
|
||||
marginTopDp: Int = 8,
|
||||
marginRightDp: Int = 16,
|
||||
marginBottomDp: Int = 8
|
||||
) {
|
||||
val params = this.layoutParams
|
||||
(params as ViewGroup.MarginLayoutParams).setMargins(
|
||||
context.dpToPixels(marginLeftDp),
|
||||
context.dpToPixels(marginTopDp),
|
||||
context.dpToPixels(marginRightDp),
|
||||
context.dpToPixels(marginBottomDp)
|
||||
)
|
||||
this.layoutParams = params
|
||||
}
|
||||
|
||||
fun Activity.setSystemBarTextColor(setTextDark: Boolean) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val flags = this.window.decorView.systemUiVisibility
|
||||
// Update the SystemUiVisibility dependening on whether we want a Light or Dark theme.
|
||||
this.window.decorView.systemUiVisibility =
|
||||
if (setTextDark) {
|
||||
flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
|
||||
} else {
|
||||
flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun String.colorSegment(
|
||||
context: Context,
|
||||
color: Int,
|
||||
startIndex: Int = 0,
|
||||
endIndex: Int = this.length
|
||||
): Spannable {
|
||||
return this.toSpannable()
|
||||
.also { spannable ->
|
||||
spannable.setSpan(
|
||||
ForegroundColorSpan(ContextCompat.getColor(context, color)),
|
||||
startIndex,
|
||||
endIndex,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun View.hideKeyboard() {
|
||||
val inputMethodManager = context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
inputMethodManager?.hideSoftInputFromWindow(this.windowToken, 0)
|
||||
}
|
||||
|
||||
fun Context.copyToClipboard(value: Any, label: String = "") {
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager ?: return
|
||||
|
||||
val clip: ClipData = ClipData.newPlainText(label, value.toString())
|
||||
clipboard.setPrimaryClip(clip)
|
||||
}
|
||||
|
||||
fun Context.shareText(text: String) {
|
||||
val sendIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_TEXT, text)
|
||||
type = "text/plain"
|
||||
}
|
||||
val shareIntent = Intent.createChooser(sendIntent, null)
|
||||
startActivity(shareIntent)
|
||||
}
|
||||
|
||||
fun Fragment.shareText(text: String) {
|
||||
requireContext().shareText(text)
|
||||
}
|
||||
|
||||
fun ViewGroup.inflate(viewToInflate: Int, rootView: ViewGroup?, parent: ViewGroup) {
|
||||
if (rootView == null) {
|
||||
val inflatedView = LayoutInflater.from(context).inflate(viewToInflate, rootView)
|
||||
parent.addView(inflatedView)
|
||||
}
|
||||
}
|
||||
19
app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt
Normal file
19
app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.tap.common.redux.navigation.navigationReducer
|
||||
import com.tangem.tap.features.wallet.redux.walletReducer
|
||||
import org.rekotlin.Action
|
||||
|
||||
fun appReducer(action: Action, state: AppState?): AppState {
|
||||
requireNotNull(state)
|
||||
if (action is AppAction.RestoreState) return action.state
|
||||
return AppState(
|
||||
navigationState = navigationReducer(action, state),
|
||||
// homeState = homeReducer(action, state),
|
||||
walletState = walletReducer(action, state),
|
||||
)
|
||||
}
|
||||
|
||||
sealed class AppAction : Action {
|
||||
data class RestoreState(val state: AppState) : AppAction()
|
||||
}
|
||||
25
app/src/main/java/com/tangem/tap/common/redux/AppState.kt
Normal file
25
app/src/main/java/com/tangem/tap/common/redux/AppState.kt
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.tap.common.redux.navigation.NavigationState
|
||||
import com.tangem.tap.common.redux.navigation.navigationMiddleware
|
||||
import com.tangem.tap.features.home.redux.homeMiddleware
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.redux.walletMiddleware
|
||||
import org.rekotlin.Middleware
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class AppState(
|
||||
val navigationState: NavigationState = NavigationState(),
|
||||
val walletState: WalletState = WalletState()
|
||||
) : StateType {
|
||||
|
||||
companion object {
|
||||
fun getMiddleware(): List<Middleware<AppState>> {
|
||||
return listOf(
|
||||
navigationMiddleware, notificationsMiddleware,
|
||||
homeMiddleware, walletMiddleware,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.TangemError
|
||||
import com.tangem.tap.notificationsHandler
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class NotificationsHandler(coordinatorLayout: CoordinatorLayout) {
|
||||
private val coordinatorLayoutWeak = WeakReference(coordinatorLayout)
|
||||
|
||||
fun showNotification(message: String) {
|
||||
coordinatorLayoutWeak.get()?.let { layout ->
|
||||
Snackbar.make(layout, message, Snackbar.LENGTH_LONG)
|
||||
.also { snackbar -> snackbar.show() }
|
||||
}
|
||||
}
|
||||
|
||||
fun showNotification(message: Int) {
|
||||
coordinatorLayoutWeak.get()?.let {
|
||||
showNotification(it.context.getString(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val notificationsMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
if (action is NotificationAction) {
|
||||
notificationsHandler?.showNotification(action.messageResource)
|
||||
}
|
||||
if (action is ErrorAction) {
|
||||
notificationsHandler?.showNotification(action.error.customMessage)
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface NotificationAction : Action {
|
||||
val messageResource: Int
|
||||
}
|
||||
|
||||
interface ErrorAction : Action {
|
||||
val error: TangemError
|
||||
}
|
||||
7
app/src/main/java/com/tangem/tap/common/redux/Request.kt
Normal file
7
app/src/main/java/com/tangem/tap/common/redux/Request.kt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import org.rekotlin.Action
|
||||
|
||||
abstract class Request : Action {
|
||||
abstract suspend fun execute()
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.tap.common.redux.navigation
|
||||
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import org.rekotlin.Action
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
sealed class NavigationAction : Action {
|
||||
data class NavigateTo(val screen: AppScreen, val addToBackstack: Boolean = true) :
|
||||
NavigationAction()
|
||||
|
||||
data class PopBackTo(val screen: AppScreen? = null) : NavigationAction()
|
||||
|
||||
data class ActivityCreated(val activity: WeakReference<FragmentActivity>) : NavigationAction()
|
||||
object ActivityDestroyed : NavigationAction()
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.tap.common.redux.navigation
|
||||
|
||||
import com.tangem.tap.common.extensions.openFragment
|
||||
import com.tangem.tap.common.extensions.popBackTo
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
val navigationMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
if (action is NavigationAction) {
|
||||
val navState = store.state.navigationState
|
||||
when (action) {
|
||||
is NavigationAction.NavigateTo -> {
|
||||
navState.activity?.get()?.openFragment(action.screen, action.addToBackstack)
|
||||
}
|
||||
is NavigationAction.PopBackTo -> {
|
||||
if (action.screen == AppScreen.Home) {
|
||||
navState.activity?.get()?.popBackTo(null, true)
|
||||
} else {
|
||||
navState.activity?.get()?.popBackTo(action.screen)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.common.redux.navigation
|
||||
|
||||
import com.tangem.tap.common.extensions.getPreviousScreen
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import org.rekotlin.Action
|
||||
|
||||
fun navigationReducer(action: Action, state: AppState): NavigationState {
|
||||
|
||||
val navigationAction = action as? NavigationAction ?: return state.navigationState
|
||||
val navState = state.navigationState
|
||||
|
||||
return when (navigationAction) {
|
||||
is NavigationAction.NavigateTo -> {
|
||||
navState.copy(backStack = navState.backStack + navigationAction.screen)
|
||||
}
|
||||
is NavigationAction.PopBackTo -> {
|
||||
val screen =
|
||||
navigationAction.screen ?: navState.activity?.get()?.getPreviousScreen()
|
||||
val index = navState.backStack.lastIndexOf(screen) + 1
|
||||
state.navigationState.copy(backStack = navState.backStack.subList(0, index))
|
||||
}
|
||||
is NavigationAction.ActivityCreated -> navState.copy(activity = navigationAction.activity)
|
||||
is NavigationAction.ActivityDestroyed -> navState.copy(activity = null)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.common.redux.navigation
|
||||
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import org.rekotlin.StateType
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
data class NavigationState(
|
||||
val backStack: List<AppScreen> = listOf(AppScreen.Home),
|
||||
val activity: WeakReference<FragmentActivity>? = null
|
||||
) : StateType
|
||||
|
||||
enum class AppScreen { Home, Wallet }
|
||||
Loading…
Add table
Add a link
Reference in a new issue