Skip to content

Commit

Permalink
[Fix-580] Components: remove some animations
Browse files Browse the repository at this point in the history
  • Loading branch information
robergro committed Oct 26, 2023
1 parent 34b061e commit 2a40401
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// UIView+ExecuteExtension.swift
// SparkCore
//
// Created by robin.lemaire on 26/10/2023.
// Copyright © 2023 Adevinta. All rights reserved.
//

import UIKit

extension UIView {

/// Execute a code with or without animation.
static func execute(
isAnimated: Bool,
withDuration duration: TimeInterval,
context: @escaping () -> Void,
completion: ((Bool) -> Void)? = nil
) {
if isAnimated {
UIView.animate(
withDuration: duration,
animations: context,
completion: completion)
} else {
context()
completion?(true)
}
}

/// Execute a code with or without transition animation.
static func execute(
with view: UIView,
isTransitionAnimated: Bool,
withDuration duration: TimeInterval,
options: UIView.AnimationOptions = [],
context: @escaping () -> Void,
completion: ((Bool) -> Void)? = nil
) {
if isTransitionAnimated {
UIView.transition(
with: view,
duration: duration,
options: options,
animations: context,
completion: completion)
} else {
context()
completion?(true)
}
}
}
35 changes: 20 additions & 15 deletions core/Sources/Components/Button/View/UIKit/ButtonUIView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ public final class ButtonUIView: UIView {
}
}

/// Button modifications should be animated or not. **True** by default.
public var isAnimated: Bool = true

// MARK: - Internal Properties

