iOS 与传输修复:取消即时落终态 + 行操作统一 + 记录按用户分桶 + 发送端进度/完成对齐接收端
- 取消传输无效:web cancelTransfer 拆除本端 p2p/relay 后立即 completeTransfer(sessionId, "CANCELLED") 落终态,不再仅依赖服务端 transfer:state CANCELLED 回显——回显延迟、或因设备名变更致路由不中而未送达时,旧实现使记录永停“进行中”,即用户所见“取消无效”。completeTransfer 幂等,随后回显安全重入。 - 进行中/已完成传输行操作统一:进行中行新增滑动“取消”+ 长按菜单“取消/切中继”,与历史行滑动+长按“删除”对称。取消即时无确认、随 transferDone 移入 history,析构滑动动画与现实一致不抖。详情页取消/切中继入口保留。 - 传输历史/消息持久化:记录按登录用户 userId 分桶持久化(EngineController recordKey/activateRecords/persist*,含旧无桶文件一次性回退)。reset() 改为只清内存、不再 RecordsStore.clear 磁盘——会话失效(authExpired/被吊销)属凭证层事件,不应连用户数据一并销毁;同一账户重登经 activateRecords 即恢复,换账号各读各桶天然防跨账号泄露。CDropApp 在 onAppear 与 onChange(session.user.id) 激活记录。 - 发送端进度/完成对齐接收端:接收端经数据通道节流(200ms)+finalize 即时回传已收字节(ack 帧);发送端进度改用 ackedBytes(单调取大),取代仅反映本地 SCTP 缓冲抽干的 senderDeliveredBytes——避免 Windows→iOS 等慢接收端组合下发送端进度虚高领先、完成早十数秒(4MB)。streamFile 抽干 buffer 后再等 ack 追平总量才宣告完成;ackedBytes==0(旧版本接收端)走旧“抽干即完成”行为、30s 超时兜底、接收端权威 /done 经 SSE 独立完成。
This commit is contained in:
@@ -227,9 +227,10 @@ struct TransferListView: View
|
||||
}
|
||||
}
|
||||
|
||||
// 传输行:卡片观感不变;点按进详情;历史记录支持滑动删除 + 长按删除(与设备 / 文件长条一致)。
|
||||
// 进行中的传输不挂删除手势(取消 / 切中继在详情页)。删除是真删除(无需二次确认),故析构滑动按钮
|
||||
// 的删除动画与实际一致、不会抖动。
|
||||
// 传输行:卡片观感不变;点按进详情;所有长条行操作逻辑统一——滑动 + 长按都给主操作(与设备 /
|
||||
// 文件长条一致)。历史记录=删除(真删除、无需二次确认);进行中=取消(即时、无确认),长按菜单
|
||||
// 另给「切中继」。两类的滑动 / 长按都直挂破坏性操作,析构滑动动画与实际一致(取消即随 transferDone
|
||||
// 移入 history、删除即移除),不会抖动。详情页仍保留取消 / 切中继入口。
|
||||
@ViewBuilder
|
||||
private func transferRow(_ item: TransferItem, history: Bool) -> some View
|
||||
{
|
||||
@@ -256,6 +257,22 @@ struct TransferListView: View
|
||||
else
|
||||
{
|
||||
card
|
||||
.swipeActions(edge: .trailing)
|
||||
{
|
||||
Button(role: .destructive) { engine.cancelTransfer(item.sessionId) }
|
||||
label: { Label(t("ios.transfer.cancel"), systemImage: "xmark.circle") }
|
||||
}
|
||||
.contextMenu
|
||||
{
|
||||
Button(role: .destructive) { engine.cancelTransfer(item.sessionId) }
|
||||
label: { Label(t("ios.transfer.cancel"), systemImage: "xmark.circle") }
|
||||
if item.mode != "relay"
|
||||
{
|
||||
Button { engine.switchToRelay(item.sessionId) }
|
||||
label: { Label(t("ios.transfer.forceRelay"),
|
||||
systemImage: "antenna.radiowaves.left.and.right") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user