From 7a34bedbb69a250b00876110a8357be350b4b17e Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Sat, 3 Oct 2026 02:15:04 +0900 Subject: [PATCH] =?UTF-8?q?=ED=8F=B4=EB=8D=94=20=EC=97=B4=EA=B8=B0=20?= =?UTF-8?q?=C2=B7=20=EA=B2=B0=EA=B3=BC=20=ED=8F=B4=EB=8D=94=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=C2=B7=20=EC=9B=B9=20=EB=B8=8C=EB=9D=BC=EC=9A=B0?= =?UTF-8?q?=EC=A0=80=20=EB=B2=84=ED=8A=BC=20=EC=9C=84=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Android [폴더 열기]: 다른 파일 관리자 (X-plore 등) 가 열려 폴더로 가지 않던 것 → 삼성 내 파일 (그 폴더로 바로) · 시스템 파일 앱 순으로 - MKV 화면: MKV 만들기 옆에 [결과 폴더] (보고 있는 동영상의 jj_mkv 폴더 열기, 아직 없으면 알림) - 웹 브라우저 버튼: MKV 만들기 옆 → 위쪽 왼쪽 공통 버튼 (MKV 화면 다음, 뒤로 앞). 모든 화면 같은 자리 Co-Authored-By: Claude Opus 5.5 --- .../kotlin/com/jj/jj_mkvmaker/MainActivity.kt | 18 ++++++++- lib/ui/app_actions.dart | 20 +++++++++- lib/ui/browser_page.dart | 2 +- lib/ui/home_page.dart | 37 ++++++++++++------- 4 files changed, 58 insertions(+), 19 deletions(-) diff --git a/android/app/src/main/kotlin/com/jj/jj_mkvmaker/MainActivity.kt b/android/app/src/main/kotlin/com/jj/jj_mkvmaker/MainActivity.kt index fe1e589..2f295b5 100644 --- a/android/app/src/main/kotlin/com/jj/jj_mkvmaker/MainActivity.kt +++ b/android/app/src/main/kotlin/com/jj/jj_mkvmaker/MainActivity.kt @@ -59,13 +59,27 @@ class MainActivity : FlutterActivity() { val root = Environment.getExternalStorageDirectory().path if (!path.startsWith(root)) return false val rel = path.removePrefix(root).trim('/') + // 1. 삼성 "내 파일": 그 폴더로 바로 연다 + try { + startActivity( + Intent("samsung.myfiles.intent.action.LAUNCH_MY_FILES") + .setPackage("com.sec.android.app.myfiles") + .putExtra("samsung.myfiles.intent.extra.START_PATH", path) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + ) + return true + } catch (e: Exception) { + } + // 2. 시스템 "파일" 앱 (Google / AOSP). 다른 파일 관리자 (X-plore 등) 는 이 주소의 폴더로 가지 않아 앱을 정해 연다 val uri = android.provider.DocumentsContract.buildDocumentUri( "com.android.externalstorage.documents", "primary:$rel" ) - for (type in listOf(android.provider.DocumentsContract.Document.MIME_TYPE_DIR, "resource/folder")) { + for (pkg in listOf("com.google.android.documentsui", "com.android.documentsui", null)) { try { startActivity( - Intent(Intent.ACTION_VIEW).setDataAndType(uri, type) + Intent(Intent.ACTION_VIEW) + .setDataAndType(uri, android.provider.DocumentsContract.Document.MIME_TYPE_DIR) + .apply { if (pkg != null) setPackage(pkg) } .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION) ) return true diff --git a/lib/ui/app_actions.dart b/lib/ui/app_actions.dart index b0247e5..be02ea2 100644 --- a/lib/ui/app_actions.dart +++ b/lib/ui/app_actions.dart @@ -41,9 +41,12 @@ class AppScope extends InheritedWidget { class AppNavButtons extends StatelessWidget { /// 다운로드 목록 화면 자신 (그 버튼을 "지금 여기" 로 표시) final bool onDownloadsPage; - const AppNavButtons({super.key, this.onDownloadsPage = false}); - static const double width = 4 * 40; + /// 웹 브라우저 화면 자신 + final bool onBrowserPage; + const AppNavButtons({super.key, this.onDownloadsPage = false, this.onBrowserPage = false}); + + static const double width = 5 * 40; /// MKV 화면 (맨 처음 화면) 까지 돌아가기 static void toMkv(BuildContext context) => Navigator.of(context).popUntil((r) => r.isFirst); @@ -91,6 +94,19 @@ class AppNavButtons extends StatelessWidget { atRoot ? null : () => toMkv(context), here: atRoot, ), + // 웹 브라우저: MKV 화면 버튼 다음 (모든 화면 같은 자리) + btn( + Icon(Icons.public, color: onBrowserPage ? JjColors.accent : null), + onBrowserPage ? '웹 브라우저 (지금 여기)' : '웹 브라우저', + scope?.bookmarks == null || onBrowserPage + ? null + : () => Navigator.push( + context, + MaterialPageRoute( + builder: (_) => + BrowserPage(c: scope!.controller, downloads: scope.downloads, bookmarks: scope.bookmarks!))), + here: onBrowserPage, + ), btn(const Icon(Icons.arrow_back), '뒤로', atRoot ? null : () => Navigator.maybePop(context)), btn( Icon(Icons.download_for_offline_outlined, color: onDownloadsPage ? JjColors.accent : null), diff --git a/lib/ui/browser_page.dart b/lib/ui/browser_page.dart index 2b78693..3fcf74f 100644 --- a/lib/ui/browser_page.dart +++ b/lib/ui/browser_page.dart @@ -274,7 +274,7 @@ class _BrowserPageState extends State { color: JjColors.panel, padding: const EdgeInsets.only(left: 8, right: appBarRightPadding), child: Row(children: [ - const AppNavButtons(), + const AppNavButtons(onBrowserPage: true), const SizedBox(width: 8), Container(width: 1, height: 24, color: JjColors.border), const SizedBox(width: 4), diff --git a/lib/ui/home_page.dart b/lib/ui/home_page.dart index 448fe51..77109ad 100644 --- a/lib/ui/home_page.dart +++ b/lib/ui/home_page.dart @@ -12,7 +12,6 @@ import '../core/models.dart'; import '../core/output_paths.dart'; import 'ai_dialog.dart'; import 'app_actions.dart'; -import 'browser_page.dart'; import 'downloads_page.dart'; import 'player_page.dart'; import 'subtitle_editor_page.dart'; @@ -95,6 +94,21 @@ class _TopBar extends StatelessWidget { const _TopBar({required this.c, this.downloads, this.onExit, this.bookmarks}); /// 고른 동영상이 없을 때: 목록 전체를 만들지 묻는다 + /// 보고 있는 동영상의 결과 폴더 (jj_mkv) 를 탐색기 · 파일 앱으로. 아직 없으면 알린다. + Future _openOutput(BuildContext context) async { + final v = c.selected; + if (v == null) return; + final dir = outputDirFor(v.path); + if (!await Directory(dir).exists()) { + if (context.mounted) { + ScaffoldMessenger.maybeOf(context) + ?.showSnackBar(SnackBar(content: Text('아직 만든 MKV · 자막이 없습니다: $dir'))); + } + return; + } + await c.services.shell.revealFile(dir); + } + Future _confirmBuildAll(BuildContext context) async { final todo = c.videos.where((v) => v.status != JobStatus.done).length; final ok = await showDialog( @@ -139,7 +153,7 @@ class _TopBar extends StatelessWidget { (c.busy ? (jobText ? 350 : 60) : 0) + (hasPlayer ? (rightText ? 201 : 48) : 0) + (mkvText ? 166 + (c.busy && jobText ? 60 : 0) : 48) + - (bookmarks != null ? (rightText ? 138 : 48) : 0) + + (rightText ? 166 : 48) + // 결과 폴더 (dlBox ? 162 : 0) + (usage ? 220 : 0) + 96 + 92 + (c.checked.isEmpty ? 0 : 3 * 26) + @@ -241,18 +255,13 @@ class _TopBar extends StatelessWidget { icon: Icon(c.busy ? Icons.playlist_add : Icons.play_arrow, size: 20), ), ), - if (bookmarks != null) ...[ - const SizedBox(width: 8), - action( - Icons.public, - '브라우저', - () => Navigator.push( - context, - MaterialPageRoute( - builder: (_) => BrowserPage(c: c, downloads: downloads, bookmarks: bookmarks!))), - text: rightText, - tip: '웹 브라우저'), - ], + // 만든 MKV 가 있는 폴더 (jj_mkv). 웹 브라우저 버튼은 왼쪽 공통 버튼으로 옮김 + const SizedBox(width: 8), + action(Icons.folder_special_outlined, '결과 폴더', c.selected == null ? null : () => _openOutput(context), + text: rightText, + tip: c.selected == null + ? '결과 폴더 열기 (동영상을 고르세요)' + : '결과 폴더 열기: ${outputDirFor(c.selected!.path)}'), if (dlBox) ...[ const SizedBox(width: 12), _DownloadBox(d: downloads!),