mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-06-28 20:09:51 +00:00
Merge branch 'beta'
This commit is contained in:
commit
ecc9cf1073
19 changed files with 926 additions and 522 deletions
|
@ -779,5 +779,17 @@
|
||||||
"enablePlainDnsDescription": "Plain DNS is enabled by default. You can disable it to force all devices to use encrypted DNS. To do this, you must enable at least one encrypted DNS protocol.",
|
"enablePlainDnsDescription": "Plain DNS is enabled by default. You can disable it to force all devices to use encrypted DNS. To do this, you must enable at least one encrypted DNS protocol.",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"loadingChangelog": "Loading changelog...",
|
"loadingChangelog": "Loading changelog...",
|
||||||
"invalidIpOrUrl": "Invalid IP address or URL"
|
"invalidIpOrUrl": "Invalid IP address or URL",
|
||||||
|
"addPersistentClient": "Add as a persistent client",
|
||||||
|
"blockThisClientOnly": "Block for this client only",
|
||||||
|
"unblockThisClientOnly": "Unblock for this client only",
|
||||||
|
"domainBlockedThisClient": "{domain} blocked for this client",
|
||||||
|
"domainUnblockedThisClient": "{domain} unblocked for this client",
|
||||||
|
"disallowThisClient": "Disallow this client",
|
||||||
|
"allowThisClient": "Allow this client",
|
||||||
|
"clientAllowedSuccessfully": "Client allowed successfully",
|
||||||
|
"clientDisallowedSuccessfully": "Client disallowed successfully",
|
||||||
|
"changesNotSaved": "Changes could not be saved",
|
||||||
|
"allowingClient": "Allowing client...",
|
||||||
|
"disallowingClient": "Disallowing client..."
|
||||||
}
|
}
|
|
@ -779,5 +779,17 @@
|
||||||
"enablePlainDnsDescription": "El DNS simple (sin cifrado) está activado de forma predeterminada. Puedes desactivarlo para obligar a todos los dispositivos a utilizar DNS cifrado. Para ello, debes habilitar al menos un protocolo DNS cifrado.",
|
"enablePlainDnsDescription": "El DNS simple (sin cifrado) está activado de forma predeterminada. Puedes desactivarlo para obligar a todos los dispositivos a utilizar DNS cifrado. Para ello, debes habilitar al menos un protocolo DNS cifrado.",
|
||||||
"date": "Fecha",
|
"date": "Fecha",
|
||||||
"loadingChangelog": "Cargando registro de cambios...",
|
"loadingChangelog": "Cargando registro de cambios...",
|
||||||
"invalidIpOrUrl": "Dirección IP o URL no válida"
|
"invalidIpOrUrl": "Dirección IP o URL no válida",
|
||||||
|
"addPersistentClient": "Añadir como cliente persistente",
|
||||||
|
"blockThisClientOnly": "Bloquear sólo para este cliente",
|
||||||
|
"unblockThisClientOnly": "Desbloquear sólo para este cliente",
|
||||||
|
"domainBlockedThisClient": "{domain} bloqueado para este cliente",
|
||||||
|
"domainUnblockedThisClient": "{domain} desbloqueado para este cliente",
|
||||||
|
"disallowThisClient": "No permitir este cliente",
|
||||||
|
"allowThisClient": "Permitir este cliente",
|
||||||
|
"clientAllowedSuccessfully": "Cliente permitido correctamente",
|
||||||
|
"clientDisallowedSuccessfully": "Cliente no permitido correctamente",
|
||||||
|
"changesNotSaved": "Los cambios no han podido ser guardados",
|
||||||
|
"allowingClient": "Permitiendo cliente...",
|
||||||
|
"disallowingClient": "No permitiendo cliente..."
|
||||||
}
|
}
|
|
@ -75,7 +75,7 @@
|
||||||
"userNotEmpty": "Kullanıcı adı boş bırakılamaz",
|
"userNotEmpty": "Kullanıcı adı boş bırakılamaz",
|
||||||
"passwordNotEmpty": "Şifre boş bırakılamaz",
|
"passwordNotEmpty": "Şifre boş bırakılamaz",
|
||||||
"examplePath": "Örnek: /adguard",
|
"examplePath": "Örnek: /adguard",
|
||||||
"helperPath": "Ters proxy kullanıyorsanız",
|
"helperPath": "Eğer ters proxy kullanıyorsanız",
|
||||||
"aboutApp": "Uygulama hakkında",
|
"aboutApp": "Uygulama hakkında",
|
||||||
"appVersion": "Uygulama sürümü",
|
"appVersion": "Uygulama sürümü",
|
||||||
"createdBy": "Geliştirici",
|
"createdBy": "Geliştirici",
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
"logsCopiedClipboard": "Günlükler panoya kopyalandı",
|
"logsCopiedClipboard": "Günlükler panoya kopyalandı",
|
||||||
"advancedSettings": "Gelişmiş ayarlar",
|
"advancedSettings": "Gelişmiş ayarlar",
|
||||||
"dontCheckCertificate": "SSL sertifikasını kontrol etme",
|
"dontCheckCertificate": "SSL sertifikasını kontrol etme",
|
||||||
"dontCheckCertificateDescription": "Sunucunun SSL sertifikası doğrulamasını geçersiz kılar",
|
"dontCheckCertificateDescription": "Sunucunun SSL sertifikası doğrulamasını geçersiz kılar.",
|
||||||
"advancedSetupDescription": "Gelişmiş seçenekleri yönet",
|
"advancedSetupDescription": "Gelişmiş seçenekleri yönet",
|
||||||
"settingsUpdatedSuccessfully": "Ayarlar başarıyla güncellendi.",
|
"settingsUpdatedSuccessfully": "Ayarlar başarıyla güncellendi.",
|
||||||
"cannotUpdateSettings": "Ayarlar güncellenemiyor.",
|
"cannotUpdateSettings": "Ayarlar güncellenemiyor.",
|
||||||
|
@ -131,11 +131,11 @@
|
||||||
"rewrite": "Yeniden Yaz",
|
"rewrite": "Yeniden Yaz",
|
||||||
"status": "Durum",
|
"status": "Durum",
|
||||||
"result": "Sonuç",
|
"result": "Sonuç",
|
||||||
"time": "Zaman",
|
"time": "Saat",
|
||||||
"blocklist": "Engelleme Listesi",
|
"blocklist": "Engelleme Listesi",
|
||||||
"request": "İstek",
|
"request": "İstek",
|
||||||
"domain": "Alan adı",
|
"domain": "Alan adı",
|
||||||
"type": "Tip",
|
"type": "Tür",
|
||||||
"clas": "Sınıf",
|
"clas": "Sınıf",
|
||||||
"response": "Yanıt",
|
"response": "Yanıt",
|
||||||
"dnsServer": "DNS sunucusu",
|
"dnsServer": "DNS sunucusu",
|
||||||
|
@ -204,7 +204,7 @@
|
||||||
"noUpstreamServers": "Üst sunucu yok.",
|
"noUpstreamServers": "Üst sunucu yok.",
|
||||||
"willBeUsedGeneralServers": "Genel üst sunucular kullanılacak.",
|
"willBeUsedGeneralServers": "Genel üst sunucular kullanılacak.",
|
||||||
"added": "Eklenenler",
|
"added": "Eklenenler",
|
||||||
"clientUpdatedSuccessfully": "İstemci başarıyla güncellendi",
|
"clientUpdatedSuccessfully": "İstemci ayarları başarıyla güncellendi",
|
||||||
"clientNotUpdated": "İstemci güncellenemedi",
|
"clientNotUpdated": "İstemci güncellenemedi",
|
||||||
"clientDeletedSuccessfully": "İstemci başarıyla kaldırıldı",
|
"clientDeletedSuccessfully": "İstemci başarıyla kaldırıldı",
|
||||||
"clientNotDeleted": "İstemci silinemedi",
|
"clientNotDeleted": "İstemci silinemedi",
|
||||||
|
@ -308,8 +308,8 @@
|
||||||
"addImportant": "Başına $important ekle",
|
"addImportant": "Başına $important ekle",
|
||||||
"howCreateRules": "Özel kurallar nasıl oluşturulur?",
|
"howCreateRules": "Özel kurallar nasıl oluşturulur?",
|
||||||
"examples": "Örnekler",
|
"examples": "Örnekler",
|
||||||
"example1": "example.org (ornek.org) ve tüm alt alan adlarına erişimi engeller.",
|
"example1": "example.org ve tüm alt alan adlarına erişimi engeller.",
|
||||||
"example2": "example.org (ornek.org) ve tüm alt alan adlarına erişimi engellemeyi kaldırır.",
|
"example2": "example.org ve tüm alt alan adlarına erişimi engellemeyi kaldırır.",
|
||||||
"example3": "Yorum ekler.",
|
"example3": "Yorum ekler.",
|
||||||
"example4": "Belirtilen düzenli ifadeye uyan alan adlarına erişimi engeller.",
|
"example4": "Belirtilen düzenli ifadeye uyan alan adlarına erişimi engeller.",
|
||||||
"moreInformation": "Daha fazla bilgi",
|
"moreInformation": "Daha fazla bilgi",
|
||||||
|
@ -418,7 +418,7 @@
|
||||||
"logSettingsNotLoaded": "Günlük ayarları yüklenemedi.",
|
"logSettingsNotLoaded": "Günlük ayarları yüklenemedi.",
|
||||||
"updatingSettings": "Ayarlar güncelleniyor...",
|
"updatingSettings": "Ayarlar güncelleniyor...",
|
||||||
"logsConfigUpdated": "Günlük ayarları başarıyla güncellendi",
|
"logsConfigUpdated": "Günlük ayarları başarıyla güncellendi",
|
||||||
"logsConfigNotUpdated": "Günlük ayarları başarıyla güncellendi",
|
"logsConfigNotUpdated": "Günlük ayarları güncellenemedi",
|
||||||
"deletingLogs": "Günlükler temizleniyor...",
|
"deletingLogs": "Günlükler temizleniyor...",
|
||||||
"logsCleared": "Günlükler başarıyla temizlendi",
|
"logsCleared": "Günlükler başarıyla temizlendi",
|
||||||
"logsNotCleared": "Günlükler temizlenemedi",
|
"logsNotCleared": "Günlükler temizlenemedi",
|
||||||
|
@ -436,7 +436,7 @@
|
||||||
"parallelRequests": "Paralel istekler",
|
"parallelRequests": "Paralel istekler",
|
||||||
"fastestIpAddress": "En hızlı IP adresi",
|
"fastestIpAddress": "En hızlı IP adresi",
|
||||||
"loadBalancingDescription": "Her seferinde bir üst sunucuya sorgu yapar. AdGuard Home, sunucuyu seçmek için ağırlıklı rastgele algoritmasını kullanır, böylece en hızlı sunucu daha sık kullanılır.",
|
"loadBalancingDescription": "Her seferinde bir üst sunucuya sorgu yapar. AdGuard Home, sunucuyu seçmek için ağırlıklı rastgele algoritmasını kullanır, böylece en hızlı sunucu daha sık kullanılır.",
|
||||||
"parallelRequestsDescription": "Tüm üst sunucuları aynı anda sorgulayarak çözümlemeyi hızlandırmak için paralel sorgular kullanır.",
|
"parallelRequestsDescription": "Tüm üst sunucuları aynı anda sorgulayarak çözümlemeyi hızlandırmak için paralel sorgular kullanılır.",
|
||||||
"fastestIpAddressDescription": "Tüm DNS sunucularına sorgu yapın ve tüm yanıtlar arasında en hızlı IP adresini döndürür. Bu, AdGuard Home'un tüm DNS sunucularından yanıtları beklemesi gerektiği için DNS sorgularını yavaşlatır, ancak genel bağlantıyı iyileştirir.",
|
"fastestIpAddressDescription": "Tüm DNS sunucularına sorgu yapın ve tüm yanıtlar arasında en hızlı IP adresini döndürür. Bu, AdGuard Home'un tüm DNS sunucularından yanıtları beklemesi gerektiği için DNS sorgularını yavaşlatır, ancak genel bağlantıyı iyileştirir.",
|
||||||
"noBootstrapDns": "Önyükleme DNS sunucuları eklenmedi.",
|
"noBootstrapDns": "Önyükleme DNS sunucuları eklenmedi.",
|
||||||
"bootstrapDnsServersInfo": "Önyükleme DNS sunucuları, üst kaynaklarda belirttiğiniz DoH/DoT çözümleyicilerinin IP adreslerini çözmek için kullanılır.",
|
"bootstrapDnsServersInfo": "Önyükleme DNS sunucuları, üst kaynaklarda belirttiğiniz DoH/DoT çözümleyicilerinin IP adreslerini çözmek için kullanılır.",
|
||||||
|
@ -469,7 +469,7 @@
|
||||||
"customIpDescription": "Manuel olarak ayarlanmış bir IP adresi ile yanıt verir.",
|
"customIpDescription": "Manuel olarak ayarlanmış bir IP adresi ile yanıt verir.",
|
||||||
"dnsCacheConfig": "DNS önbellek yapılandırması",
|
"dnsCacheConfig": "DNS önbellek yapılandırması",
|
||||||
"cacheSize": "Önbellek boyutu",
|
"cacheSize": "Önbellek boyutu",
|
||||||
"inBytes": "Alınacak önbelleğin boyutunu ayarla (bayt olarak)",
|
"inBytes": "Alınacak önbelleğin boyutunu ayarla (Bayt olarak)",
|
||||||
"overrideMinimumTtl": "Minimum kullanım süresini geçersiz kıl",
|
"overrideMinimumTtl": "Minimum kullanım süresini geçersiz kıl",
|
||||||
"overrideMinimumTtlDescription": "DNS yanıtlarını önbelleğe alırken üst sunucudan alınan minimum kullanım süresi değerini (TTL) saniye olarak ayarlayın.",
|
"overrideMinimumTtlDescription": "DNS yanıtlarını önbelleğe alırken üst sunucudan alınan minimum kullanım süresi değerini (TTL) saniye olarak ayarlayın.",
|
||||||
"overrideMaximumTtl": "Maksimum kullanım süresini geçersiz kıl",
|
"overrideMaximumTtl": "Maksimum kullanım süresini geçersiz kıl",
|
||||||
|
@ -494,7 +494,7 @@
|
||||||
"dnsCacheConfigDescription": "Sunucunun DNS önbelleğini nasıl yöneteceğini yapılandır",
|
"dnsCacheConfigDescription": "Sunucunun DNS önbelleğini nasıl yöneteceğini yapılandır",
|
||||||
"comment": "Yorum",
|
"comment": "Yorum",
|
||||||
"address": "Adres",
|
"address": "Adres",
|
||||||
"commentsDescription": "Yorumlar her zaman # işareti ile başlar. Onu eklemenize gerek yok, otomatik olarak eklenir.",
|
"commentsDescription": "Yorumlar her zaman # işareti ile başlar. Eklemenize gerek yok, otomatik olarak eklenecektir.",
|
||||||
"encryptionSettings": "Şifreleme ayarları",
|
"encryptionSettings": "Şifreleme ayarları",
|
||||||
"encryptionSettingsDescription": "Şifreleme (HTTPS/QUIC/TLS) desteği",
|
"encryptionSettingsDescription": "Şifreleme (HTTPS/QUIC/TLS) desteği",
|
||||||
"loadingEncryptionSettings": "Şifreleme ayarları yükleniyor...",
|
"loadingEncryptionSettings": "Şifreleme ayarları yükleniyor...",
|
||||||
|
@ -560,8 +560,8 @@
|
||||||
"validPrivateKey": "Geçerli özel anahtar",
|
"validPrivateKey": "Geçerli özel anahtar",
|
||||||
"expirationDate": "Son kullanma tarihi",
|
"expirationDate": "Son kullanma tarihi",
|
||||||
"keysNotMatch": "Geçersiz bir sertifika veya anahtar: tls: özel anahtar genel anahtarla eşleşmiyor.",
|
"keysNotMatch": "Geçersiz bir sertifika veya anahtar: tls: özel anahtar genel anahtarla eşleşmiyor.",
|
||||||
"timeLogs": "Günlüklerde işlem süresi göster",
|
"timeLogs": "Günlüklerde işlem süresini göster",
|
||||||
"timeLogsDescription": "Günlükler listesinde zaman yerine işlem süresini göster.",
|
"timeLogsDescription": "Günlükler listesinde zaman yerine işlem süresini gösterir.",
|
||||||
"hostNames": "Ana bilgisayar adları",
|
"hostNames": "Ana bilgisayar adları",
|
||||||
"keyType": "Anahtar türü",
|
"keyType": "Anahtar türü",
|
||||||
"updateAvailable": "Güncelleme mevcut",
|
"updateAvailable": "Güncelleme mevcut",
|
||||||
|
@ -626,7 +626,7 @@
|
||||||
"appUpdates": "Uygulama güncellemeleri",
|
"appUpdates": "Uygulama güncellemeleri",
|
||||||
"usingLatestVersion": "En son sürümü kullanıyorsunuz",
|
"usingLatestVersion": "En son sürümü kullanıyorsunuz",
|
||||||
"ipLogs": "Günlüklerde IP adresini göster",
|
"ipLogs": "Günlüklerde IP adresini göster",
|
||||||
"ipLogsDescription": "Günlükler listesinde istemci adı yerine IP adresini göster.",
|
"ipLogsDescription": "Günlükler listesinde istemci adı yerine IP adresini gösterir.",
|
||||||
"application": "Uygulama",
|
"application": "Uygulama",
|
||||||
"combinedChart": "Birleştirilmiş grafik",
|
"combinedChart": "Birleştirilmiş grafik",
|
||||||
"combinedChartDescription": "Tüm grafikleri bir araya getirir.",
|
"combinedChartDescription": "Tüm grafikleri bir araya getirir.",
|
||||||
|
@ -688,7 +688,7 @@
|
||||||
"yourVersion": "Yüklü sürüm: {version}",
|
"yourVersion": "Yüklü sürüm: {version}",
|
||||||
"minimumRequiredVersion": "Gerekli minimum sürüm: {version}",
|
"minimumRequiredVersion": "Gerekli minimum sürüm: {version}",
|
||||||
"topUpstreams": "Öne çıkan DNS sunucuları",
|
"topUpstreams": "Öne çıkan DNS sunucuları",
|
||||||
"averageUpstreamResponseTime": "DNS sunucusu ortalama işlem süresi" ,
|
"averageUpstreamResponseTime": "DNS sunucuları işlem süresi" ,
|
||||||
"dhcpNotAvailable": "DHCP sunucusu kullanılamıyor.",
|
"dhcpNotAvailable": "DHCP sunucusu kullanılamıyor.",
|
||||||
"osServerInstalledIncompatible": "AdGuard Home, işletim sisteminizde DHCP sunucusu çalıştıramıyor.",
|
"osServerInstalledIncompatible": "AdGuard Home, işletim sisteminizde DHCP sunucusu çalıştıramıyor.",
|
||||||
"resetSettings": "Ayarları sıfırla",
|
"resetSettings": "Ayarları sıfırla",
|
||||||
|
@ -721,7 +721,7 @@
|
||||||
"unblockingClient": "İstemci engeli kaldırılıyor...",
|
"unblockingClient": "İstemci engeli kaldırılıyor...",
|
||||||
"upstreamDnsCacheConfiguration": "DNS önbellek yapılandırması",
|
"upstreamDnsCacheConfiguration": "DNS önbellek yapılandırması",
|
||||||
"enableDnsCachingClient": "Bu istemci için DNS önbelleğe almayı etkinleştir",
|
"enableDnsCachingClient": "Bu istemci için DNS önbelleğe almayı etkinleştir",
|
||||||
"dnsCacheSize": "DNS önbellek boyutu (bayt cinsinden)",
|
"dnsCacheSize": "DNS önbellek boyutu (Bayt cinsinden)",
|
||||||
"nameInvalid": "Ad gereklidir",
|
"nameInvalid": "Ad gereklidir",
|
||||||
"oneIdentifierRequired": "En az bir tanımlayıcı gereklidir",
|
"oneIdentifierRequired": "En az bir tanımlayıcı gereklidir",
|
||||||
"dnsCacheNumber": "DNS önbellek boyutu bir rakam içermelidir",
|
"dnsCacheNumber": "DNS önbellek boyutu bir rakam içermelidir",
|
||||||
|
@ -754,7 +754,9 @@
|
||||||
"statisticsSettingsDescription": "İstatistikler için veri toplamayı yapılandır",
|
"statisticsSettingsDescription": "İstatistikler için veri toplamayı yapılandır",
|
||||||
"loadingStatisticsSettings": "İstatistik ayarları yükleniyor...",
|
"loadingStatisticsSettings": "İstatistik ayarları yükleniyor...",
|
||||||
"statisticsSettingsLoadError": "İstatistik ayarları yüklenirken bir hata oluştu.",
|
"statisticsSettingsLoadError": "İstatistik ayarları yüklenirken bir hata oluştu.",
|
||||||
"customTimeInHours": "Özel zaman (saat olarak)",
|
"statisticsConfigUpdated": "İstatistik ayarları başarıyla güncellendi",
|
||||||
|
"statisticsConfigNotUpdated": "İstatistik ayarları güncellenemedi",
|
||||||
|
"customTimeInHours": "Özel zaman (Saat olarak)",
|
||||||
"invalidTime": "Geçersiz zaman",
|
"invalidTime": "Geçersiz zaman",
|
||||||
"removeDomain": "Alan adını kaldır",
|
"removeDomain": "Alan adını kaldır",
|
||||||
"addDomain": "Alan adı ekle",
|
"addDomain": "Alan adı ekle",
|
||||||
|
@ -774,5 +776,8 @@
|
||||||
"showHide": "Göster/gizle",
|
"showHide": "Göster/gizle",
|
||||||
"noElementsReorderMessage": "Burada yeniden sıralamak için göster/gizle sekmesindeki bazı öğeleri etkinleştirin.",
|
"noElementsReorderMessage": "Burada yeniden sıralamak için göster/gizle sekmesindeki bazı öğeleri etkinleştirin.",
|
||||||
"enablePlainDns": "Düz DNS'i etkinleştir",
|
"enablePlainDns": "Düz DNS'i etkinleştir",
|
||||||
"enablePlainDnsDescription": "Düz DNS varsayılan olarak etkindir. Tüm aygıtları şifrelenmiş DNS kullanmaya zorlamak için bunu devre dışı bırakabilirsiniz. Bunu yapmak için en az bir şifrelenmiş DNS protokolünü etkinleştirmeniz gerekir."
|
"enablePlainDnsDescription": "Düz DNS varsayılan olarak etkindir. Tüm aygıtları şifrelenmiş DNS kullanmaya zorlamak için bunu devre dışı bırakabilirsiniz. Bunu yapmak için en az bir şifrelenmiş DNS protokolünü etkinleştirmeniz gerekir.",
|
||||||
|
"date": "Tarih",
|
||||||
|
"loadingChangelog": "Değişiklikler yükleniyor...",
|
||||||
|
"invalidIpOrUrl": "Geçersiz IP adresi veya URL"
|
||||||
}
|
}
|
|
@ -10,6 +10,16 @@ import 'package:adguard_home_manager/models/safe_search.dart';
|
||||||
import 'package:adguard_home_manager/providers/clients_provider.dart';
|
import 'package:adguard_home_manager/providers/clients_provider.dart';
|
||||||
import 'package:adguard_home_manager/models/clients.dart';
|
import 'package:adguard_home_manager/models/clients.dart';
|
||||||
|
|
||||||
|
class ClientInitialData {
|
||||||
|
final String name;
|
||||||
|
final String ip;
|
||||||
|
|
||||||
|
const ClientInitialData({
|
||||||
|
required this.name,
|
||||||
|
required this.ip,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
class ControllerListItem {
|
class ControllerListItem {
|
||||||
final String id;
|
final String id;
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
@ -25,13 +35,15 @@ class ClientScreen extends StatefulWidget {
|
||||||
final void Function(Client) onConfirm;
|
final void Function(Client) onConfirm;
|
||||||
final void Function(Client)? onDelete;
|
final void Function(Client)? onDelete;
|
||||||
final bool fullScreen;
|
final bool fullScreen;
|
||||||
|
final ClientInitialData? initialData;
|
||||||
|
|
||||||
const ClientScreen({
|
const ClientScreen({
|
||||||
super.key,
|
super.key,
|
||||||
this.client,
|
this.client,
|
||||||
required this.onConfirm,
|
required this.onConfirm,
|
||||||
this.onDelete,
|
this.onDelete,
|
||||||
required this.fullScreen
|
required this.fullScreen,
|
||||||
|
this.initialData,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -146,6 +158,13 @@ class _ClientScreenState extends State<ClientScreen> {
|
||||||
_blockedServicesSchedule = widget.client!.blockedServicesSchedule!;
|
_blockedServicesSchedule = widget.client!.blockedServicesSchedule!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (widget.initialData != null) {
|
||||||
|
nameController.text = widget.initialData!.name;
|
||||||
|
identifiersControllers[0] = ControllerListItem(
|
||||||
|
id: uuid.v4(),
|
||||||
|
controller: TextEditingController(text: widget.initialData!.ip)
|
||||||
|
);
|
||||||
|
}
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,71 +235,90 @@ class _ClientScreenState extends State<ClientScreen> {
|
||||||
|
|
||||||
|
|
||||||
if (widget.fullScreen == true) {
|
if (widget.fullScreen == true) {
|
||||||
return Dialog.fullscreen(
|
return Material(
|
||||||
child: Scaffold(
|
child: NestedScrollView(
|
||||||
appBar: AppBar(
|
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||||
leading: IconButton(
|
SliverOverlapAbsorber(
|
||||||
onPressed: () => Navigator.pop(context),
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
icon: const Icon(Icons.close)
|
sliver: SliverAppBar.large(
|
||||||
),
|
pinned: true,
|
||||||
title: Text(
|
floating: true,
|
||||||
widget.client != null
|
centerTitle: false,
|
||||||
? AppLocalizations.of(context)!.client
|
forceElevated: innerBoxIsScrolled,
|
||||||
: AppLocalizations.of(context)!.addClient
|
leading: IconButton(
|
||||||
),
|
onPressed: () => Navigator.pop(context),
|
||||||
actions: actions(),
|
icon: const Icon(Icons.close)
|
||||||
),
|
),
|
||||||
|
title: Text(
|
||||||
|
widget.client != null
|
||||||
|
? AppLocalizations.of(context)!.client
|
||||||
|
: AppLocalizations.of(context)!.addClient
|
||||||
|
),
|
||||||
|
actions: actions(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: ListView(
|
top: false,
|
||||||
controller: _scrollController,
|
bottom: false,
|
||||||
children: [
|
child: Builder(
|
||||||
if (!_nameValid || !_identifiersValid || !_dnsCacheValid) _Errors(
|
builder: (context) => CustomScrollView(
|
||||||
nameValid: _nameValid,
|
slivers: [
|
||||||
identifiersValid: _identifiersValid,
|
SliverOverlapInjector(
|
||||||
dnsCacheValid: _dnsCacheValid
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
),
|
),
|
||||||
ClientForm(
|
SliverList.list(
|
||||||
isFullScreen: true,
|
children: [
|
||||||
client: widget.client,
|
if (!_nameValid || !_identifiersValid || !_dnsCacheValid) _Errors(
|
||||||
nameController: nameController,
|
nameValid: _nameValid,
|
||||||
identifiersControllers: identifiersControllers,
|
identifiersValid: _identifiersValid,
|
||||||
selectedTags: selectedTags,
|
dnsCacheValid: _dnsCacheValid
|
||||||
useGlobalSettingsFiltering: useGlobalSettingsFiltering,
|
),
|
||||||
enableFiltering: enableFiltering,
|
ClientForm(
|
||||||
enableParentalControl: enableParentalControl,
|
isFullScreen: true,
|
||||||
enableSafeBrowsing: enableSafeBrowsing,
|
client: widget.client,
|
||||||
enableSafeSearch: enableSafeSearch,
|
nameController: nameController,
|
||||||
safeSearch: safeSearch,
|
identifiersControllers: identifiersControllers,
|
||||||
blockedServices: blockedServices,
|
selectedTags: selectedTags,
|
||||||
updateBlockedServices: (v) => setState(() => blockedServices = v),
|
useGlobalSettingsFiltering: useGlobalSettingsFiltering,
|
||||||
upstreamServers: upstreamServers,
|
enableFiltering: enableFiltering,
|
||||||
updateUpstreamServers: (v) => setState(() => upstreamServers = v),
|
enableParentalControl: enableParentalControl,
|
||||||
defaultSafeSearch: defaultSafeSearch,
|
enableSafeBrowsing: enableSafeBrowsing,
|
||||||
useGlobalSettingsServices: useGlobalSettingsServices,
|
enableSafeSearch: enableSafeSearch,
|
||||||
updateSelectedTags: (v) => setState(() => selectedTags = v),
|
safeSearch: safeSearch,
|
||||||
updateIdentifiersControllers: (v) => setState(() => identifiersControllers = v),
|
blockedServices: blockedServices,
|
||||||
enableDisableGlobalSettingsFiltering: enableDisableGlobalSettingsFiltering,
|
updateBlockedServices: (v) => setState(() => blockedServices = v),
|
||||||
updateEnableFiltering: (v) => setState(() => enableFiltering = v),
|
upstreamServers: upstreamServers,
|
||||||
updateEnableParentalControl: (v) => setState(() => enableParentalControl = v),
|
updateUpstreamServers: (v) => setState(() => upstreamServers = v),
|
||||||
updateEnableSafeBrowsing: (v) => setState(() => enableSafeBrowsing = v),
|
defaultSafeSearch: defaultSafeSearch,
|
||||||
updateEnableSafeSearch: (v) => setState(() => enableSafeSearch = v),
|
useGlobalSettingsServices: useGlobalSettingsServices,
|
||||||
updateSafeSearch: (v) => setState(() => safeSearch = v),
|
updateSelectedTags: (v) => setState(() => selectedTags = v),
|
||||||
updateUseGlobalSettingsServices: (v) => setState(() => useGlobalSettingsServices = v),
|
updateIdentifiersControllers: (v) => setState(() => identifiersControllers = v),
|
||||||
ignoreClientQueryLog: _ignoreClientQueryLog,
|
enableDisableGlobalSettingsFiltering: enableDisableGlobalSettingsFiltering,
|
||||||
ignoreClientStatistics: _ignoreClientStatistics,
|
updateEnableFiltering: (v) => setState(() => enableFiltering = v),
|
||||||
updateIgnoreClientQueryLog: (v) => setState(() => _ignoreClientQueryLog = v),
|
updateEnableParentalControl: (v) => setState(() => enableParentalControl = v),
|
||||||
updateIgnoreClientStatistics: (v) => setState(() => _ignoreClientStatistics = v),
|
updateEnableSafeBrowsing: (v) => setState(() => enableSafeBrowsing = v),
|
||||||
enableDnsCache: _enableDnsCache,
|
updateEnableSafeSearch: (v) => setState(() => enableSafeSearch = v),
|
||||||
updateEnableDnsCache: (v) => setState(() => _enableDnsCache = v),
|
updateSafeSearch: (v) => setState(() => safeSearch = v),
|
||||||
dnsCacheField: _dnsCacheField,
|
updateUseGlobalSettingsServices: (v) => setState(() => useGlobalSettingsServices = v),
|
||||||
dnsCacheError: _dnsCacheError,
|
ignoreClientQueryLog: _ignoreClientQueryLog,
|
||||||
updateDnsCacheError: (v) => setState(() => _dnsCacheError = v),
|
ignoreClientStatistics: _ignoreClientStatistics,
|
||||||
blockedServicesSchedule: _blockedServicesSchedule,
|
updateIgnoreClientQueryLog: (v) => setState(() => _ignoreClientQueryLog = v),
|
||||||
setBlockedServicesSchedule: (v) => setState(() => _blockedServicesSchedule = v),
|
updateIgnoreClientStatistics: (v) => setState(() => _ignoreClientStatistics = v),
|
||||||
),
|
enableDnsCache: _enableDnsCache,
|
||||||
],
|
updateEnableDnsCache: (v) => setState(() => _enableDnsCache = v),
|
||||||
),
|
dnsCacheField: _dnsCacheField,
|
||||||
),
|
dnsCacheError: _dnsCacheError,
|
||||||
|
updateDnsCacheError: (v) => setState(() => _dnsCacheError = v),
|
||||||
|
blockedServicesSchedule: _blockedServicesSchedule,
|
||||||
|
setBlockedServicesSchedule: (v) => setState(() => _blockedServicesSchedule = v),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ void openClientFormModal({
|
||||||
Client? client,
|
Client? client,
|
||||||
required void Function(Client) onConfirm,
|
required void Function(Client) onConfirm,
|
||||||
void Function(Client)? onDelete,
|
void Function(Client)? onDelete,
|
||||||
|
ClientInitialData? initialData,
|
||||||
}) {
|
}) {
|
||||||
showGeneralDialog(
|
showGeneralDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -105,6 +106,7 @@ void openClientFormModal({
|
||||||
client: client,
|
client: client,
|
||||||
onConfirm: onConfirm,
|
onConfirm: onConfirm,
|
||||||
onDelete: onDelete,
|
onDelete: onDelete,
|
||||||
|
initialData: initialData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,146 +131,175 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
setState(() => previousIp = widget.ip);
|
setState(() => previousIp = widget.ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Material(
|
||||||
appBar: AppBar(
|
child: NestedScrollView(
|
||||||
title: Text(widget.name != null && widget.name != '' ? widget.name! : widget.ip),
|
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||||
centerTitle: true,
|
SliverOverlapAbsorber(
|
||||||
surfaceTintColor: isDesktop(MediaQuery.of(context).size.width)
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
? Colors.transparent
|
sliver: SliverAppBar.large(
|
||||||
: null,
|
pinned: true,
|
||||||
actions: [
|
floating: true,
|
||||||
if (!(Platform.isAndroid || Platform.isIOS)) ...[
|
centerTitle: false,
|
||||||
IconButton(
|
forceElevated: innerBoxIsScrolled,
|
||||||
onPressed: fetchLogs,
|
title: SafeArea(
|
||||||
icon: const Icon(Icons.refresh_rounded),
|
child: Column(
|
||||||
tooltip: AppLocalizations.of(context)!.refresh,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
children: [
|
||||||
const SizedBox(width: 8)
|
Text(
|
||||||
]
|
AppLocalizations.of(context)!.client,
|
||||||
],
|
style: const TextStyle(
|
||||||
),
|
fontSize: 24
|
||||||
body: SafeArea(
|
),
|
||||||
child: Builder(
|
),
|
||||||
builder: (context) {
|
const SizedBox(height: 4),
|
||||||
switch (loadStatus) {
|
Text(
|
||||||
case 0:
|
widget.name != null && widget.name != '' ? widget.name! : widget.ip,
|
||||||
return SizedBox(
|
style: TextStyle(
|
||||||
width: double.maxFinite,
|
fontSize: 14,
|
||||||
child: Column(
|
fontWeight: FontWeight.w500,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
color: Theme.of(context).colorScheme.secondary
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
),
|
||||||
children: [
|
)
|
||||||
const CircularProgressIndicator(),
|
],
|
||||||
const SizedBox(height: 30),
|
),
|
||||||
Text(
|
),
|
||||||
AppLocalizations.of(context)!.loadingLogs,
|
surfaceTintColor: isDesktop(MediaQuery.of(context).size.width)
|
||||||
textAlign: TextAlign.center,
|
? Colors.transparent
|
||||||
style: TextStyle(
|
: null,
|
||||||
fontSize: 22,
|
actions: [
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
if (!(Platform.isAndroid || Platform.isIOS)) ...[
|
||||||
),
|
IconButton(
|
||||||
)
|
onPressed: fetchLogs,
|
||||||
],
|
icon: const Icon(Icons.refresh_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.refresh,
|
||||||
),
|
),
|
||||||
);
|
const SizedBox(width: 8)
|
||||||
|
]
|
||||||
case 1:
|
],
|
||||||
if (logsData!.data.isNotEmpty) {
|
)
|
||||||
return RefreshIndicator(
|
)
|
||||||
onRefresh: fetchLogs,
|
],
|
||||||
child: ListView.builder(
|
body: SafeArea(
|
||||||
controller: scrollController,
|
top: false,
|
||||||
padding: const EdgeInsets.only(top: 0),
|
bottom: false,
|
||||||
itemCount: isLoadingMore == true
|
child: Builder(
|
||||||
? logsData!.data.length+1
|
builder: (context) => RefreshIndicator(
|
||||||
: logsData!.data.length,
|
onRefresh: fetchLogs,
|
||||||
itemBuilder: (context, index) {
|
displacement: 95,
|
||||||
if (isLoadingMore == true && index == logsData!.data.length) {
|
child: CustomScrollView(
|
||||||
return const Padding(
|
slivers: [
|
||||||
padding: EdgeInsets.symmetric(vertical: 20),
|
SliverOverlapInjector(
|
||||||
child: Center(
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
child: CircularProgressIndicator(),
|
),
|
||||||
|
if (loadStatus == 0) SliverFillRemaining(
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const CircularProgressIndicator(),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.loadingLogs,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
);
|
)
|
||||||
}
|
],
|
||||||
else {
|
),
|
||||||
return LogTile(
|
)
|
||||||
log: logsData!.data[index],
|
),
|
||||||
index: index,
|
if (loadStatus == 1 && logsData!.data.isNotEmpty) SliverList.builder(
|
||||||
length: logsData!.data.length,
|
itemCount: isLoadingMore == true
|
||||||
useAlwaysNormalTile: true,
|
? logsData!.data.length+1
|
||||||
onLogTap: (log) => {
|
: logsData!.data.length,
|
||||||
if (width > 700) {
|
itemBuilder: (context, index) {
|
||||||
showDialog(
|
if (isLoadingMore == true && index == logsData!.data.length) {
|
||||||
context: context,
|
return const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 20),
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return LogTile(
|
||||||
|
log: logsData!.data[index],
|
||||||
|
index: index,
|
||||||
|
length: logsData!.data.length,
|
||||||
|
useAlwaysNormalTile: true,
|
||||||
|
onLogTap: (log) => {
|
||||||
|
if (width > 700) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => LogDetailsScreen(
|
||||||
|
log: log,
|
||||||
|
dialog: true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
builder: (context) => LogDetailsScreen(
|
builder: (context) => LogDetailsScreen(
|
||||||
log: log,
|
log: log,
|
||||||
dialog: true
|
dialog: false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
else {
|
}
|
||||||
Navigator.of(context).push(
|
},
|
||||||
MaterialPageRoute(
|
twoColumns: widget.splitView,
|
||||||
builder: (context) => LogDetailsScreen(
|
);
|
||||||
log: log,
|
|
||||||
dialog: false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
twoColumns: widget.splitView,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
),
|
}
|
||||||
);
|
),
|
||||||
}
|
if (loadStatus == 1 && logsData!.data.isEmpty) SliverFillRemaining(
|
||||||
else {
|
child: Center(
|
||||||
return Center(
|
child: Text(
|
||||||
child: Text(
|
AppLocalizations.of(context)!.noLogsDisplay,
|
||||||
AppLocalizations.of(context)!.noLogsDisplay,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
return SizedBox(
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Icon(
|
|
||||||
Icons.error,
|
|
||||||
color: Colors.red,
|
|
||||||
size: 50,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.logsNotLoaded,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
);
|
if (loadStatus == 2) SliverFillRemaining(
|
||||||
|
child: SizedBox(
|
||||||
default:
|
width: double.maxFinite,
|
||||||
return const SizedBox();
|
child: Column(
|
||||||
}
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
},
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
),
|
children: [
|
||||||
)
|
const Icon(
|
||||||
|
Icons.error,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 50,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.logsNotLoaded,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@ import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
|
|
||||||
class ClientsFab extends StatelessWidget {
|
class ClientsFab extends StatelessWidget {
|
||||||
const ClientsFab({Key? key}) : super(key: key);
|
const ClientsFab({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -85,38 +85,130 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
|
||||||
|
|
||||||
if (widget.fullScreen == true) {
|
if (widget.fullScreen == true) {
|
||||||
return Dialog.fullscreen(
|
return Dialog.fullscreen(
|
||||||
child: Scaffold(
|
child: Material(
|
||||||
appBar: AppBar(
|
child: NestedScrollView(
|
||||||
leading: CloseButton(onPressed: () => Navigator.pop(context)),
|
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||||
title: Text(AppLocalizations.of(context)!.blockedServices),
|
SliverOverlapAbsorber(
|
||||||
actions: [
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
IconButton(
|
sliver: SliverAppBar.large(
|
||||||
onPressed: updateBlockedServices,
|
pinned: true,
|
||||||
icon: const Icon(
|
floating: true,
|
||||||
Icons.save_rounded
|
centerTitle: false,
|
||||||
),
|
forceElevated: innerBoxIsScrolled,
|
||||||
tooltip: AppLocalizations.of(context)!.save,
|
leading: CloseButton(onPressed: () => Navigator.pop(context)),
|
||||||
),
|
title: Text(AppLocalizations.of(context)!.blockedServices),
|
||||||
const SizedBox(width: 10)
|
actions: [
|
||||||
],
|
IconButton(
|
||||||
),
|
onPressed: updateBlockedServices,
|
||||||
body: SafeArea(
|
icon: const Icon(
|
||||||
child: RefreshIndicator(
|
Icons.save_rounded
|
||||||
onRefresh: () async {
|
),
|
||||||
final result = await filteringProvider.loadBlockedServices();
|
tooltip: AppLocalizations.of(context)!.save,
|
||||||
if (result == false) {
|
),
|
||||||
showSnacbkar(
|
const SizedBox(width: 10)
|
||||||
appConfigProvider: appConfigProvider,
|
],
|
||||||
label: AppLocalizations.of(context)!.blockedServicesListNotLoaded,
|
)
|
||||||
color: Colors.red
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: _Content(
|
|
||||||
values: values,
|
|
||||||
updateValues: updateValues,
|
|
||||||
)
|
)
|
||||||
),
|
],
|
||||||
|
body: SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: true,
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) => CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverOverlapInjector(
|
||||||
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
|
),
|
||||||
|
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loading) Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const CircularProgressIndicator(),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.loadingBlockedServicesList,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loaded) SliverList.builder(
|
||||||
|
itemCount: filteringProvider.blockedServices!.services.length,
|
||||||
|
itemBuilder: (context, index) => Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () => updateValues(
|
||||||
|
values.contains(filteringProvider.blockedServices!.services[index].id),
|
||||||
|
filteringProvider.blockedServices!.services[index]
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 6,
|
||||||
|
bottom: 6,
|
||||||
|
right: 12,
|
||||||
|
left: 24
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
filteringProvider.blockedServices!.services[index].name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Checkbox(
|
||||||
|
value: values.contains(filteringProvider.blockedServices!.services[index].id),
|
||||||
|
onChanged: (value) => updateValues(
|
||||||
|
value!,
|
||||||
|
filteringProvider.blockedServices!.services[index]
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.error) Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
Icons.error,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 50,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.blockedServicesListNotLoaded,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -162,9 +254,105 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _Content(
|
child: Builder(
|
||||||
values: values,
|
builder: (ctx) {
|
||||||
updateValues: updateValues,
|
switch (filteringProvider.blockedServicesLoadStatus) {
|
||||||
|
case LoadStatus.loading:
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const CircularProgressIndicator(),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.loadingBlockedServicesList,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
case LoadStatus.loaded:
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: filteringProvider.blockedServices!.services.length,
|
||||||
|
itemBuilder: (context, index) => Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () => updateValues(
|
||||||
|
values.contains(filteringProvider.blockedServices!.services[index].id),
|
||||||
|
filteringProvider.blockedServices!.services[index]
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 6,
|
||||||
|
bottom: 6,
|
||||||
|
right: 12,
|
||||||
|
left: 24
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
filteringProvider.blockedServices!.services[index].name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Checkbox(
|
||||||
|
value: values.contains(filteringProvider.blockedServices!.services[index].id),
|
||||||
|
onChanged: (value) => updateValues(
|
||||||
|
value!,
|
||||||
|
filteringProvider.blockedServices!.services[index]
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
case LoadStatus.error:
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
Icons.error,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 50,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.blockedServicesListNotLoaded,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -175,117 +363,6 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Content extends StatelessWidget {
|
|
||||||
final List<String> values;
|
|
||||||
final void Function(bool value, BlockedService item) updateValues;
|
|
||||||
|
|
||||||
const _Content({
|
|
||||||
required this.values,
|
|
||||||
required this.updateValues,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final filteringProvider = Provider.of<FilteringProvider>(context);
|
|
||||||
|
|
||||||
switch (filteringProvider.blockedServicesLoadStatus) {
|
|
||||||
case LoadStatus.loading:
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const CircularProgressIndicator(),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.loadingBlockedServicesList,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
case LoadStatus.loaded:
|
|
||||||
return ListView.builder(
|
|
||||||
itemCount: filteringProvider.blockedServices!.services.length,
|
|
||||||
itemBuilder: (context, index) => Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () => updateValues(
|
|
||||||
values.contains(filteringProvider.blockedServices!.services[index].id),
|
|
||||||
filteringProvider.blockedServices!.services[index]
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
top: 6,
|
|
||||||
bottom: 6,
|
|
||||||
right: 12,
|
|
||||||
left: 24
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
filteringProvider.blockedServices!.services[index].name,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: Theme.of(context).colorScheme.onSurface
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Checkbox(
|
|
||||||
value: values.contains(filteringProvider.blockedServices!.services[index].id),
|
|
||||||
onChanged: (value) => updateValues(
|
|
||||||
value!,
|
|
||||||
filteringProvider.blockedServices!.services[index]
|
|
||||||
),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(5)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
case LoadStatus.error:
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Icon(
|
|
||||||
Icons.error,
|
|
||||||
color: Colors.red,
|
|
||||||
size: 50,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.blockedServicesListNotLoaded,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void openBlockedServicesModal({
|
void openBlockedServicesModal({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
|
|
|
@ -55,44 +55,66 @@ class _AddCustomRuleState extends State<AddCustomRule> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (widget.fullScreen == true) {
|
if (widget.fullScreen == true) {
|
||||||
return Dialog.fullscreen(
|
return Dialog.fullscreen(
|
||||||
child: Scaffold(
|
child: Material(
|
||||||
appBar: AppBar(
|
child: NestedScrollView(
|
||||||
leading: CloseButton(onPressed: () => Navigator.pop(context)),
|
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||||
title: Text(AppLocalizations.of(context)!.addCustomRule),
|
SliverOverlapAbsorber(
|
||||||
actions: [
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
IconButton(
|
sliver: SliverAppBar.large(
|
||||||
onPressed: _checkValidValues() == true
|
pinned: true,
|
||||||
? () {
|
floating: true,
|
||||||
Navigator.pop(context);
|
centerTitle: false,
|
||||||
widget.onConfirm(
|
forceElevated: innerBoxIsScrolled,
|
||||||
_buildRule(
|
leading: CloseButton(onPressed: () => Navigator.pop(context)),
|
||||||
domainController: _domainController,
|
title: Text(AppLocalizations.of(context)!.addCustomRule),
|
||||||
important: _addImportant,
|
actions: [
|
||||||
preset: _preset
|
IconButton(
|
||||||
)
|
onPressed: _checkValidValues() == true
|
||||||
);
|
? () {
|
||||||
}
|
Navigator.pop(context);
|
||||||
: null,
|
widget.onConfirm(
|
||||||
icon: const Icon(Icons.check)
|
_buildRule(
|
||||||
),
|
domainController: _domainController,
|
||||||
const SizedBox(width: 10)
|
important: _addImportant,
|
||||||
],
|
preset: _preset
|
||||||
),
|
)
|
||||||
body: SafeArea(
|
);
|
||||||
child: ListView(
|
}
|
||||||
children: [
|
: null,
|
||||||
_CustomRuleEditor(
|
icon: const Icon(Icons.check)
|
||||||
domainController: _domainController,
|
),
|
||||||
domainError: _domainError,
|
const SizedBox(width: 10)
|
||||||
important: _addImportant,
|
],
|
||||||
preset: _preset,
|
)
|
||||||
setImportant: (v) => setState(() => _addImportant = v),
|
|
||||||
setPreset: (v) => setState(() => _preset = v),
|
|
||||||
validateDomain: validateDomain
|
|
||||||
)
|
)
|
||||||
]
|
],
|
||||||
|
body: SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: true,
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) => CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverOverlapInjector(
|
||||||
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
|
),
|
||||||
|
SliverList.list(
|
||||||
|
children: [
|
||||||
|
_CustomRuleEditor(
|
||||||
|
domainController: _domainController,
|
||||||
|
domainError: _domainError,
|
||||||
|
important: _addImportant,
|
||||||
|
preset: _preset,
|
||||||
|
setImportant: (v) => setState(() => _addImportant = v),
|
||||||
|
setPreset: (v) => setState(() => _preset = v),
|
||||||
|
validateDomain: validateDomain
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
)
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,29 +37,51 @@ class _EditCustomRulesState extends State<EditCustomRules> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (widget.fullScreen == true) {
|
if (widget.fullScreen == true) {
|
||||||
return Dialog.fullscreen(
|
return Dialog.fullscreen(
|
||||||
child: Scaffold(
|
child: Material(
|
||||||
appBar: AppBar(
|
child: NestedScrollView(
|
||||||
leading: CloseButton(onPressed: () => Navigator.pop(context)),
|
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||||
title: Text(AppLocalizations.of(context)!.editCustomRules),
|
SliverOverlapAbsorber(
|
||||||
actions: [
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
IconButton(
|
sliver: SliverAppBar.large(
|
||||||
onPressed: () {
|
pinned: true,
|
||||||
Navigator.pop(context);
|
floating: true,
|
||||||
widget.onConfirm(_fieldController.text.split("\n"));
|
centerTitle: false,
|
||||||
},
|
forceElevated: innerBoxIsScrolled,
|
||||||
icon: const Icon(Icons.save_rounded),
|
leading: CloseButton(onPressed: () => Navigator.pop(context)),
|
||||||
tooltip: AppLocalizations.of(context)!.save,
|
title: Text(AppLocalizations.of(context)!.editCustomRules),
|
||||||
),
|
actions: [
|
||||||
const SizedBox(width: 10)
|
IconButton(
|
||||||
],
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
widget.onConfirm(_fieldController.text.split("\n"));
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.save_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.save,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
body: SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: true,
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) => CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverOverlapInjector(
|
||||||
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
|
),
|
||||||
|
SliverList.list(
|
||||||
|
children: [
|
||||||
|
_CustomRulesRawEditor(fieldController: _fieldController)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
_CustomRulesRawEditor(fieldController: _fieldController)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,17 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/screens/clients/client/client_screen_functions.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/clients/client/client_screen.dart';
|
||||||
import 'package:adguard_home_manager/widgets/options_menu.dart';
|
import 'package:adguard_home_manager/widgets/options_menu.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/providers/status_provider.dart';
|
import 'package:adguard_home_manager/providers/status_provider.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/filtering_provider.dart';
|
||||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||||
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
||||||
|
import 'package:adguard_home_manager/models/clients.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/clients_provider.dart';
|
||||||
import 'package:adguard_home_manager/models/menu_option.dart';
|
import 'package:adguard_home_manager/models/menu_option.dart';
|
||||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
import 'package:adguard_home_manager/functions/get_filtered_status.dart';
|
import 'package:adguard_home_manager/functions/get_filtered_status.dart';
|
||||||
|
@ -40,6 +45,8 @@ class LogTile extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
final statusProvider = Provider.of<StatusProvider>(context);
|
final statusProvider = Provider.of<StatusProvider>(context);
|
||||||
|
final clientsProvider = Provider.of<ClientsProvider>(context);
|
||||||
|
final filteringProvider = Provider.of<FilteringProvider>(context);
|
||||||
|
|
||||||
Widget logStatusWidget({
|
Widget logStatusWidget({
|
||||||
required IconData icon,
|
required IconData icon,
|
||||||
|
@ -118,6 +125,114 @@ class LogTile extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void confirmAddClient(Client client) async {
|
||||||
|
ProcessModal processModal = ProcessModal();
|
||||||
|
processModal.open(AppLocalizations.of(context)!.addingClient);
|
||||||
|
|
||||||
|
final result = await clientsProvider.addClient(client);
|
||||||
|
|
||||||
|
processModal.close();
|
||||||
|
|
||||||
|
if (result == true) {
|
||||||
|
showSnacbkar(
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.clientAddedSuccessfully,
|
||||||
|
color: Colors.green
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showSnacbkar(
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.clientNotAdded,
|
||||||
|
color: Colors.red
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void blockUnblockRuleClient() async {
|
||||||
|
ProcessModal processModal = ProcessModal();
|
||||||
|
processModal.open(AppLocalizations.of(context)!.addingRule);
|
||||||
|
|
||||||
|
final rule = isDomainBlocked(log.reason) == true
|
||||||
|
? "@@||${log.question.name}^\$client='${log.client}'"
|
||||||
|
: "||${log.question.name}^\$client='${log.client}'";
|
||||||
|
|
||||||
|
final result = await filteringProvider.addCustomRule(rule);
|
||||||
|
|
||||||
|
processModal.close();
|
||||||
|
|
||||||
|
if (!context.mounted) return;
|
||||||
|
if (result == true) {
|
||||||
|
showSnacbkar(
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: isDomainBlocked(log.reason) == true
|
||||||
|
? AppLocalizations.of(context)!.domainUnblockedThisClient(log.question.name!)
|
||||||
|
: AppLocalizations.of(context)!.domainBlockedThisClient(log.question.name!),
|
||||||
|
color: Colors.green
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showSnacbkar(
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.ruleNotAdded,
|
||||||
|
color: Colors.red
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void allowDisallowClient() async {
|
||||||
|
ProcessModal processModal = ProcessModal();
|
||||||
|
processModal.open(
|
||||||
|
log.clientInfo!.disallowed == true
|
||||||
|
? AppLocalizations.of(context)!.allowingClient
|
||||||
|
: AppLocalizations.of(context)!.disallowingClient
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await clientsProvider.addClientList(
|
||||||
|
log.client,
|
||||||
|
log.clientInfo!.disallowed == true
|
||||||
|
? AccessSettingsList.allowed
|
||||||
|
: AccessSettingsList.disallowed
|
||||||
|
);
|
||||||
|
|
||||||
|
processModal.close();
|
||||||
|
|
||||||
|
if (!context.mounted) return;
|
||||||
|
if (result.successful == true) {
|
||||||
|
showSnacbkar(
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.clientAddedSuccessfully,
|
||||||
|
color: Colors.green
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (result.successful == false && result.content == 'client_another_list') {
|
||||||
|
showSnacbkar(
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.clientAnotherList,
|
||||||
|
color: Colors.red
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showSnacbkar(
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.changesNotSaved,
|
||||||
|
color: Colors.red
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void openAddClient() {
|
||||||
|
Future.delayed(
|
||||||
|
const Duration(milliseconds: 0),
|
||||||
|
() => openClientFormModal(
|
||||||
|
context: context,
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
onConfirm: confirmAddClient,
|
||||||
|
initialData: ClientInitialData(name: "Client ${log.client}", ip: log.client)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final domainBlocked = isDomainBlocked(log.reason);
|
final domainBlocked = isDomainBlocked(log.reason);
|
||||||
|
|
||||||
if (twoColumns && !(useAlwaysNormalTile == true)) {
|
if (twoColumns && !(useAlwaysNormalTile == true)) {
|
||||||
|
@ -141,6 +256,29 @@ class LogTile extends StatelessWidget {
|
||||||
newStatus: domainBlocked == true ? 'unblock' : 'block'
|
newStatus: domainBlocked == true ? 'unblock' : 'block'
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
if (filteringProvider.filtering != null) MenuOption(
|
||||||
|
title: domainBlocked == true
|
||||||
|
? AppLocalizations.of(context)!.unblockThisClientOnly
|
||||||
|
: AppLocalizations.of(context)!.blockThisClientOnly,
|
||||||
|
icon: domainBlocked == true
|
||||||
|
? Icons.check_rounded
|
||||||
|
: Icons.block_rounded,
|
||||||
|
action: blockUnblockRuleClient
|
||||||
|
),
|
||||||
|
if (log.clientInfo?.name == "") MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.addPersistentClient,
|
||||||
|
icon: Icons.add_rounded,
|
||||||
|
action: openAddClient
|
||||||
|
),
|
||||||
|
MenuOption(
|
||||||
|
title: log.clientInfo!.disallowed == true
|
||||||
|
? AppLocalizations.of(context)!.allowThisClient
|
||||||
|
: AppLocalizations.of(context)!.disallowThisClient,
|
||||||
|
icon: log.clientInfo!.disallowed == true
|
||||||
|
? Icons.check_rounded
|
||||||
|
: Icons.block_rounded,
|
||||||
|
action: allowDisallowClient
|
||||||
|
),
|
||||||
if (log.question.name != null) MenuOption(
|
if (log.question.name != null) MenuOption(
|
||||||
title: AppLocalizations.of(context)!.copyClipboard,
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
icon: Icons.copy_rounded,
|
icon: Icons.copy_rounded,
|
||||||
|
@ -319,6 +457,29 @@ class LogTile extends StatelessWidget {
|
||||||
newStatus: domainBlocked == true ? 'unblock' : 'block'
|
newStatus: domainBlocked == true ? 'unblock' : 'block'
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
if (filteringProvider.filtering != null) MenuOption(
|
||||||
|
title: domainBlocked == true
|
||||||
|
? AppLocalizations.of(context)!.unblockThisClientOnly
|
||||||
|
: AppLocalizations.of(context)!.blockThisClientOnly,
|
||||||
|
icon: domainBlocked == true
|
||||||
|
? Icons.check_rounded
|
||||||
|
: Icons.block_rounded,
|
||||||
|
action: blockUnblockRuleClient
|
||||||
|
),
|
||||||
|
if (log.clientInfo?.name == "") MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.addPersistentClient,
|
||||||
|
icon: Icons.add_rounded,
|
||||||
|
action: openAddClient
|
||||||
|
),
|
||||||
|
MenuOption(
|
||||||
|
title: log.clientInfo!.disallowed == true
|
||||||
|
? AppLocalizations.of(context)!.allowThisClient
|
||||||
|
: AppLocalizations.of(context)!.disallowThisClient,
|
||||||
|
icon: log.clientInfo!.disallowed == true
|
||||||
|
? Icons.check_rounded
|
||||||
|
: Icons.block_rounded,
|
||||||
|
action: allowDisallowClient
|
||||||
|
),
|
||||||
if (log.question.name != null) MenuOption(
|
if (log.question.name != null) MenuOption(
|
||||||
title: AppLocalizations.of(context)!.copyClipboard,
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
icon: Icons.copy_rounded,
|
icon: Icons.copy_rounded,
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
// ignore_for_file: use_build_context_synchronously
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/screens/logs/logs_list.dart';
|
import 'package:adguard_home_manager/screens/logs/logs_list.dart';
|
||||||
import 'package:adguard_home_manager/screens/logs/details/log_details_screen.dart';
|
import 'package:adguard_home_manager/screens/logs/details/log_details_screen.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/models/logs.dart';
|
import 'package:adguard_home_manager/models/logs.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/filtering_provider.dart';
|
||||||
|
|
||||||
class Logs extends StatefulWidget {
|
class Logs extends StatefulWidget {
|
||||||
const Logs({Key? key}) : super(key: key);
|
const Logs({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<Logs> createState() => _LogsState();
|
State<Logs> createState() => _LogsState();
|
||||||
|
@ -17,6 +19,12 @@ class Logs extends StatefulWidget {
|
||||||
class _LogsState extends State<Logs> {
|
class _LogsState extends State<Logs> {
|
||||||
Log? _selectedLog;
|
Log? _selectedLog;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
Provider.of<FilteringProvider>(context, listen: false).fetchFilters();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
|
|
|
@ -8,11 +8,14 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/screens/logs/filters/logs_filters_modal.dart';
|
import 'package:adguard_home_manager/screens/logs/filters/logs_filters_modal.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/config/globals.dart';
|
||||||
import 'package:adguard_home_manager/constants/enums.dart';
|
import 'package:adguard_home_manager/constants/enums.dart';
|
||||||
import 'package:adguard_home_manager/functions/desktop_mode.dart';
|
import 'package:adguard_home_manager/functions/desktop_mode.dart';
|
||||||
import 'package:adguard_home_manager/models/applied_filters.dart';
|
import 'package:adguard_home_manager/models/applied_filters.dart';
|
||||||
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
||||||
|
|
||||||
|
final GlobalKey _searchButtonKey = GlobalKey();
|
||||||
|
|
||||||
class LogsListAppBar extends StatelessWidget {
|
class LogsListAppBar extends StatelessWidget {
|
||||||
final bool innerBoxIsScrolled;
|
final bool innerBoxIsScrolled;
|
||||||
final bool showDivider;
|
final bool showDivider;
|
||||||
|
@ -52,6 +55,25 @@ class LogsListAppBar extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showSearchDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => _Search(
|
||||||
|
searchButtonRenderBox: _searchButtonKey.currentContext?.findRenderObject() as RenderBox?,
|
||||||
|
onSearch: (v) {
|
||||||
|
logsProvider.setAppliedFilters(
|
||||||
|
AppliedFiters(
|
||||||
|
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
|
||||||
|
searchText: v != "" ? v : null,
|
||||||
|
clients: logsProvider.appliedFilters.clients
|
||||||
|
)
|
||||||
|
);
|
||||||
|
logsProvider.filterLogs();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final Map<String, String> translatedString = {
|
final Map<String, String> translatedString = {
|
||||||
"all": AppLocalizations.of(context)!.all,
|
"all": AppLocalizations.of(context)!.all,
|
||||||
"filtered": AppLocalizations.of(context)!.filtered,
|
"filtered": AppLocalizations.of(context)!.filtered,
|
||||||
|
@ -77,22 +99,8 @@ class LogsListAppBar extends StatelessWidget {
|
||||||
tooltip: AppLocalizations.of(context)!.refresh,
|
tooltip: AppLocalizations.of(context)!.refresh,
|
||||||
),
|
),
|
||||||
if (logsProvider.loadStatus == LoadStatus.loaded) IconButton(
|
if (logsProvider.loadStatus == LoadStatus.loaded) IconButton(
|
||||||
onPressed: () => showDialog(
|
key: _searchButtonKey,
|
||||||
context: context,
|
onPressed: showSearchDialog,
|
||||||
builder: (context) => _Search(
|
|
||||||
hasTopBar: MediaQuery.of(context).viewPadding.top > 0,
|
|
||||||
onSearch: (v) {
|
|
||||||
logsProvider.setAppliedFilters(
|
|
||||||
AppliedFiters(
|
|
||||||
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
|
|
||||||
searchText: v != "" ? v : null,
|
|
||||||
clients: logsProvider.appliedFilters.clients
|
|
||||||
)
|
|
||||||
);
|
|
||||||
logsProvider.filterLogs();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
icon: const Icon(Icons.search_rounded),
|
icon: const Icon(Icons.search_rounded),
|
||||||
tooltip: AppLocalizations.of(context)!.search,
|
tooltip: AppLocalizations.of(context)!.search,
|
||||||
),
|
),
|
||||||
|
@ -235,11 +243,11 @@ class LogsListAppBar extends StatelessWidget {
|
||||||
|
|
||||||
class _Search extends StatefulWidget {
|
class _Search extends StatefulWidget {
|
||||||
final void Function(String) onSearch;
|
final void Function(String) onSearch;
|
||||||
final bool hasTopBar;
|
final RenderBox? searchButtonRenderBox;
|
||||||
|
|
||||||
const _Search({
|
const _Search({
|
||||||
required this.onSearch,
|
required this.onSearch,
|
||||||
required this.hasTopBar,
|
required this.searchButtonRenderBox,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -261,67 +269,75 @@ class _SearchState extends State<_Search> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final logsProvider = Provider.of<LogsProvider>(context);
|
final logsProvider = Provider.of<LogsProvider>(context);
|
||||||
|
|
||||||
|
final position = widget.searchButtonRenderBox?.localToGlobal(Offset.zero);
|
||||||
|
final topPadding = MediaQuery.of(globalNavigatorKey.currentContext!).viewPadding.top;
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => Navigator.pop(context),
|
onTap: () => Navigator.pop(context),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Column(
|
child: LayoutBuilder(
|
||||||
mainAxisSize: MainAxisSize.min,
|
builder: (context, constraints) {
|
||||||
children: [
|
final double width = constraints.maxWidth - 32 > 500 ? 500 : constraints.maxWidth - 32;
|
||||||
GestureDetector(
|
return Stack(
|
||||||
onTap: () => {},
|
alignment: Alignment.topCenter,
|
||||||
child: ConstrainedBox(
|
children: [
|
||||||
constraints: const BoxConstraints(maxWidth: 500),
|
Positioned(
|
||||||
child: Container(
|
top: position != null ? position.dy - topPadding : topPadding,
|
||||||
margin: widget.hasTopBar
|
child: SizedBox(
|
||||||
? const EdgeInsets.symmetric(horizontal: 16)
|
width: width,
|
||||||
: const EdgeInsets.all(16),
|
child: GestureDetector(
|
||||||
decoration: BoxDecoration(
|
onTap: () => {},
|
||||||
color: Theme.of(context).colorScheme.surface,
|
child: Container(
|
||||||
borderRadius: BorderRadius.circular(16)
|
decoration: BoxDecoration(
|
||||||
),
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: ClipRRect(
|
borderRadius: BorderRadius.circular(16)
|
||||||
borderRadius: BorderRadius.circular(16),
|
),
|
||||||
child: TextFormField(
|
child: ClipRRect(
|
||||||
controller: _searchController,
|
borderRadius: BorderRadius.circular(16),
|
||||||
onChanged: (v) {
|
child: TextFormField(
|
||||||
if (v == "") {
|
controller: _searchController,
|
||||||
logsProvider.setSearchText(null);
|
onChanged: (v) {
|
||||||
return;
|
if (v == "") {
|
||||||
}
|
|
||||||
logsProvider.setSearchText(v);
|
|
||||||
},
|
|
||||||
onFieldSubmitted: (v) {
|
|
||||||
widget.onSearch(v);
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
autofocus: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: AppLocalizations.of(context)!.search,
|
|
||||||
prefixIcon: const Icon(Icons.search_rounded),
|
|
||||||
border: InputBorder.none,
|
|
||||||
filled: true,
|
|
||||||
fillColor: Colors.grey.withOpacity(0.2),
|
|
||||||
suffixIcon: _searchController.text != ""
|
|
||||||
? IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
_searchController.text = "";
|
|
||||||
logsProvider.setSearchText(null);
|
logsProvider.setSearchText(null);
|
||||||
},
|
return;
|
||||||
icon: const Icon(
|
}
|
||||||
Icons.close_rounded,
|
logsProvider.setSearchText(v);
|
||||||
size: 20,
|
},
|
||||||
),
|
onFieldSubmitted: (v) {
|
||||||
tooltip: AppLocalizations.of(context)!.clearSearch,
|
widget.onSearch(v);
|
||||||
)
|
Navigator.pop(context);
|
||||||
: null
|
},
|
||||||
|
autofocus: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: AppLocalizations.of(context)!.search,
|
||||||
|
prefixIcon: const Icon(Icons.search_rounded),
|
||||||
|
border: InputBorder.none,
|
||||||
|
filled: true,
|
||||||
|
fillColor: Colors.grey.withOpacity(0.2),
|
||||||
|
suffixIcon: _searchController.text != ""
|
||||||
|
? IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
_searchController.text = "";
|
||||||
|
logsProvider.setSearchText(null);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.close_rounded,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
tooltip: AppLocalizations.of(context)!.clearSearch,
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
),
|
],
|
||||||
)
|
);
|
||||||
],
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -165,7 +165,7 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
||||||
processModal.open(AppLocalizations.of(context)!.savingConfig);
|
processModal.open(AppLocalizations.of(context)!.savingConfig);
|
||||||
|
|
||||||
final result = await dnsProvider.saveDnsServerConfig({
|
final result = await dnsProvider.saveDnsServerConfig({
|
||||||
"ratelimit": int.parse(_limitRequestsController.text),
|
"ratelimit": int.tryParse(_limitRequestsController.text),
|
||||||
"edns_cs_enabled": _enableEdns,
|
"edns_cs_enabled": _enableEdns,
|
||||||
"edns_cs_use_custom": _useCustomIpEdns,
|
"edns_cs_use_custom": _useCustomIpEdns,
|
||||||
"edns_cs_custom_ip": _customIpEdnsController.text,
|
"edns_cs_custom_ip": _customIpEdnsController.text,
|
||||||
|
|
|
@ -47,6 +47,7 @@ class _UpdateScreenState extends State<UpdateScreen> {
|
||||||
|
|
||||||
void processChangelog() async {
|
void processChangelog() async {
|
||||||
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
|
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
|
||||||
|
if (serversProvider.updateAvailable.data?.changelog == null) return;
|
||||||
final markdownResult = await compute(md.markdownToHtml, serversProvider.updateAvailable.data!.changelog!);
|
final markdownResult = await compute(md.markdownToHtml, serversProvider.updateAvailable.data!.changelog!);
|
||||||
final htmlParsedResult = await compute(html.parse, markdownResult);
|
final htmlParsedResult = await compute(html.parse, markdownResult);
|
||||||
setState(() => _htmlChangelog = htmlParsedResult.outerHtml);
|
setState(() => _htmlChangelog = htmlParsedResult.outerHtml);
|
||||||
|
@ -84,7 +85,7 @@ class _UpdateScreenState extends State<UpdateScreen> {
|
||||||
|
|
||||||
processModal.close();
|
processModal.close();
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!context.mounted) return;
|
||||||
if (result.successful == true) {
|
if (result.successful == true) {
|
||||||
serversProvider.recheckPeriodServerUpdated();
|
serversProvider.recheckPeriodServerUpdated();
|
||||||
showSnacbkar(
|
showSnacbkar(
|
||||||
|
|
|
@ -76,6 +76,7 @@ class _OptionsModal extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
scrollable: true,
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
|
@ -94,19 +95,17 @@ class _OptionsModal extends StatelessWidget {
|
||||||
),
|
),
|
||||||
content: ConstrainedBox(
|
content: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxWidth: 400
|
maxWidth: 500
|
||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
child: Column(
|
||||||
child: Wrap(
|
children: options(value).map((opt) => CustomListTileDialog(
|
||||||
children: options(value).map((opt) => CustomListTileDialog(
|
title: opt.title,
|
||||||
title: opt.title,
|
icon: opt.icon,
|
||||||
icon: opt.icon,
|
onTap: () {
|
||||||
onTap: () {
|
Navigator.pop(context);
|
||||||
Navigator.pop(context);
|
opt.action();
|
||||||
opt.action();
|
},
|
||||||
},
|
)).toList()
|
||||||
)).toList()
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
|
|
@ -6,13 +6,13 @@ PODS:
|
||||||
- FlutterMacOS (1.0.0)
|
- FlutterMacOS (1.0.0)
|
||||||
- package_info_plus (0.0.1):
|
- package_info_plus (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- Sentry/HybridSDK (8.20.0):
|
- Sentry/HybridSDK (8.21.0):
|
||||||
- SentryPrivate (= 8.20.0)
|
- SentryPrivate (= 8.21.0)
|
||||||
- sentry_flutter (0.0.1):
|
- sentry_flutter (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- Sentry/HybridSDK (= 8.20.0)
|
- Sentry/HybridSDK (= 8.21.0)
|
||||||
- SentryPrivate (8.20.0)
|
- SentryPrivate (8.21.0)
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
@ -84,9 +84,9 @@ SPEC CHECKSUMS:
|
||||||
dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f
|
dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f
|
||||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||||
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
|
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
|
||||||
Sentry: a8d7b373b9f9868442b02a0c425192f693103cbf
|
Sentry: ebc12276bd17613a114ab359074096b6b3725203
|
||||||
sentry_flutter: 03e7660857a8cdb236e71456a7e8447b65c8a788
|
sentry_flutter: dff1df05dc39c83d04f9330b36360fc374574c5e
|
||||||
SentryPrivate: 006b24af16828441f70e2ab6adf241bd0a8ad130
|
SentryPrivate: d651efb234cf385ec9a1cdd3eff94b5e78a0e0fe
|
||||||
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
||||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||||
sqlite3: 73b7fc691fdc43277614250e04d183740cb15078
|
sqlite3: 73b7fc691fdc43277614250e04d183740cb15078
|
||||||
|
|
24
pubspec.lock
24
pubspec.lock
|
@ -157,10 +157,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: dynamic_color
|
name: dynamic_color
|
||||||
sha256: a866f1f8947bfdaf674d7928e769eac7230388a2e7a2542824fad4bb5b87be3b
|
sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.9"
|
version: "1.7.0"
|
||||||
equatable:
|
equatable:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -311,10 +311,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: a64c5323ac83ed2b7940d2b6288d160aa1753ff271ba9d9b2a86770414aa3eab
|
sha256: cb44f7831b23a6bdd0f501718b0d2e8045cbc625a15f668af37ddb80314821db
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.20+1"
|
version: "0.6.21"
|
||||||
flutter_native_splash:
|
flutter_native_splash:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -458,10 +458,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: markdown
|
name: markdown
|
||||||
sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90"
|
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.1"
|
version: "7.2.2"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -618,18 +618,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sentry
|
name: sentry
|
||||||
sha256: d2ee9c850d876d285f22e2e662f400ec2438df9939fe4acd5d780df9841794ce
|
sha256: a524a87d096799b775530176c8c082afe7aa1f10cc31ba078fecdd74e9afc923
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.16.1"
|
version: "7.17.0"
|
||||||
sentry_flutter:
|
sentry_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sentry_flutter
|
name: sentry_flutter
|
||||||
sha256: "5b428c189c825f16fb14e9166529043f06b965d5b59bfc3a1415e39c082398c0"
|
sha256: e0f8367f8f7c74dba9f7521f71700bce6c6ee065cf342f065d4fce411b84fc7b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.16.1"
|
version: "7.17.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -951,10 +951,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.2.0"
|
version: "5.3.0"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 2.16.4+134
|
version: 2.17.0+136
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.18.1 <3.0.0'
|
sdk: '>=2.18.1 <3.0.0'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue