Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Card 'X' 버튼 이벤트 구현 #73

Merged
merged 16 commits into from
Apr 17, 2024
Merged

User Card 'X' 버튼 이벤트 구현 #73

merged 16 commits into from
Apr 17, 2024

Conversation

Minny27
Copy link
Member

@Minny27 Minny27 commented Mar 22, 2024

Motivation ⍰

  • 유저 카드에서 'X' 버튼 클릭 시 로티 애니메이션 표시를 0.5초간 유지 후, 다음 유저 카드로 스크롤
  • 타이머의 상태를 .over로 변경

Key Changes 🔑

미리보기는 다음과 같습니다.

  • 이전에는 타이머의 재개, 멈춤이 구현되어 있지 않았는데, 'X' 버튼 클릭 시, 구독을 끊고 타이머의 상태를 .over로 해야 하다보니 timer 클래스를 따로 구현할 필요가 있었습니다.
    코드는 다음과 같습니다.
// FallingUserCollectionViewCellModel
final private class Timer {
  private var disposable: Disposable? = nil
  
  let currentTime = BehaviorRelay<Double>(value: 13.0) // emit할 값
  private var startTime: Double // 멈춘 다음에 재개 시 시작할 시간 상태 값
  
  init(startTime: Double) {
    self.startTime = startTime
  }
  
  func start() {
    guard disposable == nil else { return }
    
    disposable = Observable<Int>.interval(.milliseconds(10),
                                          scheduler: MainScheduler.instance)
    .take(Int(startTime * 100) + 1)
    .map { [weak self] value in
      guard let self = self else { return 0.0 }
      return round((self.startTime * 100 - Double(value))) / 100
    }
    .debug()
    .bind(to: currentTime)
  }
  
  func pause() {
    startTime = currentTime.value
    disposable?.dispose()
    disposable = nil
  }
}

func transform(input: Input) -> Output {
    let timer = Timer(startTime: 13.0) // timer class
    let user = Driver.just(self.userDomain)
    
    let timerActiveTrigger = input.timerActiveTrigger
    
    let rejectButtonAction = input.rejectButtonTrigger
      .do(onNext: { _ in
        timer.pause()
        timer.currentTime.accept(-1.0) // reject 시에는 0.5초 후에 넘어 가야하는 제약이 있어서, 0초로 설정하지 않았고, reject 버튼 이벤트에 대한 처리는 상위 뷰에서 따로 처리하고 있음.
      })
    
    let likeButtonAction = input.likeButtonTrigger
    
    let timeActiveAction = timerActiveTrigger
      .do { value in
        if !value {
          timer.pause() // 시간 활성화 안 됐을 시, 멈춤
        } else {
          timer.start() // 시간 됐을 시, 재개
        }
      }
    
      { ... }
  }

사이드 이팩트나 더 좋은 방법이 있으면 제안해주세요. :)


To Reviewers 🙏🏻

  • 'X' 버튼 클릭 시, 로티 애니메이션 표시되는 지 확인해주세요.
  • 타이머의 상태가 초기화된 상태로 돌아가는 지 확인해주세요.
  • 다음 셀로 스크롤되는 지 확인해주세요.

Linked Issue 🔗

