fix(android): 修复keygen进度显示和参与者列表不完整的问题

问题1: 进度显示问题
- 协议进度永远卡在0/9直到完成
- 原因: 进度只在发送出站消息时更新,接收消息时不更新
- 修复: 在SendIncomingMessage中也提取轮次并调用OnProgress

问题2: totalRounds硬编码
- UI硬编码totalRounds=9,但keygen只有4轮
- 修复: 使用Go库传来的动态totalRounds值
- keygen默认4轮,sign默认9轮

问题3: 参与者列表不完整
- 只显示"参与方 1",缺少其他参与者
- 原因: 参与者通过participant_joined事件逐个添加
- 后加入者不会收到之前参与者的事件
- 修复: 在session_started时根据thresholdN/T初始化完整列表

修改文件:
- tsslib.go: SendIncomingMessage添加进度回调
- MainViewModel.kt: 添加_totalRounds, 初始化完整参与者列表
- MainActivity.kt: 使用动态totalRounds

注意: 需要重新编译tsslib.aar才能生效

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-27 08:36:25 -08:00
parent 71eea98ea5
commit 613f85f1c2
3 changed files with 35 additions and 7 deletions

View File

@ -77,6 +77,7 @@ fun TssPartyApp(
val currentSessionId by viewModel.currentSessionId.collectAsState() val currentSessionId by viewModel.currentSessionId.collectAsState()
val sessionParticipants by viewModel.sessionParticipants.collectAsState() val sessionParticipants by viewModel.sessionParticipants.collectAsState()
val currentRound by viewModel.currentRound.collectAsState() val currentRound by viewModel.currentRound.collectAsState()
val totalRounds by viewModel.totalRounds.collectAsState()
val publicKey by viewModel.publicKey.collectAsState() val publicKey by viewModel.publicKey.collectAsState()
val hasEnteredSession by viewModel.hasEnteredSession.collectAsState() val hasEnteredSession by viewModel.hasEnteredSession.collectAsState()
@ -349,7 +350,7 @@ fun TssPartyApp(
sessionStatus = sessionStatus, sessionStatus = sessionStatus,
participants = signParticipants, participants = signParticipants,
currentRound = signCurrentRound, currentRound = signCurrentRound,
totalRounds = 9, totalRounds = if (totalRounds > 0) totalRounds else 9, // Default to sign rounds
preparedTx = preparedTx, preparedTx = preparedTx,
signSessionId = signSessionId, signSessionId = signSessionId,
inviteCode = signInviteCode, inviteCode = signInviteCode,
@ -435,7 +436,7 @@ fun TssPartyApp(
hasEnteredSession = hasEnteredSession, hasEnteredSession = hasEnteredSession,
participants = sessionParticipants, participants = sessionParticipants,
currentRound = currentRound, currentRound = currentRound,
totalRounds = 9, totalRounds = if (totalRounds > 0) totalRounds else 4, // Default to keygen rounds
publicKey = publicKey, publicKey = publicKey,
countdownSeconds = uiState.countdownSeconds, countdownSeconds = uiState.countdownSeconds,
onCreateSession = { name, t, n, participantName -> onCreateSession = { name, t, n, participantName ->
@ -486,7 +487,7 @@ fun TssPartyApp(
sessionInfo = screenSessionInfo, sessionInfo = screenSessionInfo,
participants = joinKeygenParticipants, participants = joinKeygenParticipants,
currentRound = joinKeygenRound, currentRound = joinKeygenRound,
totalRounds = 9, totalRounds = if (totalRounds > 0) totalRounds else 4, // Default to keygen rounds
publicKey = joinKeygenPublicKey, publicKey = joinKeygenPublicKey,
countdownSeconds = uiState.countdownSeconds, countdownSeconds = uiState.countdownSeconds,
onValidateInviteCode = { inviteCode -> onValidateInviteCode = { inviteCode ->
@ -542,7 +543,7 @@ fun TssPartyApp(
signSessionInfo = screenSignSessionInfo, signSessionInfo = screenSignSessionInfo,
participants = coSignParticipants, participants = coSignParticipants,
currentRound = coSignRound, currentRound = coSignRound,
totalRounds = 9, totalRounds = if (totalRounds > 0) totalRounds else 9, // Default to sign rounds
signature = coSignSignature, signature = coSignSignature,
countdownSeconds = uiState.countdownSeconds, countdownSeconds = uiState.countdownSeconds,
onValidateInviteCode = { inviteCode -> onValidateInviteCode = { inviteCode ->

View File

@ -218,6 +218,9 @@ class MainViewModel @Inject constructor(
private val _currentRound = MutableStateFlow(0) private val _currentRound = MutableStateFlow(0)
val currentRound: StateFlow<Int> = _currentRound.asStateFlow() val currentRound: StateFlow<Int> = _currentRound.asStateFlow()
private val _totalRounds = MutableStateFlow(0)
val totalRounds: StateFlow<Int> = _totalRounds.asStateFlow()
private val _publicKey = MutableStateFlow<String?>(null) private val _publicKey = MutableStateFlow<String?>(null)
val publicKey: StateFlow<String?> = _publicKey.asStateFlow() val publicKey: StateFlow<String?> = _publicKey.asStateFlow()
@ -299,8 +302,10 @@ class MainViewModel @Inject constructor(
} }
// Setup progress callback for real-time round updates from native TSS bridge // Setup progress callback for real-time round updates from native TSS bridge
repository.setProgressCallback { round, totalRounds -> repository.setProgressCallback { round, totalRoundsFromGo ->
android.util.Log.d("MainViewModel", "Progress update: $round / $totalRounds") android.util.Log.d("MainViewModel", "Progress update: $round / $totalRoundsFromGo")
// Update totalRounds from Go library (keygen=4, sign=9)
_totalRounds.value = totalRoundsFromGo
// Update the appropriate round state based on which session type is active // Update the appropriate round state based on which session type is active
when { when {
// Initiator keygen (CreateWallet) // Initiator keygen (CreateWallet)
@ -338,6 +343,8 @@ class MainViewModel @Inject constructor(
val currentSessionId = _currentSessionId.value val currentSessionId = _currentSessionId.value
if (currentSessionId != null && event.sessionId == currentSessionId) { if (currentSessionId != null && event.sessionId == currentSessionId) {
android.util.Log.d("MainViewModel", "Session started event for keygen initiator, triggering keygen") android.util.Log.d("MainViewModel", "Session started event for keygen initiator, triggering keygen")
// Initialize participant list with all N parties (keygen requires all parties)
_sessionParticipants.value = (1..event.thresholdN).map { "参与方 $it" }
viewModelScope.launch { viewModelScope.launch {
startKeygenAsInitiator( startKeygenAsInitiator(
sessionId = currentSessionId, sessionId = currentSessionId,
@ -359,6 +366,8 @@ class MainViewModel @Inject constructor(
val joinSignInfo = pendingJoinSignInfo val joinSignInfo = pendingJoinSignInfo
if (joinSignInfo != null && event.sessionId == joinSignInfo.sessionId) { if (joinSignInfo != null && event.sessionId == joinSignInfo.sessionId) {
android.util.Log.d("MainViewModel", "Session started event for sign joiner, triggering sign") android.util.Log.d("MainViewModel", "Session started event for sign joiner, triggering sign")
// Initialize participant list with T parties (sign requires T parties)
_coSignParticipants.value = (1..event.thresholdT).map { "参与方 $it" }
startSignAsJoiner() startSignAsJoiner()
} }
@ -367,6 +376,8 @@ class MainViewModel @Inject constructor(
android.util.Log.d("MainViewModel", "Checking for sign initiator: signSessionId=$signSessionId, eventSessionId=${event.sessionId}") android.util.Log.d("MainViewModel", "Checking for sign initiator: signSessionId=$signSessionId, eventSessionId=${event.sessionId}")
if (signSessionId != null && event.sessionId == signSessionId) { if (signSessionId != null && event.sessionId == signSessionId) {
android.util.Log.d("MainViewModel", "Session started event for sign initiator, triggering sign") android.util.Log.d("MainViewModel", "Session started event for sign initiator, triggering sign")
// Initialize participant list with T parties (sign requires T parties)
_signParticipants.value = (1..event.thresholdT).map { "参与方 $it" }
startSignAsInitiator(event.selectedParties) startSignAsInitiator(event.selectedParties)
} else { } else {
android.util.Log.d("MainViewModel", "NOT triggering sign initiator: signSessionId=$signSessionId, pendingSignInitiatorInfo=${pendingSignInitiatorInfo?.sessionId}") android.util.Log.d("MainViewModel", "NOT triggering sign initiator: signSessionId=$signSessionId, pendingSignInitiatorInfo=${pendingSignInitiatorInfo?.sessionId}")
@ -515,6 +526,7 @@ class MainViewModel @Inject constructor(
_currentSessionId.value = null _currentSessionId.value = null
_sessionParticipants.value = emptyList() _sessionParticipants.value = emptyList()
_currentRound.value = 0 _currentRound.value = 0
_totalRounds.value = 0
_publicKey.value = null _publicKey.value = null
_createdInviteCode.value = null _createdInviteCode.value = null
_hasEnteredSession.value = false _hasEnteredSession.value = false
@ -659,7 +671,11 @@ class MainViewModel @Inject constructor(
viewModelScope.launch { viewModelScope.launch {
_uiState.update { it.copy(isLoading = true, error = null) } _uiState.update { it.copy(isLoading = true, error = null) }
android.util.Log.d("MainViewModel", "Starting keygen as joiner: sessionId=${joinInfo.sessionId}, partyIndex=${joinInfo.partyIndex}") // Initialize participant list with all N parties (keygen requires all parties)
// This ensures UI shows correct participant count even if we missed some participant_joined events
_joinKeygenParticipants.value = (1..joinInfo.thresholdN).map { "参与方 $it" }
android.util.Log.d("MainViewModel", "Starting keygen as joiner: sessionId=${joinInfo.sessionId}, partyIndex=${joinInfo.partyIndex}, thresholdN=${joinInfo.thresholdN}")
val result = repository.executeKeygenAsJoiner( val result = repository.executeKeygenAsJoiner(
sessionId = joinInfo.sessionId, sessionId = joinInfo.sessionId,

View File

@ -393,6 +393,17 @@ func SendIncomingMessage(fromPartyIndex int, isBroadcast bool, payloadBase64 str
return fmt.Errorf("failed to parse message: %w", err) return fmt.Errorf("failed to parse message: %w", err)
} }
// Extract round from incoming message and update progress
// This ensures progress updates on both sending and receiving messages
totalRounds := 4 // GG20 keygen has 4 rounds
if !session.isKeygen {
totalRounds = 9 // GG20 signing has 9 rounds
}
currentRound := extractRoundFromMessageType(parsedMsg.Type())
if currentRound > 0 {
session.callback.OnProgress(currentRound, totalRounds)
}
go func() { go func() {
_, err := session.localParty.Update(parsedMsg) _, err := session.localParty.Update(parsedMsg)
if err != nil { if err != nil {