internal let viewModel: ButtonViewModel
Expand Down Expand Up @@ -572,11 +575,13 @@ public final class ButtonUIView: UIView {
let horizontalSpacing = self._horizontalSpacing.wrappedValue
let horizontalPadding = self._horizontalPadding.wrappedValue

let animationDuration = self.firstContentStackViewAnimation ? 0 : Constants.Animation.slowDuration
if verticalSpacing != self.contentStackViewTopConstraint?.constant ||
horizontalSpacing != self.contentStackViewLeadingConstraint?.constant ||
horizontalPadding != self.contentStackView.spacing {
UIView.animate(withDuration: animationDuration) { [weak self] in
UIView.execute(
isAnimated: self.isAnimated && !self.firstContentStackViewAnimation,
withDuration: Constants.Animation.slowDuration
) { [weak self] in
guard let self else { return }

self.firstContentStackViewAnimation = false
Expand Down Expand Up @@ -617,12 +622,11 @@ public final class ButtonUIView: UIView {

// Animate only if new alpha is different from current alpha
let alpha = state.opacity
if self.alpha != alpha {
UIView.animate(withDuration: Constants.Animation.slowDuration) { [weak self] in
UIView.execute(
isAnimated: self.isAnimated && self.alpha != alpha,
withDuration: Constants.Animation.slowDuration
) { [weak self] in
self?.alpha = alpha
}
} else {
self.alpha = alpha
}
}
// **
Expand All @@ -633,12 +637,11 @@ public final class ButtonUIView: UIView {
guard let self, let colors else { return }

// Background Color
if self.backgroundColor != colors.backgroundColor.uiColor {
UIView.animate(withDuration: Constants.Animation.fastDuration) { [weak self] in
self?.backgroundColor = colors.backgroundColor.uiColor
}
} else {
self.backgroundColor = colors.backgroundColor.uiColor
UIView.execute(
isAnimated: self.isAnimated && self.backgroundColor != colors.backgroundColor.uiColor,
withDuration: Constants.Animation.fastDuration
) { [weak self] in
self?.backgroundColor = colors.backgroundColor.uiColor
}

// Border Color
Expand Down Expand Up @@ -709,8 +712,10 @@ public final class ButtonUIView: UIView {
self.iconImageView.image = content.iconImage?.leftValue

// Subviews positions and visibilities
let animationDuration = self.firstContentStackViewSubviewAnimation ? 0 : Constants.Animation.slowDuration
UIView.animate(withDuration: animationDuration) { [weak self] in
UIView.execute(
isAnimated: self.isAnimated && !self.firstContentStackViewSubviewAnimation,
withDuration: Constants.Animation.slowDuration
) { [weak self] in
guard let self else { return }

self.firstContentStackViewSubviewAnimation = false
Expand Down
88 changes: 50 additions & 38 deletions core/Sources/Components/Switch/View/UIKit/SwitchUIView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,13 @@ public final class SwitchUIView: UIView {
}
}

/// The value of the switch.
/// The value of the switch (retrieve and set without animation).
public var isOn: Bool {
get {
return self.viewModel.isOn
}
set {
self.isOnAnimated = false
self.viewModel.set(isOn: newValue)
}
}
Expand All @@ -159,12 +160,13 @@ public final class SwitchUIView: UIView {
}
}

/// The state of the switch: enabled or not.
/// The state of the switch: enabled or not (retrieve and set without animation). .
public var isEnabled: Bool {
get {
return self.viewModel.isEnabled
}
set {
self.isEnabledAnimated = false
self.viewModel.set(isEnabled: newValue)
}
}
Expand Down Expand Up @@ -250,6 +252,9 @@ public final class SwitchUIView: UIView {
@ScaledUIMetric private var toggleSpacing: CGFloat = Constants.ToggleSizes.padding
@ScaledUIMetric private var toggleDotSpacing: CGFloat = Constants.toggleDotImagePadding

private var isEnabledAnimated: Bool = false
private var isOnAnimated: Bool = false

private var subscriptions = Set<AnyCancellable>()

// MARK: - Initialization
Expand Down Expand Up @@ -605,6 +610,20 @@ public final class SwitchUIView: UIView {
self.textLabel.heightAnchor.constraint(greaterThanOrEqualTo: self.toggleView.heightAnchor).isActive = true
}

// MARK: - Setter

/// Sets the state of the switch to the on or off position, optionally animating the transition.
public func setOn(_ isOn: Bool, animated: Bool) {
self.isOnAnimated = animated
self.viewModel.set(isOn: isOn)
}

/// Sets the enable status of the switch, optionally animating the color.
public func setEnabled(_ isEnabled: Bool, animated: Bool) {
self.isEnabledAnimated = animated
self.viewModel.set(isEnabled: isEnabled)
}

// MARK: - Actions

@objc private func toggleTapGestureAction(_ sender: UITapGestureRecognizer) {
Expand Down Expand Up @@ -702,14 +721,11 @@ public final class SwitchUIView: UIView {
guard let self, let toggleOpacity else { return }

// Animate only if new alpha is different from current alpha
let animated = self.toggleView.alpha != toggleOpacity

if animated {
UIView.animate(withDuration: Constants.animationDuration) { [weak self] in
self?.toggleView.alpha = toggleOpacity
}
} else {
self.toggleView.alpha = toggleOpacity
UIView.execute(
isAnimated: self.isEnabledAnimated && self.toggleView.alpha != toggleOpacity,
withDuration: Constants.animationDuration
) { [weak self] in
self?.toggleView.alpha = toggleOpacity
}
}
// **
Expand All @@ -722,12 +738,11 @@ public final class SwitchUIView: UIView {
// Animate only if there is currently an color on View and if new color is different from current color
let animated = self.toggleView.backgroundColor != nil && self.toggleView.backgroundColor != colorToken.uiColor

if animated {
UIView.animate(withDuration: Constants.animationDuration) { [weak self] in
self?.toggleView.backgroundColor = colorToken.uiColor
}
} else {
self.toggleView.backgroundColor = colorToken.uiColor
UIView.execute(
isAnimated: self.isOnAnimated && animated,
withDuration: Constants.animationDuration
) { [weak self] in
self?.toggleView.backgroundColor = colorToken.uiColor
}
}
self.viewModel.$toggleDotBackgroundColorToken.subscribe(in: &self.subscriptions) { [weak self] colorToken in
Expand All @@ -741,12 +756,11 @@ public final class SwitchUIView: UIView {
// Animate only if there is currently an color on View and if new color is different from current color
let animated = self.toggleDotImageView.tintColor != nil && self.toggleDotImageView.tintColor != colorToken.uiColor

if animated {
UIView.animate(withDuration: Constants.animationDuration) { [weak self] in
self?.toggleDotImageView.tintColor = colorToken.uiColor
}
} else {
self.toggleDotImageView.tintColor = colorToken.uiColor
UIView.execute(
isAnimated: self.isOnAnimated && animated,
withDuration: Constants.animationDuration
) { [weak self] in
self?.toggleDotImageView.tintColor = colorToken.uiColor
}
}
self.viewModel.$textForegroundColorToken.subscribe(in: &self.subscriptions) { [weak self] colorToken in
Expand Down Expand Up @@ -786,7 +800,10 @@ public final class SwitchUIView: UIView {
let currentUserInteraction = self.viewModel.isToggleInteractionEnabled ?? true
self.toggleView.isUserInteractionEnabled = false

UIView.animate(withDuration: Constants.animationDuration) { [weak self] in
UIView.execute(
isAnimated: self.isOnAnimated,
withDuration: Constants.animationDuration
) { [weak self] in
self?.toggleLeftSpaceView.isHidden = !showLeftSpace
self?.toggleRightSpaceView.isHidden = showLeftSpace
} completion: { [weak self] _ in
Expand All @@ -803,21 +820,16 @@ public final class SwitchUIView: UIView {
let image = toggleDotImagesState?.currentImage.leftValue

// Animate only if there is currently an image on ImageView and new image is exists
let animated = self.toggleDotImageView.image != nil && image != nil

if animated {
UIView.transition(
with: self.toggleDotImageView,
duration: Constants.animationDuration,
options: .transitionCrossDissolve,
animations: {
self.toggleDotImageView.image = image
},
completion: nil
)
} else {
self.toggleDotImageView.image = image
}
UIView.execute(
with: self.toggleDotImageView,
isTransitionAnimated: self.isOnAnimated && self.toggleDotImageView.image != nil && image != nil,
withDuration: Constants.animationDuration,
options: .transitionCrossDissolve,
context: {
self.toggleDotImageView.image = image
},
completion: nil
)
}

// Displayed Text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct ButtonComponentView: View {
@State private var alignment: ButtonAlignment = .leadingIcon
@State private var content: ButtonContentDefault = .text
@State private var isEnabled: CheckboxSelectionState = .selected
@State private var isAnimated: CheckboxSelectionState = .selected

@State private var shouldShowReverseBackgroundColor: Bool = false

Expand Down Expand Up @@ -102,7 +103,8 @@ struct ButtonComponentView: View {
shape: self.$shape.wrappedValue,
alignment: self.$alignment.wrappedValue,
content: self.$content.wrappedValue,
isEnabled: self.$isEnabled.wrappedValue == .selected
isEnabled: self.$isEnabled.wrappedValue == .selected,
isAnimated: self.$isAnimated.wrappedValue == .selected
)
.frame(width: geometry.size.width, height: self.uiKitViewHeight, alignment: .center)
.padding(.horizontal, self.shouldShowReverseBackgroundColor ? 4 : 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct ButtonComponentItemsUIView: UIViewRepresentable {
private let alignment: ButtonAlignment
private let content: ButtonContentDefault
private let isEnabled: Bool
private let isAnimated: Bool

// MARK: - Initialization

Expand All @@ -42,7 +43,8 @@ struct ButtonComponentItemsUIView: UIViewRepresentable {
shape: ButtonShape,
alignment: ButtonAlignment,
content: ButtonContentDefault,
isEnabled: Bool
isEnabled: Bool,
isAnimated: Bool
) {
self.viewModel = viewModel
self.iconImage = .init(named: viewModel.imageNamed) ?? UIImage()
Expand All @@ -62,6 +64,7 @@ struct ButtonComponentItemsUIView: UIViewRepresentable {
self.alignment = alignment
self.content = content
self.isEnabled = isEnabled
self.isAnimated = isAnimated
}

// MARK: - Maker
Expand Down Expand Up @@ -198,6 +201,10 @@ struct ButtonComponentItemsUIView: UIViewRepresentable {
buttonView.isEnabled = self.isEnabled
}

if buttonView.isAnimated != self.isAnimated {
buttonView.isAnimated = self.isAnimated
}

DispatchQueue.main.async {
self.height = buttonView.frame.height
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,10 @@ final class ButtonComponentUIView: ComponentUIView {
guard let self = self else { return }
self.buttonView.isEnabled = isEnabled
}

self.viewModel.$isAnimated.subscribe(in: &self.cancellables) { [weak self] isAnimated in
guard let self = self else { return }
self.buttonView.isAnimated = isAnimated
}
}
}
Loading

0 comments on commit 2a40401

Please sign in to comment.