import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/catia_instance.dart'; import '../models/catia_status.dart'; import '../services/catia_provider.dart'; import '../theme/app_theme.dart'; import '../theme/desktop_tints.dart'; import 'catia_card_drop_zone.dart'; import 'tinted_card.dart'; import 'desktop_move_dialog.dart'; import 'desktop_pick_dialog.dart'; import 'editable_title.dart'; import 'macro_play_button.dart'; import 'mini_toolbar.dart'; import 'rename_dialog.dart'; import 'mini_pill.dart'; import 'run_script_dialog.dart'; import 'status_badge.dart'; import '../services/workbench_icons.dart'; /// Ultra-kompakt kart: tek satır başlık + tek satır dosya + 16px mini toolbar. /// Başlığa çift tık → yeniden adlandır. Toolbar: 👁 odak • ▶️ başlat • /// 📤 export • ⏹ durdur • 🔄 restart • ✏️ başlık • 📄 dökümanlar • ❌ kapat. /// 🖥 M1 rozeti: CATIA'nın bulunduğu sanal masaüstü. /// 📄 ile açılır döküman listesi: her dökümanda 📂 klasör • 💾 kaydet • ❌ kapat. class CatiaListTile extends StatefulWidget { final CatiaInstance instance; final VoidCallback onTap; const CatiaListTile({super.key, required this.instance, required this.onTap}); @override State createState() => _CatiaListTileState(); } class _CatiaListTileState extends State { bool _docsOpen = true; @override void initState() { super.initState(); // Gerçek pid'lerde masaüstü GUID'ini native'den sorgula (mock pid=0'da atlanır). WidgetsBinding.instance.addPostFrameCallback((_) { context.read().refreshDesktops(); }); } /// Karta bırakılan CATIA dosyası O CATIA'da açılır (bkz. catia_card_drop_zone). @override Widget build(BuildContext context) => widget.instance.placeholder // 👻 Kayıtlı oturumda olup henüz bağlanmamış CATIA: sade, soluk kart; // dosya bırakma/CATIA aksiyonları yok (ortada gerçek bir CATIA yok). ? _buildPlaceholderCard(context) : CatiaCardDropZone( instance: widget.instance, child: _buildCard(context), ); /// "Bağlı değil" yer tutucu kart (kayıtlı oturumdan). Başlık + masaüstü /// rozeti + 🔌 durum hapı, altında ilk dosya (+N), 🔄 (gri kartta: CATIA'yı /// başlat + kayıtlı dökümanları aç), 📄 (kayıtlı dökümanları göster) ve /// ❌ (bu açılışta listeden gizle) düğmeleri. Widget _buildPlaceholderCard(BuildContext context) { final provider = context.read(); final instance = widget.instance; // İki tür: kayıtlı-ama-kapalı (gri) ve ÇALIŞAN-ama-bağlanmamış (kehribar: // CATIA açık, macro kayıt olmamış — dikkat çekmeli). Yalnız gri kartta // 🔄 var: kehribarda zaten çalışan bir süreç var ve macro kaydı olmadan // COM ile döküman açtırılamıyor. final open = instance.isOpenUnconnected; final color = open ? AppColors.warn : CatiaStatus.disconnected.color; // 🟦 Kehribar (açık-ama-bağlanmamış) kartın GERÇEK bir CATIA süreci var // (openPid) — Windows'ta o an aktif pencere buna aitse vurgula. Gri // (tamamen kapalı, openPid=0) kartın karşılığı bir pencere yok, hiç // eşleşmez. final isActiveWindow = open && instance.openPid > 0 && instance.openPid == provider.activePid; final activeColor = Color(provider.sessionSettings.activeWindowColor); final docCount = instance.documents.length; return Opacity( opacity: 0.85, // Tek tık: kayıtlı/eşleşen döküman listesi kapalıysa aç (kapatmaz). // Çift tık: CATIA'yı + masaüstünü odakla (açık hayalette süreç; gri // hayalette kayıtla eşleşen çalışan süreç aranır, yoksa uyarı). child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { if (!_docsOpen && docCount > 0) setState(() => _docsOpen = true); }, onDoubleTap: () => open ? provider.focusOpenGhost(instance.id) : provider.focusSavedGhost(instance.id), child: TintedCard( tint: DesktopTint.forNumber(instance.desktopNumber), // Hayalet kart de masaüstünün tonunda ama daha soluk; durum rengi // (gri/kehribar) çerçevede kalır. color: isActiveWindow ? Color.alphaBlend( activeColor.withValues(alpha: 0.26), DesktopTint.forNumber(instance.desktopNumber).panel) : DesktopTint.forNumber(instance.desktopNumber).panel, borderColor: isActiveWindow ? activeColor.withValues(alpha: 0.85) : color.withValues(alpha: 0.65), borderWidth: isActiveWindow ? 1.4 : 1.2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Row( children: [ Flexible( child: Text( instance.title, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: AppColors.textSecondary, fontWeight: FontWeight.w700, fontSize: 10, height: 1.1, ), ), ), const SizedBox(width: 4), Tooltip( message: (instance.desktopName ?? '').isNotEmpty ? '${open ? 'Sanal masaüstü' : 'Kayıtlı sanal masaüstü'}: ${instance.desktopName}' : (open ? 'Sanal masaüstü' : 'Kayıtlı sanal masaüstü'), child: Text( provider.desktopLabel( instance.desktopGuid, desktopNumber: instance.desktopNumber, ), style: TextStyle( color: AppColors.textMuted, fontSize: 8.5, height: 1.0, ), ), ), const SizedBox(width: 4), const StatusBadge( status: CatiaStatus.disconnected, compact: true, ), ], ), Text( open ? '🔌 Açık ama bağlanmadı (pid ${instance.openPid})' '${instance.fileName.isNotEmpty ? ' · ${instance.fileName}' : ''}' '${docCount > 1 ? ' (+${docCount - 1})' : ''}' : '🔌 Bağlı değil — kayıtlı oturumdan · ${instance.fileName}' '${docCount > 1 ? ' (+${docCount - 1})' : ''}', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: color, fontStyle: FontStyle.italic, fontSize: 8.5, height: 1.2, ), ), const SizedBox(height: 3), MiniToolbar( actions: [ MiniToolAction( emoji: '👁', tooltip: open ? 'Öne getir (başka masaüstündeyse o masaüstüne ' 'geçer) — bu CATIA uygulamaya bağlı değil' : 'Kayıtla eşleşen ÇALIŞAN CATIA varsa masaüstüyle ' 'birlikte öne getirir (yoksa "kapalı" uyarısı)', onTap: () => open ? provider.focusOpenGhost(instance.id) : provider.focusSavedGhost(instance.id), ), if (open && provider.sessionSettings.connectShortcut .trim() .isNotEmpty) MiniToolAction( emoji: '🔌', tooltip: '26. oturum (deneysel): pencereyi öne getirip ' 'Ayarlar\'daki kısayolu gönderir — CATIA\'da bu ' 'kısayola bağlantı makrosu atanmış olmalı', tint: AppColors.ok, onTap: () => provider.triggerConnectShortcut(instance.id), ), if (open) MiniToolAction( emoji: '🚪', tooltip: 'CATIA\'yı kapat: uygulama penceresine kapatma ' 'isteği gönderir (kaydedilmemiş döküman varsa CATIA ' 'sorar)', tint: AppColors.danger, onTap: () => _confirmQuitCatia(context, provider, instance), ), if (!open) MiniToolAction( emoji: '🔄', tooltip: 'Aç: CATIA\'yı başlatır ve kayıtlı ' 'dökümanları açar', tint: AppColors.ok, onTap: () => provider.openSavedGhost(instance.id), ), if (docCount > 0) MiniToolAction( emoji: '📄', tooltip: open ? 'Kayıttan eşleşen dökümanlar ($docCount)' : 'Kayıtlı dökümanlar ($docCount)', onTap: () => setState(() => _docsOpen = !_docsOpen), ), MiniToolAction( emoji: '❌', tooltip: open ? 'Bu açılışta listeden gizle (CATIA kapatılmaz)' : 'Bu açılışta listeden gizle ' '(kayıtlı oturum dosyası silinmez)', tint: AppColors.danger, onTap: () => provider.dismissGhost(instance.id), ), ], ), if (_docsOpen && instance.documents.isNotEmpty) ...[ const SizedBox(height: 3), Container( padding: const EdgeInsets.symmetric( horizontal: 4, vertical: 2, ), decoration: BoxDecoration( color: AppColors.bg, borderRadius: BorderRadius.circular(4), border: Border.all(color: AppColors.border), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ for (final doc in instance.documents) Padding( padding: const EdgeInsets.symmetric(vertical: 1), child: Row( children: [ Text( doc.kindEmoji, style: const TextStyle( fontSize: 9, height: 1.0, ), ), const SizedBox(width: 3), Expanded( child: Text( doc.isActive ? '▶ ${doc.name}' : doc.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 8.5, height: 1.1, fontStyle: FontStyle.italic, fontWeight: doc.isActive ? FontWeight.w700 : null, color: AppColors.textMuted, ), ), ), ], ), ), ], ), ), ], ], ), ), ), ); } Widget _buildCard(BuildContext context) { final provider = context.read(); final instance = widget.instance; final closedDocs = provider.closedDocumentsFor(instance.id); final busy = instance.status.isBusy; final showProgress = busy && instance.progress != null; // Kompakt durum rozeti (StatusBadge) 9px ikondan ibaret — bu kadar // küçükte 🔌 ile ⏱️/💤 gibi ikonlar göz gezdirirken ayırt edilemiyor. // Bağlantı kesildiğinde bu yüzden kartın kendisini de belirgin şekilde // renklendiriyoruz (arka plan + kenarlık + alt satır yazısı). final disconnected = instance.status == CatiaStatus.disconnected; // 🟦 Windows'ta ŞU AN aktif (ön plandaki) pencere bu CATIA'ya aitse // kartı vurgula (bkz. CatiaProvider._activeWindowPollTimer). Bağlantı // kesikken pid eşleşmesi anlamsız — disconnected görünümü önceliklidir. // NOT: CATScript makronun bildirdiği instance.pid launcher/bat ile // başlatılan kurulumlarda GERÇEK pencere pid'inden farklı çıkabiliyor — // bu yüzden önce native probe'un bulduğu gerçek pid'e bakılır, o henüz // yoksa instance.pid'e düşülür. final effectivePid = provider.realWindowPid(instance.id) ?? instance.pid; final isActiveWindow = !disconnected && effectivePid > 0 && effectivePid == provider.activePid; final activeColor = Color(provider.sessionSettings.activeWindowColor); // 🧩 Aktif çalışma alanı (workbench) — bağlı değilse gösterilmez (native // bu durumda zaten kimliği tazelemiyor, eski bir değer görünebilir). final workbenchInfo = disconnected ? null : workbenchInfoFor(instance.workbenchId); // 🎨 Bu CATIA'nın bulunduğu sanal masaüstünün tonu (kart zemini/şeridi). final tint = DesktopTint.forNumber(instance.desktopNumber); return InkWell( // Tek tık: kartı seç + döküman listesi KAPALIYSA aç (tıkla kapatmaz — // kapatmak yalnız 📄 düğmesiyle). Çift tık: bu CATIA'yı ve bulunduğu // sanal masaüstünü odakla (👁 ile aynı). onTap: () { widget.onTap(); if (!_docsOpen) setState(() => _docsOpen = true); }, onDoubleTap: instance.pid > 0 ? () => provider.focusInstance(instance.id) : null, borderRadius: BorderRadius.circular(6), child: TintedCard( tint: tint, // Zemin masaüstünün tonunda (M1 mavi, M2 turuncu…); bağlantı-kesildi // ve aktif-pencere vurgusu tonun ÜSTÜNE biner (ton kaybolmaz). color: disconnected ? Color.alphaBlend( CatiaStatus.disconnected.color.withValues(alpha: 0.16), tint.card) : isActiveWindow ? Color.alphaBlend(activeColor.withValues(alpha: 0.28), tint.card) : tint.card, borderColor: disconnected ? CatiaStatus.disconnected.color.withValues(alpha: 0.75) : isActiveWindow ? activeColor.withValues(alpha: 0.85) : tint.cardBorder, borderWidth: disconnected || isActiveWindow ? 1.4 : 1, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Row( children: [ Flexible( child: EditableTitle( text: instance.title, // Kart başlığı CATIA'nın kendi pencere başlığından türetilir; // ikisi farklıysa (ör. otomatik ad ya da özel ad) kullanıcı // CATIA'nın gerçek başlığını ipucunda görebilsin. tooltip: instance.caption.trim().isEmpty || instance.caption.trim() == instance.title ? 'Değiştirmek için çift tıkla' : 'CATIA penceresinin başlığı: ${instance.caption.trim()}\n' 'Değiştirmek için çift tıkla', style: TextStyle( color: AppColors.textPrimary, fontWeight: FontWeight.w700, fontSize: 10, height: 1.1, ), onRename: (v) => provider.renameInstance(instance.id, v), ), ), const SizedBox(width: 4), // Sanal masaüstü etiketi: CATIA'nın hangi masaüstünde olduğu. // Tıklayınca masaüstü listesi açılır; birini seçmek CATIA'yı // oraya taşır ve o masaüstüne geçer. Tooltip( message: (instance.desktopName ?? '').isNotEmpty ? 'Sanal masaüstü: ${instance.desktopName} — tıkla: masaüstü seç' : 'Sanal masaüstü — tıkla: masaüstü seç', child: InkWell( borderRadius: BorderRadius.circular(4), onTap: instance.pid > 0 ? () => showDesktopPickDialog(context, provider, instance) : null, child: Padding( padding: const EdgeInsets.symmetric( horizontal: 3, vertical: 1, ), child: Text( provider.desktopLabel( instance.desktopGuid, desktopNumber: instance.desktopNumber, ), style: TextStyle( color: tint.label, fontSize: 9, fontWeight: FontWeight.w800, height: 1.0, ), ), ), ), ), const SizedBox(width: 4), StatusBadge(status: instance.status, compact: true), // 🧩 Aktif çalışma alanı (workbench) rozeti — başlık // satırının EN SAĞINDA. `Application.GetWorkbenchId()`den // native'in canlı okuduğu kimlik ikona çevrilir (bkz. // workbench_icons.dart); bağlı değilse ya da CATIA henüz // okumamışsa hiçbir şey gösterilmez (yer kaplamaz). if (workbenchInfo != null) ...[ const SizedBox(width: 4), MiniPill( emoji: workbenchInfo.emoji, label: 'Çalışma alanı: ${workbenchInfo.label}', color: AppColors.accent, compact: true, ), ], ], ), Text( disconnected ? '🔌 Bağlantı kesildi — CATIA kapandı' : (instance.hasCustomTitle ? '${instance.id} · ${instance.fileName}' : instance.fileName), maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: disconnected ? CatiaStatus.disconnected.color : AppColors.textMuted, fontWeight: disconnected ? FontWeight.w700 : null, fontSize: 8.5, height: 1.2, ), ), if (showProgress) ...[ const SizedBox(height: 3), Row( children: [ Expanded( child: ClipRRect( borderRadius: BorderRadius.circular(2), child: LinearProgressIndicator( value: (instance.progress ?? 0) / 100, minHeight: 3, backgroundColor: AppColors.border, color: instance.status.color, ), ), ), const SizedBox(width: 5), Text( '%${instance.progress}', style: TextStyle( color: AppColors.textMuted, fontSize: 8.5, height: 1.0, ), ), ], ), ], const SizedBox(height: 3), // Toolbar solda; ▶ hızlı çalıştır düğmesi SAĞA dayalı. Dar pencerede // toolbar küçülerek sığar (FittedBox), ▶ hep görünür kalır. Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerLeft, child: MiniToolbar( actions: [ MiniToolAction( emoji: '👁', tooltip: instance.connected ? 'Öne getir (başka masaüstündeyse o masaüstüne geçer)' : 'Öne getir — bağlantı yok; pencere süreç ' 'taramasından bulunur (başka masaüstüne geçer)', enabled: instance.connected || instance.pid > 0, onTap: () => provider.focusInstance(instance.id), ), // MiniToolAction( // emoji: '▶️', // tooltip: 'Hesap başlat', // tint: AppColors.ok, // enabled: !busy, // onTap: () => provider.startJob(instance.id), // ), // MiniToolAction( // emoji: '📤', // tooltip: 'Dışa aktar', // tint: AppColors.violet, // enabled: !busy, // onTap: () => provider.exportInstance(instance.id), // ), // MiniToolAction( // emoji: '⏹', // tooltip: 'Durdur', // tint: AppColors.warn, // enabled: busy, // onTap: () => provider.stopInstance(instance.id), // ), MiniToolAction( emoji: '🔄', tooltip: instance.status == CatiaStatus.disconnected ? 'Yeniden Aç: CATIA\'yı tekrar başlatır ve açık dökümanları geri açar' : 'Yeniden başlat', tint: instance.status == CatiaStatus.disconnected ? AppColors.ok : null, enabled: instance.status.isProblem || !busy, onTap: () => instance.status == CatiaStatus.disconnected ? provider.reopenInstance(instance.id) : provider.restartInstance(instance.id), ), MiniToolAction( emoji: '✏️', tooltip: 'Başlığı düzenle', onTap: () => showRenameDialog( context, provider, instance.id, instance.title, ), ), MiniToolAction( emoji: '🖥', tooltip: 'Sanal masaüstü: taşı / adlandır / geç', enabled: instance.pid > 0 && instance.connected, onTap: () => showDesktopMoveDialog( context, provider, instance.id, instance.desktopName, ), ), // MiniToolAction( // emoji: '🧪', // tooltip: instance.pid > 0 && instance.connected // ? 'Makro / kod penceresi: makro dosyası ekle, kod yaz ve ' // 'adıyla kaydet (SystemService.Evaluate / ExecuteScript). ' // 'Hızlı çalıştırma için sağdaki ▶' // : 'Makro/kod için CATIA\'ya bağlı olmalı (yeşil kart)', // tint: AppColors.violet, // enabled: instance.pid > 0 && instance.connected, // onTap: () => showRunScriptDialog( // context, // provider, // instance.id, // instance.title, // ), // ), MiniToolAction( emoji: '📄', tooltip: 'Açık dökümanlar (${instance.documents.length})' '${closedDocs.isNotEmpty ? ' · 🕘 ${closedDocs.length} daha önce açıktı' : ''}', tint: instance.documents.any((d) => !d.saved) ? AppColors.warn : null, onTap: () => setState(() => _docsOpen = !_docsOpen), ), MiniToolAction( emoji: '🚪', tooltip: instance.pid > 0 ? 'CATIA\'yı kapat: uygulama penceresine kapatma isteği ' 'gönderir (kaydedilmemiş döküman varsa CATIA sorar)' : 'Çalışan bir CATIA yok', tint: AppColors.danger, enabled: instance.pid > 0, onTap: () => _confirmQuitCatia(context, provider, instance), ), MiniToolAction( emoji: '❌', tooltip: 'Listeden kaldır (CATIA açık kalır — kapatmak için 🚪)', tint: AppColors.danger, onTap: () => provider.closeInstance(instance.id), ), ], ), ), ), const SizedBox(width: 6), MacroPlayButton(instance: instance, size: 16), ], ), // Açılır döküman listesi: her satırda tür ikonu + ad + mini toolbar. if (_docsOpen && (instance.documents.isNotEmpty || closedDocs.isNotEmpty)) ...[ const SizedBox(height: 3), Container( padding: const EdgeInsets.symmetric(vertical: 2), decoration: BoxDecoration( color: AppColors.bg, borderRadius: BorderRadius.circular(4), border: Border.all(color: AppColors.border), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ for (final doc in instance.documents) Padding( padding: const EdgeInsets.symmetric( horizontal: 4, vertical: 1, ), // Satıra tek tık = CATIA'da bu dökümanı öne al // (🎯 ile aynı işlem; zaten aktifse de CATIA // penceresi öne gelir). Sağdaki mini butonlar kendi // tıklamasını yakalar, satıra taşmaz. child: InkWell( borderRadius: BorderRadius.circular(3), mouseCursor: instance.connected ? SystemMouseCursors.click : SystemMouseCursors.basic, onTap: instance.connected ? () => provider.activateDocument( instance.id, doc.id, ) : null, child: Row( children: [ Text( doc.kindEmoji, style: const TextStyle( fontSize: 9, height: 1.0, ), ), const SizedBox(width: 3), Expanded( child: Text( doc.saved ? (doc.isActive ? '▶ ${doc.name}' : doc.name) : '${doc.isActive ? '▶ ' : ''}${doc.name} •', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 8.5, height: 1.1, fontWeight: doc.isActive ? FontWeight.w700 : null, color: doc.saved ? AppColors.textSecondary : AppColors.warn, ), ), ), const SizedBox(width: 4), MiniToolbar( actions: [ // 🎯 Aktif et: CATIA'da bu dökümanın penceresini // öne getirir (Window.Activate) ve CATIA // penceresini öne alır. Zaten aktifse pasif. MiniToolAction( emoji: '🎯', tooltip: doc.isActive ? 'Bu döküman zaten aktif' : 'Aktif et: CATIA\'da bu dökümanın penceresini öne getirir', tint: AppColors.accent, enabled: !doc.isActive && instance.connected, onTap: () => provider.activateDocument( instance.id, doc.id, ), ), MiniToolAction( emoji: '📂', tooltip: 'Klasörü aç', onTap: () => provider.openDocumentFolder( instance.id, doc.id, ), ), MiniToolAction( emoji: '💾', tooltip: doc.saved ? 'Kaydedildi' : 'Kaydet', enabled: !doc.saved && instance.connected, tint: doc.saved ? AppColors.ok : AppColors.warn, onTap: () => provider.saveDocument( instance.id, doc.id, ), ), MiniToolAction( emoji: '❌', tooltip: instance.connected ? 'Dökümanı kapat (CATIA\'da kapatılır)' : 'Listeden kaldır', tint: AppColors.danger, onTap: () => provider.closeDocument( instance.id, doc.id, ), ), ], ), ], ), ), ), // 🕘 Daha önce açıktı: bu CATIA'da kapanmış (❌ ile ya da // CATIA'nın kendisinde/dışarıdan) dökümanlar. Tek buton: // aynı CATIA'da yeniden aç. for (final cd in closedDocs) Padding( padding: const EdgeInsets.symmetric( horizontal: 4, vertical: 1, ), child: Row( children: [ const Text( '🕘', style: TextStyle(fontSize: 9, height: 1.0), ), const SizedBox(width: 3), Expanded( child: Text( cd.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 8.5, height: 1.1, fontStyle: FontStyle.italic, color: AppColors.textMuted, ), ), ), const SizedBox(width: 4), MiniToolbar( actions: [ MiniToolAction( emoji: '↩️', tooltip: instance.connected ? 'Daha önce açıktı — bu CATIA\'da yeniden aç' : 'Daha önce açıktı (CATIA bağlı değil)', tint: AppColors.accent, enabled: instance.connected, onTap: () => provider.reopenClosedDocument( instance.id, cd, ), ), ], ), ], ), ), ], ), ), ], ], ), ), ); } } /// 🚪 CATIA'yı kapat: tüm uygulamayı kapattığı için önce onay sorar. Onaylanırsa /// CATIA penceresine kapatma isteği gider; kaydedilmemiş dökümanlar için CATIA /// kendi diyaloğunu gösterir (zorla sonlandırma yok). Future _confirmQuitCatia( BuildContext context, CatiaProvider provider, CatiaInstance instance, ) async { final docCount = instance.documents.length; final unsaved = instance.documents.where((d) => !d.saved).length; final detail = StringBuffer('"${instance.title}" CATIA uygulaması kapatılacak'); if (instance.connected && docCount > 0) { detail.write(' ($docCount açık döküman'); if (unsaved > 0) detail.write(', $unsaved kaydedilmemiş'); detail.write(')'); } detail.write( '.\n\nKaydedilmemiş değişiklik varsa CATIA kendisi soracaktır.'); final ok = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('CATIA kapatılsın mı?', style: TextStyle(fontSize: 13)), content: Text(detail.toString(), style: const TextStyle(fontSize: 11)), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(false), child: const Text('İptal'), ), TextButton( onPressed: () => Navigator.of(ctx).pop(true), child: Text('Kapat', style: TextStyle(color: AppColors.danger)), ), ], ), ); if (ok == true) await provider.quitCatia(instance.id); }