Minny27 added 14 commits March 12, 2024 13:28
- 더블 클릭 이벤트와 중첩되서 infoBoxView에 있는 버튼을 클릭했을 때 버벅였던 것으로 확인
- infoBoxView를 profile collection view와 분리
- UserInfoCollectionView에서도 중지가 가능하도록 구현은 했으나
- UserInfoCollectionView에서도 report 버튼이 있다보니 없앴음
- 더블 클릭 트리거를 cell에 넘겨준 것을 구독해서 멈춤 뷰 혹은 프로필 탭 시 이벤트 전달하는 방식으로 구현
- 원형 타이머 dot과 stoke가 이루는 각도를 30도로 가정해서 위치 수정
- 0초 위치 수정
- compositional layout의 섹션마다 다양한 타입의 아이템을 리턴하기 위함
- EmojiType hashable 준수
- FallingUserInfoItem을 diffable DataSource에 적용
- 아이템, 행, 섹션 간격 및 폰트 적용
- 필요 없는 코드 삭제
- pageControl 구현
- 아직 스크롤에 대한 이벤트 처리는 안 됨.
- 일부 제약조건 수정
- timer 클래스 생성
- timer에서 start()함수를 호출하면 disposable의 타이머 구독 생성
- pause에서는 현재 시간을 갱신하고 disposable의 구독을 해제하고 참조도 제거
- 로티 애니메이션 추가
- 디자인 변경으로 유저 카드 흔들리는 애니메이션 제거
- timeStart로 dimview를 hidden했었으나 currentTime이 BehaviorRelay로 되어 있어서 최초에 한 번 호출로 인해 dimview가 사라짐
- isTimerActive에서 처리하도록 해서 문제 해결
- 로티 애니메이션이 0.5초 간 지속되도록 설정
- 'x' 버튼이 클릭된 셀의 indexPath를 받아서 vc에 전달
- 로티를 표시하고 timeOverSubject emit
@Minny27 Minny27 added the 🦊 Feature New feature or request label Mar 22, 2024
@Minny27 Minny27 requested review from ibcylon and ChaNoo97 March 22, 2024 08:58
@Minny27 Minny27 self-assigned this Mar 22, 2024
Minny27 added 2 commits March 24, 2024 10:22
- progess를 셋째자리까지 표현하면 오차가 발생해서 원하는대로 애니메이션이 적용되지 않음.
- 또한 각도를 30도로 하게 되면 점과 선의 거리가 멀어 보여서 18도로 설정
Copy link
Member

@ibcylon ibcylon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다.

코드를 샅샅히 보지는 못했습니다.

질문

  1. timer를 class로 분리한 이유?
  2. cancellable timer, repeatable timer로 리팩토링 생각있는지?
  3. diffable 사용할 때 snapshot afterAnimation true/false에 대한 차이를 알고 계신지?

제안

  1. FallingCellViewModel에서 timer class와 timer state는 파일 분리하는 것이 좋을 것 같습니다. 가독성 측면에서도
  2. timer state의 enum 값 이름 변경 표시되는 값 5초와 실 시간 8초와의 괴리도 있고, 수정이 발생할 때마다 간극이 더 벌어질 것 같습니다. 따라서 stage#,이나 phase#으로 바꾸는 것이 어떨까요?

@Minny27
Copy link
Member Author

Minny27 commented Apr 15, 2024

  1. timer를 class로 분리한 이유?
  • pause, start 함수로 구현해야 하다보니 분리해야 했습니다.
  • 또한, pause 시 해제를 구현해야 하다보니 timer에서 구독, 해제를 구현해야 했습니다.
  1. cancellable timer, repeatable timer로 리팩토링 생각있는지?
  • 좋은 거 같습니다
  • cancellable과 disposable은 어떻게 차이가 있을 지 궁금합니다.
  1. diffable 사용할 때 snapshot afterAnimation true/false에 대한 차이를 알고 계신지?
  • animatingDifferences를 말씀하시는 걸까요?
  1. FallingCellViewModel에서 timer class와 timer state는 파일 분리하는 것이 좋을 것 같습니다. 가독성 측면에서도
    timer state의 enum 값 이름 변경 표시되는 값 5초와 실 시간 8초와의 괴리도 있고, 수정이 발생할 때마다 간극이 더 벌어질 것 같습니다. 따라서 stage#,이나 phase#으로 바꾸는 것이 어떨까요?
  • stage, phase 파라미터로 생성하는 거 좋은 거 같습니다.
  • 리팩토링 해보겠습니다.

@Minny27 Minny27 merged commit beba149 into main Apr 17, 2024
@Minny27 Minny27 deleted the Feature/reject_action branch April 17, 2024 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🦊 Feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants