Updated on 2026-08-14
This commit is contained in:
parent
baaa317381
commit
ca51d6803a
13 changed files with 198 additions and 36 deletions
|
|
@ -16,9 +16,16 @@ fun <T> MutableList<T>.removeBy(predicate: (T) -> Boolean): Boolean {
|
|||
return toRemove.isNotEmpty()
|
||||
}
|
||||
|
||||
fun <T> MutableList<T>.replaceBy(item: T, predicate: (T) -> Boolean) {
|
||||
fun <T> MutableList<T>.replaceBy(item: T, predicate: (T) -> Boolean): Boolean {
|
||||
val toRemove = this.filter(predicate)
|
||||
if (toRemove.isEmpty()) return false
|
||||
|
||||
val indexes = toRemove.map { indexOf(it) }
|
||||
this.removeAll(toRemove)
|
||||
indexes.forEach { this.add(it, item) }
|
||||
return true
|
||||
}
|
||||
|
||||
fun <T> MutableList<T>.replaceByOrAdd(item: T, predicate: (T) -> Boolean) {
|
||||
if (!replaceBy(item, predicate)) add(item)
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
suspend fun <T> withMainContext(block: suspend CoroutineScope.() -> T) {
|
||||
withContext(Dispatchers.Main, block)
|
||||
}
|
||||
|
||||
suspend fun <T> withIOContext(block: suspend CoroutineScope.() -> T) {
|
||||
withContext(Dispatchers.IO, block)
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ import com.tangem.tap.features.details.ui.walletconnect.WalletConnectSessionsFra
|
|||
import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
|
||||
import com.tangem.tap.features.home.HomeFragment
|
||||
import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment
|
||||
import com.tangem.tap.features.onboarding.products.old.OnboardingOtherCardsFragment
|
||||
import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCardsFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.OnboardingWalletFragment
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.tokens.ui.AddTokensFragment
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.common.extensions
|
|||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -32,6 +33,27 @@ fun Store<*>.dispatchToastNotification(resId: Int) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fun Store<*>.dispatchErrorNotification(error: TapError) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
store.dispatch(GlobalAction.ShowErrorNotification(error))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fatal used to indicate errors that should not normally have occurred
|
||||
*/
|
||||
fun Store<*>.dispatchDebugErrorNotification(message: String, fatal: Boolean = false) {
|
||||
val prefix = if (fatal) "FATAL ERROR: " else "DEBUG ERROR: "
|
||||
dispatchDebugErrorNotification(TapError.CustomError("$prefix $message"))
|
||||
}
|
||||
|
||||
fun Store<*>.dispatchDebugErrorNotification(error: TapError) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
store.dispatch(GlobalAction.DebugShowErrorNotification(error))
|
||||
}
|
||||
}
|
||||
|
||||
fun Store<*>.dispatchDialogShow(dialog: StateDialog) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
store.dispatch(GlobalAction.ShowDialog(dialog))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewParent
|
||||
import androidx.core.view.forEach
|
||||
|
|
@ -15,11 +16,8 @@ import timber.log.Timber
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun ViewGroup.inflate(viewToInflate: Int, rootView: ViewGroup?, parent: ViewGroup) {
|
||||
if (rootView == null) {
|
||||
val inflatedView = LayoutInflater.from(context).inflate(viewToInflate, rootView)
|
||||
parent.addView(inflatedView)
|
||||
}
|
||||
fun ViewGroup.inflate(viewToInflate: Int, attachToRoot: Boolean = false): View {
|
||||
return LayoutInflater.from(context).inflate(viewToInflate, this, attachToRoot)
|
||||
}
|
||||
|
||||
fun ViewParent?.beginDelayedTransition(transition: Transition = AutoTransition()) {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import java.lang.ref.WeakReference
|
|||
sealed class NavigationAction : Action {
|
||||
data class NavigateTo(
|
||||
val screen: AppScreen,
|
||||
val addToBackstack: Boolean = true,
|
||||
val fragmentShareTransition: FragmentShareTransition? = null
|
||||
val fragmentShareTransition: FragmentShareTransition? = null,
|
||||
val addToBackstack: Boolean = true
|
||||
) : NavigationAction()
|
||||
|
||||
data class PopBackTo(val screen: AppScreen? = null) : NavigationAction()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
package com.tangem.tap.common.toggleWidget
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.*
|
||||
import android.widget.ViewSwitcher
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.wallet.R
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class RefreshBalanceWidget(
|
||||
private val root: ViewGroup
|
||||
) : ViewStateWidget {
|
||||
|
||||
var isShowing: Boolean? = null
|
||||
private set
|
||||
|
||||
override val mainView: View = root.findViewById(R.id.btn_refresh_balance)
|
||||
|
||||
|
||||
private val viewSwitcher: ViewSwitcher by lazy { mainView.findViewById(R.id.switcher_refresh_arrow_to_progress) }
|
||||
|
||||
private val arrowView = mainView.findViewById<View>(R.id.imv_arrow_refresh)
|
||||
|
||||
private var progressViewAnimation: Animation? = null
|
||||
|
||||
init {
|
||||
viewSwitcher.inAnimation = AlphaAnimation(0f, 1f).apply {
|
||||
duration = 400
|
||||
interpolator = LinearInterpolator()
|
||||
}
|
||||
viewSwitcher.outAnimation = AlphaAnimation(1f, 0f).apply {
|
||||
duration = 400
|
||||
interpolator = LinearInterpolator()
|
||||
}
|
||||
}
|
||||
|
||||
override fun changeState(state: WidgetState) {
|
||||
val progressState = state as? ProgressState ?: return
|
||||
|
||||
val currentStateByView = getState()
|
||||
|
||||
if (progressState == currentStateByView) return
|
||||
|
||||
animateState(progressState)
|
||||
viewSwitcher.showNext()
|
||||
|
||||
}
|
||||
|
||||
private fun animateState(state: ProgressState) {
|
||||
when (state) {
|
||||
ProgressState.Done, ProgressState.Error -> {
|
||||
progressViewAnimation?.cancel()
|
||||
}
|
||||
ProgressState.Loading -> {
|
||||
val animation = RotateAnimation(
|
||||
0f, 360f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f
|
||||
)
|
||||
animation.duration = 700
|
||||
animation.interpolator = AccelerateInterpolator()
|
||||
animation.repeatCount = -1
|
||||
arrowView.startAnimation(animation)
|
||||
progressViewAnimation = animation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun show(show: Boolean) {
|
||||
if (show == isShowing) return
|
||||
|
||||
isShowing = show
|
||||
if (show) {
|
||||
mainView.startAnimation(ShowAnimation())
|
||||
} else {
|
||||
mainView.startAnimation(AlphaAnimation(1f, 0f).apply { fillAfter = true })
|
||||
}
|
||||
}
|
||||
|
||||
private fun isArrowRefreshActive(): Boolean = viewSwitcher.currentView.id == R.id.fl_arrow_refresh_container
|
||||
|
||||
private fun getState(): ProgressState = if (isArrowRefreshActive()) ProgressState.Done else ProgressState.Loading
|
||||
}
|
||||
|
||||
class ShowAnimation : AnimationSet(true) {
|
||||
init {
|
||||
addAnimation(ScaleAnimation(
|
||||
0f, 1f,
|
||||
0f, 1f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f)
|
||||
)
|
||||
addAnimation(AlphaAnimation(0f, 1f))
|
||||
duration = 300
|
||||
interpolator = AnticipateOvershootInterpolator()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
package com.tangem.tap.common.transitions
|
||||
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.ChangeImageTransform
|
||||
import androidx.transition.TransitionSet
|
||||
import androidx.transition.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -10,18 +8,37 @@ import androidx.transition.TransitionSet
|
|||
class FrontCardEnterTransition : TransitionSet() {
|
||||
init {
|
||||
ordering = ORDERING_TOGETHER;
|
||||
addTransition(ChangeImageTransform())
|
||||
addTransition(ChangeBounds())
|
||||
// addTransition(Fade())
|
||||
// addTransition(Fade(Visibility.MODE_IN))
|
||||
// addTransition(ChangeTransform())
|
||||
addTransition(Fade())
|
||||
addTransition(ChangeImageTransform()) // изменения внутри ImageView
|
||||
addTransition(ChangeTransform()) // изменение размеров, углов накона
|
||||
addTransition(ChangeBounds()) // изменение положения
|
||||
}
|
||||
}
|
||||
|
||||
class FrontCardExitTransition : TransitionSet() {
|
||||
init {
|
||||
ordering = ORDERING_TOGETHER;
|
||||
addTransition(Fade())
|
||||
addTransition(ChangeImageTransform())
|
||||
addTransition(ChangeTransform())
|
||||
addTransition(ChangeBounds())
|
||||
}
|
||||
}
|
||||
|
||||
class HomeToOnboardingTransition : TransitionSet() {
|
||||
init {
|
||||
ordering = ORDERING_TOGETHER;
|
||||
addTransition(Fade())
|
||||
addTransition(ChangeTransform())
|
||||
addTransition(ChangeBounds())
|
||||
}
|
||||
}
|
||||
|
||||
class InternalNoteLayoutTransition : TransitionSet() {
|
||||
init {
|
||||
ordering = ORDERING_TOGETHER;
|
||||
addTransition(ChangeTransform())
|
||||
addTransition(ChangeBounds())
|
||||
addTransition(Fade())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue