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);