$ErrorActionPreference = "Stop" Write-Host "" Write-Host "=== DURAKOMETR V1.11 STREAK BUGFIX ===" $root = (Get-Location).Path $file = Join-Path $root "app\src\main\java\ru\durakscore\app\StreakPraise.kt" $backupDir = Join-Path $root ".v111-streak-backup" if (-not (Test-Path $file)) { throw "Не найден StreakPraise.kt. Запусти скрипт из корня Android-проекта." } $content = Get-Content -LiteralPath $file -Raw -Encoding UTF8 $content = $content -replace "`r`n", "`n" $original = $content # ------------------------------------------------------------ # Strict preflight: patch only the expected current code. # ------------------------------------------------------------ $durationMatches = [regex]::Matches( $content, 'const\s+val\s+STREAK_PRAISE_DURATION_MS\s*=\s*[0-9_]+L' ) if ($durationMatches.Count -ne 1) { throw "Ожидалось ровно одно STREAK_PRAISE_DURATION_MS, найдено: $($durationMatches.Count). Ничего не изменено." } $oldPhrase = 'У {nameGen} серия {streak}. Остальные выглядят как четыре ошибки, случайно севшие за один стол.' $newPhrase = 'У {nameGen} серия {streak}. Остальные выглядят как три ошибки, случайно севшие за один стол.' if (-not $content.Contains($oldPhrase) -and -not $content.Contains($newPhrase)) { throw "Не найдена фраза про четыре/три ошибки. Ничего не изменено." } $oldRender = @' if ( activePraises.isNotEmpty() ) { Spacer( modifier = androidx.compose.ui.Modifier.height( topSpacingDp.dp ) ) if ( activePraises.size == 1 ) { StreakPraiseBanner( praise = activePraises.first() ) } else { MultiStreakPraiseBanner( praises = activePraises, lastLoserName = history .lastOrNull() ?.let { loserId -> players .firstOrNull { it.first == loserId } ?.second } ) } } '@ $oldRender = $oldRender -replace "`r`n", "`n" $newRender = @' /* * Плашка стрика теперь рисуется поверх экрана через Popup. * Она НЕ участвует в высоте PokerScreen/Column, поэтому появление * и исчезновение больше не сдвигает карточки игроков и кнопки +1. */ if ( activePraises.isNotEmpty() ) { Popup( alignment = Alignment.TopCenter, onDismissRequest = null, properties = PopupProperties( focusable = false, dismissOnBackPress = false, dismissOnClickOutside = false ) ) { Box( modifier = Modifier .fillMaxWidth() .padding( top = (92 + topSpacingDp).dp, start = 14.dp, end = 14.dp ) ) { if ( activePraises.size == 1 ) { StreakPraiseBanner( praise = activePraises.first() ) } else { MultiStreakPraiseBanner( praises = activePraises, lastLoserName = history .lastOrNull() ?.let { loserId -> players .firstOrNull { it.first == loserId } ?.second } ) } } } } '@ $newRender = $newRender -replace "`r`n", "`n" if (-not $content.Contains($oldRender) -and -not $content.Contains($newRender)) { throw "Не найден ожидаемый блок отображения streak-плашки. Ничего не изменено." } # ------------------------------------------------------------ # Backup before writing anything. # ------------------------------------------------------------ New-Item -ItemType Directory -Force -Path $backupDir | Out-Null Copy-Item -LiteralPath $file -Destination (Join-Path $backupDir "StreakPraise.kt") -Force # ------------------------------------------------------------ # 1. Duration: exactly 30 seconds. # ------------------------------------------------------------ $content = [regex]::Replace( $content, 'const\s+val\s+STREAK_PRAISE_DURATION_MS\s*=\s*[0-9_]+L', 'const val STREAK_PRAISE_DURATION_MS = 30_000L', 1 ) # ------------------------------------------------------------ # 2. Text: with one streak-holder at a 4-player table, # "остальные" are three people, not four. # ------------------------------------------------------------ $content = $content.Replace( $oldPhrase, $newPhrase ) # Keep comments truthful. $content = $content.Replace( 'Никакой очереди по 20 секунд.', 'Никакой очереди по 30 секунд.' ) $content = $content.Replace( '20-секундного таймера', '30-секундного таймера' ) # ------------------------------------------------------------ # 3. No layout shift: render the streak banner as an overlay Popup. # ------------------------------------------------------------ if ($content.Contains($oldRender)) { $content = $content.Replace( $oldRender, $newRender ) } $importsToAdd = @( 'import androidx.compose.foundation.layout.Box', 'import androidx.compose.foundation.layout.fillMaxWidth', 'import androidx.compose.foundation.layout.padding', 'import androidx.compose.ui.Alignment', 'import androidx.compose.ui.Modifier', 'import androidx.compose.ui.window.Popup', 'import androidx.compose.ui.window.PopupProperties' ) foreach ($importLine in $importsToAdd) { if (-not $content.Contains($importLine)) { $content = $content.Replace( 'import androidx.compose.foundation.layout.Spacer', "import androidx.compose.foundation.layout.Spacer`n$importLine" ) } } # ------------------------------------------------------------ # Final validation before saving. # ------------------------------------------------------------ if ($content -notmatch 'STREAK_PRAISE_DURATION_MS\s*=\s*30_000L') { throw "Не удалось выставить 30 секунд." } if ($content.Contains('как четыре ошибки, случайно севшие за один стол')) { throw "Старая фраза «четыре ошибки» всё ещё осталась." } if (-not $content.Contains('как три ошибки, случайно севшие за один стол')) { throw "Новая фраза «три ошибки» не записана." } if (-not $content.Contains('Popup(')) { throw "Overlay Popup не установлен." } Set-Content -LiteralPath $file -Value $content -Encoding UTF8 Write-Host "" Write-Host "=== PATCH COMPLETE ===" Write-Host "Streak duration: 30 sec" Write-Host "Phrase: четыре ошибки -> три ошибки" Write-Host "Streak banner: overlay, layout shift removed" Write-Host "Backup: $backupDir\StreakPraise.kt" Write-Host "" Write-Host "Теперь в Android Studio: Rebuild Project."