feat(android): floating lyrics overlay (SYSTEM_ALERT_WINDOW) + karaoke fill - #13
Merged
Conversation
…e fill 다른 앱/홈 화면 위에 떠서 실시간 가사를 보여주는 오버레이를 추가한다. - Services/OverlayService.cs: 포그라운드 서비스. WindowManager의 TYPE_APPLICATION_OVERLAY 뷰(하단 중앙 반투명 둥근 카드)를 붙이고, 터치는 FLAG_NOT_FOCUSABLE|NOT_TOUCHABLE로 완전 통과. Android 8+ 알림 채널 + "정지" 액션. specialUse 포그라운드 타입. - Views/KaraokeTextView.cs: 글자 단위 카라오케 커스텀 뷰. 흰색 베이스 위에 노랑(#FFEB3B)을 진행 글자까지 Path 클립으로 덧그린다. 타임태그 (InlineTimeTags.CharIndexAt) 있으면 글자 위치, 없으면 라인 비율 폴백. 100ms 갱신 사이를 앵커+실시간으로 60fps 보간. StaticLayout 멀티라인/ 가운데정렬 대응. - MainActivity.cs: 오버레이 권한 안내/요청(CanDrawOverlays → ACTION_MANAGE_OVERLAY_PERMISSION) + 켜기/끄기 토글. 앱 내 가사 표시 유지. - AndroidManifest.xml: SYSTEM_ALERT_WINDOW / FOREGROUND_SERVICE(+_SPECIAL_USE) / POST_NOTIFICATIONS 권한. 엔진 재사용(골든룰): 오버레이는 MusebaseApp이 1회 조립한 LyricsCoordinator의 CurrentLineChanged/LineProgressChanged와 소스의 IsPlayingChanged를 구독만 한다 (엔진 재조립 없음). 코어/엔진/contracts 무수정. 빌드: APK 산출 성공(경고 0/오류 0). sln Release 빌드 + Core 테스트 90개 통과. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n API key) Same root cause as the Windows fix — the Android head hardcoded libretranslate, whose public instance silently fails without a key, so no translation appeared. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ics source - Engine: LyricsCoordinator.CurrentTranslationStatus + TranslationStatusChanged. Computed after each translate run from run stats + routed translator failures (Quota/RateLimit -> quota). Factory now builds the coordinator first, then wires BuildTranslation with a callback that feeds failures into the coordinator (for status) and on to the app (logging/hint). - Windows: appends " · 번역: 정상 번역 / 캐시 이용 / 한도 초과" to the lyrics source status in tray tooltip + mini window; re-renders on TranslationStatusChanged. i18n. - Android: same suffix on the in-app lyrics status line. Answers "is missing translation expected?" — no; it was the LibreTranslate breakage (now MyMemory) plus no visibility. This surfaces quota vs live vs cache on both heads. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ation live Extracts the translation wiring (failure routing to coordinator + app, target language, refresh) so platform heads can rebuild the engine on settings change. Used by Create; now reusable by Android settings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MyMemory 하드코딩을 제거하고 사용자가 번역 엔진/키/대상 언어를 고르게 한다. - Services/AndroidSettings.cs(신규): ISharedPreferences(앱 private) 래퍼. TranslationEngine/DeeplApiKey/TargetLanguage. 앱 private 저장(디스크 암호화는 아님 — Windows DPAPI와 다름)임을 주석/README에 명시. EffectiveTranslationEngine 헬퍼(Windows와 동일 규칙: 명시값 우선, 없으면 키 유무로 결정). - SettingsActivity.cs(신규): 코드 UI, Exported=false. 엔진 스피너(MyMemory/DeepL/끄기) + DeepL 키(DeepL 선택 시만 표시, 눈 토글) + 대상 언어(비면 로케일 기본) + 저장. 저장 시 AndroidSettings 반영 → MusebaseApp.ApplyTranslationSettings() → 토스트/종료. - MusebaseApp.cs: EngineConfig를 설정값으로 구성(BuildConfig). translationCache/dbPath를 필드로 보관. 신규 ApplyTranslationSettings()가 LyricsEngineFactory.ApplyTranslation으로 재시작 없이 번역 재구성(새 엔진은 다음 곡/재검색부터 — Windows와 동일). - MainActivity.cs: "번역 설정" 버튼 → StartActivity(SettingsActivity). - README: 번역 설정 사용법/저장 한계 문서화. 코어/엔진/contracts 미변경(beta에 이미 있는 ApplyTranslation API만 사용). APK 빌드 성공(경고 0/오류 0), sln Release + Core 테스트 90개 통과. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
다른 앱(음악 앱)·홈 화면 위에 떠 있는 오버레이로 실시간 가사를 표시한다. 글자 단위 카라오케 채움 포함. 기존 앱 내 가사 표시는 대체 확인용으로 유지.
오버레이 서비스 (
Services/OverlayService.cs)Service— Android 8+ 필수 알림 채널 + "Musebase 가사 표시 중" + 정지 액션.specialUse포그라운드 타입.WindowManager의TYPE_APPLICATION_OVERLAY뷰(화면 하단 중앙, 반투명 둥근 카드): 현재 줄(크게) + 번역(아래).FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE.글자 단위 카라오케 (
Views/KaraokeTextView.cs)#FFEB3B(Windows 기본과 통일)을 진행 글자 위치까지Path클립으로 덧그린다.InlineTimeTags.CharIndexAt) 있으면 글자 위치까지, 없으면 라인 표시 구간 대비 비율 폴백.LineProgressChanged는 100ms 간격 → 앵커+실시간으로 프레임마다 보간(60fps,postInvalidateOnAnimation).StaticLayout으로 멀티라인/가운데정렬 대응(윗줄 전체 + 현재 줄 좌측~채움 x 클립, 소수 글자 보간).권한/진입 (
MainActivity.cs,AndroidManifest.xml)Settings.CanDrawOverlays확인 → 미허용 시ACTION_MANAGE_OVERLAY_PERMISSION인텐트. "오버레이 권한 허용" 버튼 + 상태 문구(알림 접근 안내와 나란히).SYSTEM_ALERT_WINDOW+FOREGROUND_SERVICE(+FOREGROUND_SERVICE_SPECIAL_USE, Android 14) +POST_NOTIFICATIONS.엔진 재사용 (골든룰)
오버레이는
MusebaseApp이 1회 조립한LyricsCoordinator의CurrentLineChanged/LineProgressChanged와AndroidNowPlayingSource.IsPlayingChanged를 구독만 한다 — 엔진 재조립 없음. 초기 표시는RefreshCurrentLine()로 현재 라인 재발행. 코어/엔진/contracts 무수정.검증
src/Musebase.Android/bin/Debug/net8.0-android/com.countnine.musebase-Signed.apkdotnet build Musebase.sln -c Release성공(Android은 sln 밖 — 코어 미변경 확인).폰 테스트 시나리오
🤖 Generated with Claude Code