| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- //
- // LNAudioCallFloatingView.swift
- // Gami
- //
- // Created by OneeChan on 2026/2/3.
- //
- import Foundation
- import UIKit
- import SnapKit
- class LNAudioCallFloatingView: UIView {
- private let size: CGFloat = 67
-
- private let stackView = UIStackView()
- private let stateIc = UIImageView()
- private let durationLabel = UILabel()
-
- private var timer: Timer?
-
- override init(frame: CGRect) {
- super.init(frame: frame)
-
- setupViews()
- setupGesture()
-
- LNEventDeliver.addObserver(self)
-
- if let callInfo = LNIMManager.shared.curCallInfo,
- callInfo.beginTime > 0 {
- updateCallDuration()
- startTimer()
- }
- }
-
- func show() {
- guard let window = UIView.appKeyWindow else { return }
- window.addSubview(self)
-
- frame = .init(x: window.bounds.width - 16 - size,
- y: window.bounds.height - 100.0 - size,
- width: size, height: size)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- }
- extension LNAudioCallFloatingView {
- func dismiss() {
- removeFromSuperview()
- }
-
- private func updateCallDuration() {
- guard let callInfo = LNIMManager.shared.curCallInfo else { return }
- let duration = curTime - callInfo.beginTime
- durationLabel.text = duration.timeCountDisplay
- durationLabel.isHidden = false
- }
-
- private func startTimer() {
- stopTimer()
- let timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { [weak self] _ in
- guard let self else { return }
- guard LNIMManager.shared.curCallInfo != nil else {
- stopTimer()
- return
- }
-
- updateCallDuration()
- }
- RunLoop.main.add(timer, forMode: .common)
- self.timer = timer
- }
-
- private func stopTimer() {
- timer?.invalidate()
- timer = nil
- }
- }
- extension LNAudioCallFloatingView {
- @objc
- private func handlePan(_ ges: UIPanGestureRecognizer) {
- let location = ges.location(in: superview)
-
- switch ges.state {
- case .began:
- break
- case .changed:
- center = location
- break
- default:
- updatePosition(animated: true)
- break
- }
- }
- }
- extension LNAudioCallFloatingView {
- private func updatePosition(animated: Bool) {
- guard let superview else { return }
- let movement = { [weak self] in
- guard let self else { return }
-
- let y = center.y.bounded(min: 160, max: superview.bounds.height - 160)
- // if center.x > superview.bounds.width * 0.5 {
- center = .init(x: superview.bounds.width - bounds.width * 0.5 - 16, y: y)
- // } else {
- // center = .init(x: bounds.width * 0.5 + 16, y: y)
- // }
- }
- if animated {
- UIView.animate(withDuration: 0.25, animations: movement)
- } else {
- movement()
- }
- }
-
- private func setupViews() {
- layer.shadowColor = UIColor.black.withAlphaComponent(0.08).cgColor
- layer.shadowOffset = .init(width: 0, height: 4)
- layer.shadowRadius = 6
- layer.shadowOpacity = 0.5
- layer.masksToBounds = false
-
- backgroundColor = .fill
- layer.cornerRadius = 12
-
- stackView.axis = .vertical
- stackView.spacing = 8
- stackView.alignment = .center
- addSubview(stackView)
- stackView.snp.makeConstraints { make in
- make.center.equalToSuperview()
- }
-
- stateIc.image = .icCalling
- stackView.addArrangedSubview(stateIc)
-
- durationLabel.isHidden = true
- durationLabel.font = .heading_h5
- durationLabel.textColor = .text_6
- stackView.addArrangedSubview(durationLabel)
- }
-
- private func setupGesture() {
- let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
- addGestureRecognizer(pan)
-
- onTap {
- let panel = LNAudioCallPanel()
- panel.resume()
- panel.popup()
- }
- }
- }
- extension LNAudioCallFloatingView: LNIMManagerNotify {
- func onVoiceCallEnd() {
- dismiss()
- }
-
- func onVoiceCallBegin() {
- updateCallDuration()
- startTimer()
- }
- }
|