mirror of
https://github.com/Finb/Bark.git
synced 2025-12-08 21:36:01 +00:00
修复折叠推送点击复制只会复制第一条的问题
This commit is contained in:
parent
2f554e9e92
commit
eb77151fdc
@ -115,6 +115,7 @@
|
||||
068EC15827ED99C900D5D11E /* ServerListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 068EC15727ED99C900D5D11E /* ServerListViewController.swift */; };
|
||||
068EC15A27ED99E700D5D11E /* ServerListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 068EC15927ED99E700D5D11E /* ServerListViewModel.swift */; };
|
||||
068F66B3247BD84C00DAD25A /* MessageListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 068F66B2247BD84C00DAD25A /* MessageListViewController.swift */; };
|
||||
0699473D2D223094008D5E40 /* CustomTapTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0699473C2D223094008D5E40 /* CustomTapTextView.swift */; };
|
||||
06AE3118266F4E2E00B39FBB /* GroupFilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06AE3117266F4E2E00B39FBB /* GroupFilterViewController.swift */; };
|
||||
06AE311A266F4E6600B39FBB /* GroupFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06AE3119266F4E6600B39FBB /* GroupFilterViewModel.swift */; };
|
||||
06AE311C266F54A500B39FBB /* GroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06AE311B266F54A500B39FBB /* GroupTableViewCell.swift */; };
|
||||
@ -357,6 +358,7 @@
|
||||
068EC15727ED99C900D5D11E /* ServerListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListViewController.swift; sourceTree = "<group>"; };
|
||||
068EC15927ED99E700D5D11E /* ServerListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListViewModel.swift; sourceTree = "<group>"; };
|
||||
068F66B2247BD84C00DAD25A /* MessageListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListViewController.swift; sourceTree = "<group>"; };
|
||||
0699473C2D223094008D5E40 /* CustomTapTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTapTextView.swift; sourceTree = "<group>"; };
|
||||
06AE3117266F4E2E00B39FBB /* GroupFilterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupFilterViewController.swift; sourceTree = "<group>"; };
|
||||
06AE3119266F4E6600B39FBB /* GroupFilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupFilterViewModel.swift; sourceTree = "<group>"; };
|
||||
06AE311B266F54A500B39FBB /* GroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupTableViewCell.swift; sourceTree = "<group>"; };
|
||||
@ -681,6 +683,7 @@
|
||||
066890092D19495400E106F2 /* MessageList */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0699473C2D223094008D5E40 /* CustomTapTextView.swift */,
|
||||
066890072D1946D500E106F2 /* MessageItemView.swift */,
|
||||
0667D191247D162C005DE2ED /* MessageTableViewCell.swift */,
|
||||
0668900A2D19525400E106F2 /* ShowLessAndClearView.swift */,
|
||||
@ -1238,6 +1241,7 @@
|
||||
0642B55C27EB149900453D91 /* MutableTextCellViewModel.swift in Sources */,
|
||||
062B98C8251B27AE004562E7 /* UINavigationItem+Extension.swift in Sources */,
|
||||
060481EE250F404500BC9799 /* SoundsViewController.swift in Sources */,
|
||||
0699473D2D223094008D5E40 /* CustomTapTextView.swift in Sources */,
|
||||
06EEF333291CCFF400CA228A /* CryptoSettingController.swift in Sources */,
|
||||
0603706D20E23EC000F4CA05 /* BarkSFSafariViewController.swift in Sources */,
|
||||
06AE311A266F4E6600B39FBB /* GroupFilterViewModel.swift in Sources */,
|
||||
|
||||
@ -104,6 +104,23 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
.subscribe(onNext: { [weak self] _ in
|
||||
self?.tableView.refreshControl?.sendActions(for: .valueChanged)
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
// 点击群组消息,展开群
|
||||
tableView.rx.itemSelected.subscribe(onNext: { [weak self] indexPath in
|
||||
guard let self else { return }
|
||||
if let cell = self.tableView.cellForRow(at: indexPath) as? MessageGroupTableViewCell {
|
||||
if !cell.isExpanded {
|
||||
UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.2) {
|
||||
self.tableView.performBatchUpdates {
|
||||
cell.isExpanded = true
|
||||
}
|
||||
}
|
||||
if let groupName = cell.cellData?.groupName {
|
||||
self.expandedGroup.insert(groupName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}).disposed(by: rx.disposeBag)
|
||||
}
|
||||
|
||||
// tableView 数据源
|
||||
@ -120,6 +137,10 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(MessageTableViewCell.self)") as? MessageTableViewCell else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
cell.tapAction = { [weak self, weak cell] message, sourceView in
|
||||
guard let self else { return }
|
||||
self.alertMessage(message: message.attributedText?.string ?? "", sourceView: sourceView)
|
||||
}
|
||||
cell.message = message
|
||||
return cell
|
||||
case .messageGroup(let title, let totalCount, let messages):
|
||||
@ -146,6 +167,10 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
guard let self, let cell, let indexPath = self.tableView.indexPath(for: cell) else { return }
|
||||
self.tableView.dataSource?.tableView?(self.tableView, commit: .delete, forRowAt: indexPath)
|
||||
}
|
||||
cell.tapAction = { [weak self, weak cell] message, sourceView in
|
||||
guard let self else { return }
|
||||
self.alertMessage(message: message.attributedText?.string ?? "", sourceView: sourceView)
|
||||
}
|
||||
cell.cellData = (title, max(0, totalCount - messages.count), messages)
|
||||
cell.isExpanded = self.expandedGroup.contains(title)
|
||||
return cell
|
||||
@ -161,31 +186,11 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
return
|
||||
}
|
||||
|
||||
let itemSelected = tableView.rx.itemSelected.asDriver().compactMap { [weak self] indexPath -> Int? in
|
||||
guard let self else { return nil }
|
||||
if let cell = self.tableView.cellForRow(at: indexPath) as? MessageGroupTableViewCell {
|
||||
if !cell.isExpanded {
|
||||
UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.2) {
|
||||
self.tableView.performBatchUpdates {
|
||||
cell.isExpanded = true
|
||||
}
|
||||
}
|
||||
if let groupName = cell.cellData?.groupName {
|
||||
self.expandedGroup.insert(groupName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return indexPath.row
|
||||
}
|
||||
|
||||
let output = viewModel.transform(
|
||||
input: MessageListViewModel.Input(
|
||||
refresh: tableView.refreshControl!.rx.controlEvent(.valueChanged).asDriver(),
|
||||
loadMore: tableView.mj_footer!.rx.refresh.asDriver(),
|
||||
itemDelete: tableView.rx.modelDeleted(MessageListCellItem.self).asDriver(),
|
||||
itemSelected: itemSelected,
|
||||
delete: getBatchDeleteDriver(),
|
||||
groupToggleTap: groupBtn.rx.tap.asDriver(),
|
||||
searchText: navigationItem.searchController!.searchBar.rx.text.asObservable()
|
||||
@ -200,11 +205,6 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
.drive(tableView.rx.items(dataSource: dataSource))
|
||||
.disposed(by: rx.disposeBag)
|
||||
|
||||
// message操作alert
|
||||
output.alertMessage.drive(onNext: { [weak self] message in
|
||||
self?.alertMessage(message: message.0, indexPath: IndexPath(row: message.1, section: 0))
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
// 选择群组
|
||||
output.type
|
||||
.drive(onNext: { [weak self] type in
|
||||
@ -266,7 +266,7 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
.asDriver(onErrorDriveWith: .empty())
|
||||
}
|
||||
|
||||
private func alertMessage(message: String, indexPath: IndexPath) {
|
||||
private func alertMessage(message: String, sourceView: UIView) {
|
||||
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
let copyAction = UIAlertAction(title: NSLocalizedString("CopyAll"), style: .default, handler: { [weak self]
|
||||
(_: UIAlertAction) in
|
||||
@ -279,11 +279,9 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
alertController.addAction(copyAction)
|
||||
alertController.addAction(cancelAction)
|
||||
if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
if let cell = self.tableView.cellForRow(at: indexPath) {
|
||||
alertController.popoverPresentationController?.sourceView = self.tableView
|
||||
alertController.popoverPresentationController?.sourceRect = cell.frame
|
||||
alertController.modalPresentationStyle = .popover
|
||||
}
|
||||
alertController.popoverPresentationController?.sourceView = sourceView.superview
|
||||
alertController.popoverPresentationController?.sourceRect = sourceView.frame
|
||||
alertController.modalPresentationStyle = .popover
|
||||
}
|
||||
|
||||
self.navigationController?.present(alertController, animated: true, completion: nil)
|
||||
|
||||
@ -34,8 +34,6 @@ class MessageListViewModel: ViewModel, ViewModelType {
|
||||
var loadMore: Driver<Void>
|
||||
/// 删除
|
||||
var itemDelete: Driver<MessageListCellItem>
|
||||
/// 点击
|
||||
var itemSelected: Driver<Int>
|
||||
/// 批量删除
|
||||
var delete: Driver<MessageDeleteType>
|
||||
/// 切换群组和列表显示样式
|
||||
@ -49,8 +47,6 @@ class MessageListViewModel: ViewModel, ViewModelType {
|
||||
var messages: Driver<[MessageSection]>
|
||||
/// 刷新控件状态
|
||||
var refreshAction: Driver<MJRefreshAction>
|
||||
/// 点击后,弹出提示
|
||||
var alertMessage: Driver<(String, Int)>
|
||||
/// 群组过滤
|
||||
var type: Driver<MessageListType>
|
||||
/// 标题
|
||||
@ -189,26 +185,6 @@ class MessageListViewModel: ViewModel, ViewModelType {
|
||||
}
|
||||
|
||||
func transform(input: Input) -> Output {
|
||||
let alertMessage = input.itemSelected.map { [weak self] index in
|
||||
guard let results = self?.results else {
|
||||
return ("", 0)
|
||||
}
|
||||
let message = results[index]
|
||||
|
||||
var copyContent: String = ""
|
||||
if let title = message.title {
|
||||
copyContent += "\(title)\n"
|
||||
}
|
||||
if let body = message.body {
|
||||
copyContent += "\(body)\n"
|
||||
}
|
||||
if let url = message.url {
|
||||
copyContent += "\(url)\n"
|
||||
}
|
||||
copyContent = String(copyContent.prefix(copyContent.count - 1))
|
||||
|
||||
return (copyContent, index)
|
||||
}
|
||||
// 标题
|
||||
let titleRelay = BehaviorRelay<String>(value: NSLocalizedString("historyMessage"))
|
||||
// 数据源
|
||||
@ -384,7 +360,6 @@ class MessageListViewModel: ViewModel, ViewModelType {
|
||||
return Output(
|
||||
messages: messagesRelay.asDriver(onErrorJustReturn: []),
|
||||
refreshAction: refreshAction.asDriver(),
|
||||
alertMessage: alertMessage,
|
||||
type: Driver.merge(messageTypeChanged.asDriver(), Driver.just(self.type)),
|
||||
title: titleRelay.asDriver(),
|
||||
groupToggleButtonHidden: Driver.just(groupToggleButtonHidden)
|
||||
|
||||
65
View/MessageList/CustomTapTextView.swift
Normal file
65
View/MessageList/CustomTapTextView.swift
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// CustomTapTextView.swift
|
||||
// Bark
|
||||
//
|
||||
// Created by huangfeng on 12/30/24.
|
||||
// Copyright © 2024 Fin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// 可以自定义点击事件的 UITextView,同时保留 UITextView 的所有其他手势
|
||||
/// 此 TextView 不可编辑, 不可滚动
|
||||
class CustomTapTextView: UITextView, UIGestureRecognizerDelegate {
|
||||
/// 点击手势,如果有选中文字,则不触发
|
||||
private lazy var tapGesture = UITapGestureRecognizer(target: self, action: #selector(tap))
|
||||
/// 双击手势,只是为了让 tapGesture 不要在双击选中文本时触发,没有其他作用
|
||||
private let doubleTapGesture = UITapGestureRecognizer()
|
||||
|
||||
/// 额外的单击事件
|
||||
var customTapAction: (() -> Void)?
|
||||
|
||||
init() {
|
||||
super.init(frame: .zero, textContainer: nil)
|
||||
|
||||
self.backgroundColor = UIColor.clear
|
||||
self.isEditable = false
|
||||
self.dataDetectorTypes = [.phoneNumber, .link]
|
||||
self.isScrollEnabled = false
|
||||
self.textContainerInset = .zero
|
||||
self.textContainer.lineFragmentPadding = 0
|
||||
|
||||
tapGesture.delegate = self
|
||||
tapGesture.require(toFail: doubleTapGesture)
|
||||
self.addGestureRecognizer(tapGesture)
|
||||
|
||||
doubleTapGesture.numberOfTapsRequired = 2
|
||||
doubleTapGesture.delegate = self
|
||||
self.addGestureRecognizer(doubleTapGesture)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc func tap() {
|
||||
self.customTapAction?()
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
if gestureRecognizer == doubleTapGesture {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
if gestureRecognizer == tapGesture {
|
||||
if self.selectedRange.length > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return super.gestureRecognizerShouldBegin(gestureRecognizer)
|
||||
}
|
||||
}
|
||||
@ -25,14 +25,8 @@ class MessageItemView: UIView {
|
||||
return view
|
||||
}()
|
||||
|
||||
let bodyLabel: UITextView = {
|
||||
let label = UITextView()
|
||||
label.backgroundColor = UIColor.clear
|
||||
label.isEditable = false
|
||||
label.dataDetectorTypes = [.phoneNumber, .link]
|
||||
label.isScrollEnabled = false
|
||||
label.textContainerInset = .zero
|
||||
label.textContainer.lineFragmentPadding = 0
|
||||
let bodyLabel: CustomTapTextView = {
|
||||
let label = CustomTapTextView()
|
||||
label.font = UIFont.preferredFont(ofSize: 14)
|
||||
label.adjustsFontForContentSizeCategory = true
|
||||
label.textColor = BKColor.grey.darken4
|
||||
@ -73,6 +67,8 @@ class MessageItemView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
var tapAction: ((_ message: MessageItemModel, _ sourceView: UIView) -> Void)?
|
||||
|
||||
init() {
|
||||
super.init(frame: .zero)
|
||||
self.backgroundColor = BKColor.background.primary
|
||||
@ -93,6 +89,13 @@ class MessageItemView: UIView {
|
||||
}
|
||||
self.dateLabel.text = self.message?.dateText
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
self.bodyLabel.customTapAction = { [weak self] in
|
||||
guard let self, let message = self.message else { return }
|
||||
self.tapAction?(message, self)
|
||||
}
|
||||
|
||||
panel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap)))
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
@ -122,6 +125,11 @@ class MessageItemView: UIView {
|
||||
make.edges.equalTo(panel)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func tap() {
|
||||
guard let message else { return }
|
||||
self.tapAction?(message, self)
|
||||
}
|
||||
}
|
||||
|
||||
extension MessageItemView {
|
||||
|
||||
@ -23,6 +23,12 @@ class MessageTableViewCell: UITableViewCell {
|
||||
}
|
||||
}
|
||||
|
||||
var tapAction: ((_ message: MessageItemModel, _ sourceView: UIView) -> Void)? {
|
||||
didSet {
|
||||
messageView.tapAction = tapAction
|
||||
}
|
||||
}
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
self.selectionStyle = .none
|
||||
@ -136,6 +142,8 @@ class MessageGroupTableViewCell: UITableViewCell {
|
||||
groupHeader.clearAction = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var tapAction: ((_ message: MessageItemModel, _ sourceView: UIView) -> Void)? = nil
|
||||
|
||||
/// 查看群组所有消息
|
||||
var showGroupMessageAction: ((_ group: String?) -> Void)? = nil
|
||||
@ -170,6 +178,12 @@ class MessageGroupTableViewCell: UITableViewCell {
|
||||
moreView.gestureRecognizers?.first?.rx.event.subscribe(onNext: { [weak self] _ in
|
||||
self?.showGroupMessageAction?(self?.messages.first?.group)
|
||||
}).disposed(by: self.rx.disposeBag)
|
||||
|
||||
for view in messageViews {
|
||||
view.tapAction = { [weak self] message, sourceView in
|
||||
self?.tapAction?(message, sourceView)
|
||||
}
|
||||
}
|
||||
|
||||
refreshViewState()
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user