diff --git a/docs/IOS_PUSH_NOTIFICATIONS.md b/docs/IOS_PUSH_NOTIFICATIONS.md new file mode 100644 index 0000000..9a4f09f --- /dev/null +++ b/docs/IOS_PUSH_NOTIFICATIONS.md @@ -0,0 +1,113 @@ +# iOS Push Notification Desteği + +VibeTorrent artık iOS 16.4+ cihazlarda push notification destekliyor! 🎉 + +## Gereksinimler + +- **iOS 16.4 veya üzeri** (Mart 2023 ve sonrası) +- Safari tarayıcısı +- HTTPS bağlantısı (production ortamında) + +## Nasıl Kullanılır? + +### 1. Ana Ekrana Ekle + +Push notification'lar **sadece Home Screen'e eklenmiş PWA'larda çalışır**. Safari'den doğrudan çalışmaz! + +#### Adımlar: +1. Safari'de uygulamayı açın +2. Alt kısımdaki **Paylaş** butonuna tıklayın (⬆️ ikonu) +3. **"Ana Ekrana Ekle"** seçeneğini seçin +4. İsmi onaylayıp **"Ekle"** butonuna basın +5. Ana ekrandaki ikona tıklayarak uygulamayı açın + +### 2. Notification İzni Verin + +İlk açılışta uygulama notification izni isteyecektir: +- **"İzin Ver"** seçeneğini seçin +- Eğer atlarsanız, daha sonra Safari ayarlarından izin verebilirsiniz + +### 3. Push Notification Otomatik Aktif Olur + +Ana ekrandan açılan PWA'da: +- Uygulama otomatik olarak push notification'a abone olur +- Torrent tamamlandığında bildirim alırsınız +- **Uygulama kapalı olsa bile bildirim gelir!** + +## Teknik Detaylar + +### iOS Safari Kısıtlamaları: + +✅ **Çalışır:** +- Home Screen'e eklenmiş PWA +- iOS 16.4+ Safari + +❌ **Çalışmaz:** +- Safari browser mode (standalone olmayan) +- iOS 16.4 altı sürümler +- Chrome veya diğer tarayıcılar iOS'ta (WebKit kısıtlaması) + +### Test Etme: + +1. iOS cihazınızdan production URL'e gidin (HTTPS gerekli) +2. Ana ekrana ekleyin +3. Bir torrent indirin ve tamamlanmasını bekleyin +4. Uygulamayı kapatın +5. Torrent tamamlandığında notification alacaksınız! + +### Sorun Giderme: + +**"Push notification desteklenmiyor" mesajı görüyorum:** +- Ana ekrana eklediniz mi? Safari'den değil, ana ekrandaki ikondan açmalısınız +- iOS 16.4+ sürümü mü kullanıyorsunuz? + +**Notification gelmiyor:** +- Settings → VibeTorrent → Notifications → izinlerin açık olduğundan emin olun +- Ana ekrandaki PWA'dan açtığınızdan emin olun (Safari'den değil) +- Developer Console'da "Push subscription" log'unu kontrol edin + +**Notification izni reddettim, nasıl yeniden açarım?** +- Settings → Safari → Advanced → Website Data → VibeTorrent'i silin +- Uygulamayı ana ekrandan silin ve yeniden ekleyin + +## Platform Karşılaştırması + +| Platform | Push Support | Gereksinim | +|----------|--------------|------------| +| **Android Chrome** | ✅ Tam destek | Browser veya PWA | +| **iOS 16.4+ Safari** | ✅ PWA destekli | Ana ekrana eklenmiş olmalı | +| **iOS 16.3 ve altı** | ❌ Desteklenmez | - | +| **Desktop (Chrome/Edge)** | ✅ Tam destek | Browser veya PWA | +| **Desktop Safari** | ⚠️ Sınırlı | macOS 13+ (Ventura) | + +## Güvenlik + +- VAPID anahtarları kullanılıyor +- End-to-end şifreli push notification +- Subscription'lar backend'de güvenli saklanıyor +- iOS Safari security model tam uyumlu + +## Geliştiriciler İçin + +```rust +// iOS detection +if crate::utils::platform::is_ios() { + // iOS-specific kod +} + +// Standalone mode kontrolü +if crate::utils::platform::is_standalone() { + // PWA mode +} + +// Push notification desteği +if crate::utils::platform::supports_push_notifications() { + // Subscribe +} +``` + +## Kaynaklar + +- [iOS Safari Web Push](https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/) +- [PWA on iOS Guide](https://developer.apple.com/wwdc23/10120) +- [Web Push API](https://developer.mozilla.org/en-US/docs/Web/API/Push_API) diff --git a/frontend/index.html b/frontend/index.html index bb628df..ff1edb5 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -11,9 +11,13 @@ + + + + diff --git a/frontend/manifest.json b/frontend/manifest.json index 2860ca0..efff2a5 100644 --- a/frontend/manifest.json +++ b/frontend/manifest.json @@ -3,6 +3,7 @@ "short_name": "VibeTorrent", "description": "Modern web-based torrent client with real-time updates", "start_url": "/", + "scope": "/", "display": "standalone", "background_color": "#1d232a", "theme_color": "#1d232a", diff --git a/frontend/src/app.rs b/frontend/src/app.rs index 0555f16..9f184d9 100644 --- a/frontend/src/app.rs +++ b/frontend/src/app.rs @@ -16,6 +16,27 @@ pub fn App() -> impl IntoView { // Wait a bit for service worker to be ready gloo_timers::future::TimeoutFuture::new(2000).await; + // Check if running on iOS and not standalone + if let Some(ios_message) = crate::utils::platform::get_ios_notification_info() { + tracing::warn!("iOS detected: {}", ios_message); + + // Show toast to inform user + if let Some(store) = use_context::() { + crate::store::show_toast_with_signal( + store.notifications, + shared::NotificationLevel::Info, + ios_message, + ); + } + return; + } + + // Check if push notifications are supported + if !crate::utils::platform::supports_push_notifications() { + tracing::warn!("Push notifications not supported on this platform"); + return; + } + // Check if Notification API is available and permission is granted let window = web_sys::window().expect("window should exist"); if let Ok(notification_class) = js_sys::Reflect::get(&window, &"Notification".into()) { diff --git a/frontend/src/utils/mod.rs b/frontend/src/utils/mod.rs index 2e566f3..d664481 100644 --- a/frontend/src/utils/mod.rs +++ b/frontend/src/utils/mod.rs @@ -1,6 +1,7 @@ use tailwind_fuse::merge::tw_merge; pub mod notification; +pub mod platform; pub fn cn(classes: impl AsRef) -> String { tw_merge(classes.as_ref()) diff --git a/frontend/src/utils/platform.rs b/frontend/src/utils/platform.rs new file mode 100644 index 0000000..ecd088b --- /dev/null +++ b/frontend/src/utils/platform.rs @@ -0,0 +1,70 @@ +/// Platform detection utilities + +/// Check if running on iOS +pub fn is_ios() -> bool { + let window = web_sys::window().expect("window should exist"); + let navigator = window.navigator(); + let user_agent = navigator.user_agent().unwrap_or_default(); + + user_agent.contains("iPhone") + || user_agent.contains("iPad") + || user_agent.contains("iPod") +} + +/// Check if running as a standalone PWA (installed on home screen) +pub fn is_standalone() -> bool { + let window = web_sys::window().expect("window should exist"); + let navigator = window.navigator(); + + // Check for iOS standalone mode + if let Ok(standalone) = js_sys::Reflect::get(&navigator, &"standalone".into()) { + if let Some(is_standalone) = standalone.as_bool() { + return is_standalone; + } + } + + // Check display-mode via matchMedia + if let Ok(match_media_fn) = js_sys::Reflect::get(&window, &"matchMedia".into()) { + if match_media_fn.is_function() { + let match_media = js_sys::Function::from(match_media_fn); + if let Ok(result) = match_media.call1(&window, &"(display-mode: standalone)".into()) { + if let Ok(matches) = js_sys::Reflect::get(&result, &"matches".into()) { + if let Some(is_match) = matches.as_bool() { + return is_match; + } + } + } + } + } + + false +} + +/// Check if push notifications are supported +pub fn supports_push_notifications() -> bool { + let window = web_sys::window().expect("window should exist"); + + // Check if PushManager exists + if let Ok(navigator) = js_sys::Reflect::get(&window, &"navigator".into()) { + if let Ok(service_worker) = js_sys::Reflect::get(&navigator, &"serviceWorker".into()) { + if let Ok(push_manager) = js_sys::Reflect::get(&service_worker, &"PushManager".into()) { + return !push_manager.is_undefined(); + } + } + } + + false +} + +/// Get platform-specific notification message +pub fn get_ios_notification_info() -> Option { + if is_ios() && !is_standalone() { + Some( + "iOS'ta push notification alabilmek için uygulamayı Ana Ekran'a eklemelisiniz. \ + Safari menüsünden 'Ana Ekrana Ekle' seçeneğini kullanın." + .to_string() + ) + } else { + None + } +} diff --git a/frontend/sw.js b/frontend/sw.js index 4e63588..cdeb36a 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -110,6 +110,13 @@ self.addEventListener('push', (event) => { badge: data.badge || '/icon-192.png', tag: data.tag || 'vibetorrent-notification', requireInteraction: false, + // iOS-specific: vibrate pattern (if supported) + vibrate: [200, 100, 200], + // Add data for notification click handling + data: { + url: data.url || '/', + timestamp: Date.now() + } }; console.log('[Service Worker] Showing notification:', title, options);