Merge branch 'beta'

This commit is contained in:
Juan Gilsanz Polo 2023-10-04 18:41:40 +02:00
commit b539ad702e
24 changed files with 1861 additions and 620 deletions

View file

@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.8.20'
repositories {
google()
mavenCentral()

View file

@ -0,0 +1,13 @@
import 'dart:convert';
import 'package:adguard_home_manager/constants/enums.dart';
final List<HomeTopItems> homeTopItemsDefaultOrder = [
HomeTopItems.queriedDomains,
HomeTopItems.blockedDomains,
HomeTopItems.recurrentClients
];
final String homeTopItemsDefaultOrderString = jsonEncode(
List<String>.from(homeTopItemsDefaultOrder.map((e) => e.name))
);

View file

@ -1 +1,2 @@
enum LoadStatus { loading, loaded, error }
enum LoadStatus { loading, loaded, error }
enum HomeTopItems { queriedDomains, blockedDomains, recurrentClients }

View file

@ -653,5 +653,12 @@
"queries": "Queries",
"adultSites": "Adult sites",
"quickFilters": "Quick filters",
"searchDomainInternet": "Search domain on the Internet"
"searchDomainInternet": "Search domain on the Internet",
"hideServerAddress": "Hide server address",
"hideServerAddressDescription": "Hides the server address on the home screen",
"topItemsOrder": "Top items order",
"topItemsOrderDescription": "Order the home screen top items lists",
"topItemsReorderInfo": "Hold and swipe an item to reorder it.",
"discardChanges": "Discard changes",
"discardChangesDescription": "Are you sure you want to discard the changes?"
}

View file

@ -653,5 +653,12 @@
"queries": "Peticiones",
"adultSites": "Sitios de adultos",
"quickFilters": "Filtros rápidos",
"searchDomainInternet": "Buscar dominio en internet"
"searchDomainInternet": "Buscar dominio en internet",
"hideServerAddress": "Ocultar dirección del servidor",
"hideServerAddressDescription": "Oculta la dirección del servidor en la pantalla de inicio",
"topItemsOrder": "Orden de los top",
"topItemsOrderDescription": "Ordena las listas de top de elementos en la pantalla de inicio",
"topItemsReorderInfo": "Mantén presionado y desliza un elemento para reordenarlo.",
"discardChanges": "Descartar cambios",
"discardChangesDescription": "¿Estás seguro de que deseas descartar los cambios realizados?"
}

657
lib/l10n/app_pl.arb Normal file
View file

@ -0,0 +1,657 @@
{
"home": "Dom",
"settings": "Ustawienia",
"connect": "Połączyć",
"servers": "Serwery",
"createConnection": "Utwórz połączenie",
"name": "Nazwa",
"ipDomain": "Adres IP lub domena",
"path": "Ścieżka",
"port": "Port",
"username": "Nazwa użytkownika",
"password": "Hasło",
"defaultServer": "Serwer domyślny",
"general": "Ogólne",
"connection": "Połączenie",
"authentication": "Uwierzytelnianie",
"other": "Inne",
"invalidPort": "Nieprawidłowy port",
"invalidPath": "Nieprawidłowa ścieżka",
"invalidIpDomain": "Nieprawidłowy adres IP lub domena",
"ipDomainNotEmpty": "Adres IP lub domena nie mogą być puste",
"nameNotEmpty": "Nazwa nie może być pusta",
"invalidUsernamePassword": "Nieprawidłowa nazwa użytkownika lub hasło",
"tooManyAttempts": "Zbyt wiele prób, spróbuj ponownie później",
"cantReachServer": "Nie można połączyć się z serwerem. Sprawdź dane połączenia.",
"sslError": "Błąd SSL. Przejdź do pozycji Ustawienia > Ustawienia zaawansowane i włącz opcję Zastąp sprawdzanie poprawności SSL.",
"unknownError": "Nieznany błąd",
"connectionNotCreated": "Nie można utworzyć połączenia",
"connecting": "Łączenie...",
"connected": "Połączony",
"selectedDisconnected": "Zaznaczone, ale rozłączone",
"connectionDefaultSuccessfully": "Połączenie ustawione jako domyślne pomyślnie.",
"connectionDefaultFailed": "Nie można ustawić połączenia jako domyślne.",
"noSavedConnections": "Brak zapisanych połączeń",
"cannotConnect": "Nie można połączyć się z serwerem",
"connectionRemoved": "Połączenie zostało pomyślnie usunięte.",
"connectionCannotBeRemoved": "Nie można usunąć połączenia.",
"remove": "Usuń",
"removeWarning": "Czy na pewno chcesz usunąć połączenie z tym serwerem AdGuard Home?",
"cancel": "Anuluj",
"defaultConnection": "Połączenie domyślne",
"setDefault": "Ustaw jako domyślne",
"edit": "Edytuj",
"delete": "Usuń",
"save": "Zapisz",
"serverStatus": "Stan serwera",
"connectionNotUpdated": "Połączenie nie zostało zaktualizowane",
"ruleFilteringWidget": "Widget Reguł filtrowania",
"safeBrowsingWidget": "Widget Bezpieczne przeglądanie",
"parentalFilteringWidget": "Widget Filtrowania rodzicielskiego",
"safeSearchWidget": "Widget Bezpiecznego wyszukiwania",
"ruleFiltering": "Reguły filtrowania",
"safeBrowsing": "Bezpieczne przeglądanie",
"parentalFiltering": "Filtrowanie rodzicielskie",
"safeSearch": "Bezpieczne wyszukiwanie",
"serverStatusNotRefreshed": "Nie można odświeżyć stanu serwera",
"loadingStatus": "Stan ładowania...",
"errorLoadServerStatus": "Nie można załadować stanu serwera",
"topQueriedDomains": "Najczęściej wyszukiwane domeny",
"viewMore": "Zobacz więcej",
"topClients": "Najlepsi klienci",
"topBlockedDomains": "Najczęściej blokowane domeny",
"appSettings": "Ustawienia aplikacji",
"theme": "Motyw",
"light": "Jasny",
"dark": "Ciemny",
"systemDefined": "Zdefiniowany przez system",
"close": "Zamknij",
"connectedTo": "Połączony z:",
"selectedServer": "Wybrany serwer:",
"noServerSelected": "Nie wybrano serwera",
"manageServer": "Zarządzanie serwerem",
"allProtections": "Wszystkie zabezpieczenia",
"userNotEmpty": "Nazwa użytkownika nie może być pusta",
"passwordNotEmpty": "Hasło nie może być puste",
"examplePath": "Przykład: /adguard",
"helperPath": "Jeśli używasz zwrotnego serwera proxy",
"aboutApp": "O aplikacji",
"appVersion": "Wersja aplikacji",
"createdBy": "Stworzone przez",
"clients": "Klienci",
"allowed": "Dozwolone",
"blocked": "Zablokowane",
"noClientsList": "Na tej liście nie ma klientów",
"activeClients": "Aktywny",
"removeClient": "Usuń klienta",
"removeClientMessage": "Czy na pewno chcesz usunąć tego klienta z listy?",
"confirm": "Potwierdź",
"removingClient": "Usuwanie klienta...",
"clientNotRemoved": "Nie można usunąć klienta z listy",
"addClient": "Dodaj klienta",
"list": "Lista",
"ipAddress": "Adres IP",
"ipNotValid": "Adres IP jest nieprawidłowy",
"clientAddedSuccessfully": "Klient został pomyślnie dodany do listy.",
"addingClient": "Dodawanie klienta...",
"clientNotAdded": "Nie można dodać klienta do listy.",
"clientAnotherList": "Ten klient jest już na innej liście.",
"noSavedLogs": "Brak zapisanych danych w dzienniku logów",
"logs": "Logi",
"copyLogsClipboard": "Kopiowanie dzienników logów do schowka",
"logsCopiedClipboard": "Dzienniki logów skopiowane do schowka",
"advancedSettings": "Ustawienia zaawansowane",
"dontCheckCertificate": "Nie sprawdzaj certyfikatu SSL",
"dontCheckCertificateDescription": "Zastępuje sprawdzanie poprawności certyfikatu SSL serwera",
"advancedSetupDescription": "Opcje zaawansowane",
"settingsUpdatedSuccessfully": "Ustawienia zostały pomyślnie zaktualizowane.",
"cannotUpdateSettings": "Nie można zaktualizować ustawień.",
"restartAppTakeEffect": "Uruchom ponownie aplikację",
"loadingLogs": "Ładowanie logów dzienników...",
"logsNotLoaded": "Nie można załadować listy dzienników",
"processed": "Przetworzone\nBrak listy",
"processedRow": "Przetworzone (brak listy)",
"blockedBlacklist": "Zablokowane\nCzarna lista",
"blockedBlacklistRow": "Zablokowane (czarna lista)",
"blockedSafeBrowsing": "Zablokowane\nBezpieczne przeglądanie",
"blockedSafeBrowsingRow": "Zablokowane (bezpieczne przeglądanie)",
"blockedParental": "Zablokowane\nFiltrowanie rodzicielskie",
"blockedParentalRow": "Zablokowane (filtrowanie rodzicielskie)",
"blockedInvalid": "Zablokowany\nNieprawidłowy",
"blockedInvalidRow": "Zablokowane (nieprawidłowe)",
"blockedSafeSearch": "Zablokowane\nBezpieczne wyszukiwanie",
"blockedSafeSearchRow": "Zablokowane (bezpieczne wyszukiwanie)",
"blockedService": "Zablokowana\nZablokowana usługa",
"blockedServiceRow": "Zablokowana (zablokowana usługa)",
"processedWhitelist": "Przetworzone\nBiała lista",
"processedWhitelistRow": "Przetworzone (biała lista)",
"processedError": "Przetworzone\nBłąd",
"processedErrorRow": "Przetworzone (błąd)",
"rewrite": "Nadpisać",
"status": "Status",
"result": "Wynik",
"time": "Czas",
"blocklist": "Lista zablokowanych",
"request": "Żądanie",
"domain": "Domena",
"type": "Type",
"clas": "Klasa",
"response": "Odpowiedź",
"dnsServer": "DNS server",
"elapsedTime": "Czas, który upłynął",
"responseCode": "Kod odpowiedzi",
"client": "Klient",
"deviceIp": "Adres IP urządzenia",
"deviceName": "Nazwa urządzenia",
"logDetails": "Szczegóły dziennika logów",
"blockingRule": "Reguła blokowania",
"blockDomain": "Blokowanie domeny",
"couldntGetFilteringStatus": "Nie można uzyskać stanu filtrowanias",
"unblockDomain": "Odblokuj domenę",
"userFilteringRulesNotUpdated": "Nie można zaktualizować reguł filtrowania użytkowników.",
"userFilteringRulesUpdated": "Reguły filtrowania użytkowników zostały pomyślnie zaktualizowane",
"savingUserFilters": "Zapisywanie filtrów użytkownika...",
"filters": "Filtry",
"logsOlderThan": "Dzienniki logów starsze niż",
"responseStatus": "Stan odpowiedzi",
"selectTime": "Wybierz czas",
"notSelected": "Nie wybrano",
"resetFilters": "Resetowanie filtrów",
"noLogsDisplay": "Brak dzienników logów do wyświetlenia",
"noLogsThatOld": "Możliwe, że dla wybranego czasu nie zapisano żadnych dzienników logów. Spróbuj wybrać nowszą godzinę.",
"apply": "Zastosować",
"selectAll": "Zaznacz wszystko",
"unselectAll": "Odznacz wszystko",
"all": "Wszystko",
"filtered": "Przefiltrowano",
"checkAppLogs": "Sprawdź dzienniki logów aplikacji",
"refresh": "Odśwież",
"search": "Szukaj",
"dnsQueries": "Zapytania DNS",
"average": "Średnia",
"blockedFilters": "Zablokowane przez filtry",
"malwarePhisingBlocked": "Zablokowane złośliwe oprogramowanie/phishing",
"blockedAdultWebsites": "Zablokowane witryny dla dorosłych",
"generalSettings": "Ustawienia główne",
"generalSettingsDescription": "Różne ustawienia",
"hideZeroValues": "Ukryj wartości zerowe",
"hideZeroValuesDescription": "Na ekranie głównym ukryj bloki o zerowej wartości",
"webAdminPanel": "Panel administracyjny WWW",
"visitGooglePlay": "Odwiedź stronę Google Play",
"gitHub": "Kod aplikacji dostępny na GitHub",
"blockClient": "Zablokuj klienta",
"selectTags": "Wybierz tagi",
"noTagsSelected": "Brak zaznaczonych tagów",
"tags": "Tagi",
"identifiers": "Identyfikatory",
"identifier": "Identyfikator",
"identifierHelper": "Adres IP , CIDR, Adres MAC, or ClientID",
"noIdentifiers": "Nie dodano identyfikatorów",
"useGlobalSettings": "Użyj ustawień globalnych",
"enableFiltering": "Włącz filtrowanie",
"enableSafeBrowsing": "Włącz bezpieczne przeglądanie",
"enableParentalControl": "Włącz kontrolę rodzicielską",
"enableSafeSearch": "Włącz bezpieczne wyszukiwanie",
"blockedServices": "Zablokowane usługi",
"selectBlockedServices": "Wybierz usługi do zablokowaniak",
"noBlockedServicesSelected": "Brak zablokowanych usług",
"services": "Usługi",
"servicesBlocked": "Usługi zablokowane",
"tagsSelected": "wybrane tagi",
"upstreamServers": "Serwery nadrzędne",
"serverAddress": " Adres servera",
"noUpstreamServers": "Brak serwerów nadrzędnych.",
"willBeUsedGeneralServers": "Wykorzystane zostaną ogólne serwery nadrzędne.",
"added": "Dodane",
"clientUpdatedSuccessfully": "Klient został pomyślnie zaktualizowany",
"clientNotUpdated": "Nie można zaktualizować klienta",
"clientDeletedSuccessfully": "Klient został pomyślnie usunięty",
"clientNotDeleted": "Nie można usunąć klienta",
"options": "Opcje",
"loadingFilters": "Ładowanie filtrów...",
"filtersNotLoaded": "Nie można załadować filtrów.",
"whitelists": "Biała lista",
"blacklists": "Czarna lista",
"rules": "Zasady",
"customRules": "Reguły niestandardowe",
"enabledRules": "Włączone reguły",
"enabled": "Włączone",
"disabled": "Wyłączone",
"rule": "Reguła",
"addCustomRule": "Dodaj niestandardową regułę",
"removeCustomRule": "Usuń regułę niestandardową",
"removeCustomRuleMessage": "Czy na pewno chcesz usunąć tę regułę niestandardową?",
"updatingRules": "Aktualizowanie reguł niestandardowych...",
"ruleRemovedSuccessfully": "Reguła została pomyślnie usunięta",
"ruleNotRemoved": "Nie można usunąć reguły",
"ruleAddedSuccessfully": "Reguła dodana pomyślnie",
"ruleNotAdded": "Nie można dodać reguły",
"noCustomFilters": "Brak filtrów niestandardowych",
"noBlockedClients": "Brak zablokowanych klientów",
"noBlackLists": "Brak czarnych list",
"noWhiteLists": "Brak białych list",
"addWhitelist": "Dodaj białą listę",
"addBlacklist": "Dodaj czarną listę",
"urlNotValid": "Adres URL jest nieprawidłowy",
"urlAbsolutePath": "Adres URL lub ścieżka bezwzględna",
"addingList": "Dodawanie listy...",
"listAdded": "Lista została dodana pomyślnie. Dodane elementy:",
"listAlreadyAdded": "Lista została już dodana",
"listUrlInvalid": "Adres URL listy jest nieprawidłowy",
"listNotAdded": "Nie można dodać listy",
"listDetails": "Szczegóły listy",
"listType": "Typ listy",
"whitelist": "Biała lista",
"blacklist": "Czarna list",
"latestUpdate": "Najnowsza aktualizacja",
"disable": "Wyłączyć",
"enable": "Włączać",
"currentStatus": "Aktualny stan",
"listDataUpdated": "Dane listy zostały pomyślnie zaktualizowane",
"listDataNotUpdated": "Nie można zaktualizować danych listy",
"updatingListData": "Aktualizowanie danych listy...",
"editWhitelist": "Edytuj białą listę",
"editBlacklist": "Edytuj czarną listę",
"deletingList": "Usuwanie listy...",
"listDeleted": "Lista usunięta pomyślnie",
"listNotDeleted": "Nie można usunąć listy",
"deleteList": "Usuń listę",
"deleteListMessage": "Czy na pewno chcesz usunąć tę listę? Tej akcji nie można cofnąć.",
"serverSettings": "Ustawienia serwera",
"serverInformation": "Informacje o serwerze",
"serverInformationDescription": "Informacje i status serwera",
"loadingServerInfo": "Ładowanie informacji o serwerze...",
"serverInfoNotLoaded": "Nie można załadować informacji o serwerze.",
"dnsAddresses": "Adresy DNS",
"seeDnsAddresses": "Zobacz adresy DNS",
"dnsPort": "Port DNS",
"httpPort": "Port HTTP",
"protectionEnabled": "Ochrona włączona",
"dhcpAvailable": "Dostępne DHCP",
"serverRunning": "Serwer działa",
"serverVersion": "Wersia Serwera",
"serverLanguage": "Język serwera",
"yes": "Tak",
"no": "Nie",
"allowedClients": "Dozwoleni klienci",
"disallowedClients": "Niedozwoloni klienci",
"disallowedDomains": "Niedozwolone domeny",
"accessSettings": "Ustawienia dostępu",
"accessSettingsDescription": "Konfigurowanie reguł dostępu dla serwera",
"loadingClients": "Ładowanie klientów...",
"clientsNotLoaded": "Nie można załadować klientów.",
"noAllowedClients": "Brak dozwolonych klientów.",
"allowedClientsDescription": "Jeśli ta lista zawiera wpisy, AdGuard Home będzie akceptować żądania tylko od tych klientów.",
"blockedClientsDescription": "Jeśli ta lista zawiera wpisy, AdGuard Home odrzuci żądania od tych klientów. To pole jest ignorowane, jeśli w obszarze Dozwolone klienty znajdują się wpisy",
"disallowedDomainsDescription": "AdGuard Home usuwa zapytania DNS pasujące do tych domen, a zapytania te nawet nie pojawiają się w dzienniku zapytań",
"addClientFieldDescription": "CIDRs, adres IP or ClientID",
"clientIdentifier": "Identyfikator klienta",
"allowClient": "Zezwól klientowi",
"disallowClient": "Nie zezwalaj klientowi",
"noDisallowedDomains": "Brak niedozwolonych domen",
"domainNotAdded": "Nie można dodać domeny",
"statusSelected": "Wybrany status",
"updateLists": "Aktualizuj listy",
"checkHostFiltered": "Sprawdź hosta",
"updatingLists": "Aktualizowanie list...",
"listsUpdated": "Zaktualizowano listy",
"listsNotUpdated": "Nie można zaktualizować list",
"listsNotLoaded": "Nie można załadować list",
"domainNotValid": "Nieprawidłowa domena",
"check": "Sprawdź",
"checkingHost": "Sprawdzanie hosta...",
"errorCheckingHost": "Nie można sprawdzić hosta",
"block": "Zablokować",
"unblock": "Odblokować",
"custom": "Niestandardowy",
"addImportant": "Dodawaj $important",
"howCreateRules": "Jak tworzyć reguły niestandardowe",
"examples": "Przykłady",
"example1": "Zablokuj dostęp do example.org i wszystkich jej subdomen.",
"example2": "Odblokowuje dostęp do example.org i wszystkich jego subdomen.",
"example3": "Dodaje komentarz.",
"example4": "Blokowanie dostępu do domen zgodnych z określonym wyrażeniem regularnym.",
"moreInformation": "Więcej informacji",
"addingRule": "Dodawanie reguły...",
"deletingRule": "Usuwanie reguły...",
"enablingList": "Włączanie listy...",
"disablingList": "Wyłączanie listy...",
"disableFiltering": "Wyłącz filtrowanie",
"enablingFiltering": "Włączanie filtrowania...",
"disablingFiltering": "Wyłączanie filtrowania...",
"filteringStatusUpdated": "Stan filtrowania został pomyślnie zaktualizowany",
"filteringStatusNotUpdated": "Nie można zaktualizować stanu filtrowania",
"updateFrequency": "Częstotliwość aktualizacji",
"never": "Nigdy",
"hour1": "Co 1 godzinę",
"hours12": "Co 12 godzin",
"hours24": "Co 24 godziny",
"days3": "Co 3 dni",
"days7": "Co 7 dni",
"changingUpdateFrequency": "Zmieniam...",
"updateFrequencyChanged": "Częstotliwość aktualizacji została pomyślnie zmieniona",
"updateFrequencyNotChanged": "Nie można zmienić częstotliwości aktualizacji",
"updating": "Aktualizowanie wartości...",
"blockedServicesUpdated": "Zablokowane usługi zostały pomyślnie zaktualizowane",
"blockedServicesNotUpdated": "Nie można zaktualizować zablokowanych usług",
"insertDomain": "Wstaw domenę, aby sprawdzić jej status.",
"dhcpSettings": "Ustawienia DHCP",
"dhcpSettingsDescription": "Konfigurowanie serwera DHCP",
"dhcpSettingsNotLoaded": "Nie można załadować ustawień DHCP",
"loadingDhcp": "Ładowanie ustawień DHCP...",
"enableDhcpServer": "Włącz serwer DHCP",
"selectInterface": "Wybierz interfejs",
"hardwareAddress": "Adres sprzętowy",
"gatewayIp": "Adres IP bramy",
"ipv4addresses": "Adres IPv4",
"ipv6addresses": "Adres IPv6",
"neededSelectInterface": "Aby skonfigurować serwer DHCP, należy wybrać interfejs.",
"ipv4settings": "Ustawienia IPv4",
"startOfRange": "Początek zakresu",
"endOfRange": "Koniec zakresu",
"ipv6settings": "Ustawienia IPv6",
"subnetMask": "Maska podsieci",
"subnetMaskNotValid": "Maska podsieci jest nieprawidłowa",
"gateway": "Brama",
"gatewayNotValid": "Brama jest nieprawidłowa",
"leaseTime": "Czas dzierżawy",
"seconds": "{time} sekund",
"leaseTimeNotValid": "Czas dzierżawy jest nieaktualny",
"restoreConfiguration": "Zresetuj konfigurację",
"restoreConfigurationMessage": "Czy na pewno chcesz kontynuować? Spowoduje to zresetowanie całej konfiguracji. Tej czynności nie można cofnąć.",
"changeInterface": "Zmień interfejs",
"savingSettings": "Zapisywanie ustawień...",
"settingsSaved": "Ustawienia zapisane pomyślnie",
"settingsNotSaved": "Nie można zapisać ustawień",
"restoringConfig": "Przywracanie konfiguracji...",
"configRestored": "Konfiguracja została zresetowana pomyślnie",
"configNotRestored": "Nie można zresetować konfiguracji",
"dhcpStatic": "Dzierżawy statyczne DHCP",
"noDhcpStaticLeases": "Nie znaleziono dzierżaw statycznych DHCP",
"deleting": "Usuwanie...",
"staticLeaseDeleted": "Dzierżawa statyczna DHCP została pomyślnie usunięta",
"staticLeaseNotDeleted": "Nie można usunąć dzierżawy statycznej DHCP",
"deleteStaticLease": "Usuwanie dzierżawy statycznej...",
"deleteStaticLeaseDescription": "Dzierżawa statyczna DHCP zostanie usunięta. Tej akcji nie można cofnąć.",
"addStaticLease": "Dodawanie dzierżawy statycznej",
"macAddress": "Adres MAC",
"macAddressNotValid": "Nieprawidłowy adres MAC",
"hostName": "Nazwa hosta",
"hostNameError": "Nazwa hosta nie może być pusta",
"creating": "Tworzenie...",
"staticLeaseCreated": "Dzierżawa statyczna DHCP utworzona pomyślnie",
"staticLeaseNotCreated": "Nie można utworzyć dzierżawy statycznej DHCP",
"staticLeaseExists": "Dzierżawa statyczna DHCP już istnieje",
"serverNotConfigured": "Serwer nie jest skonfigurowany",
"restoreLeases": "Resetowanie dzierżaw",
"restoreLeasesMessage": "Czy na pewno chcesz kontynuować? Spowoduje to zresetowanie wszystkich istniejących dzierżaw. Tej czynności nie można cofnąć.",
"restoringLeases": "Resetowanie dzierżaw...",
"leasesRestored": "Dzierżawy zostały pomyślnie zresetowane",
"leasesNotRestored": "Nie można zresetować dzierżaw",
"dhcpLeases": "Dzierżawy DHCP",
"noLeases": "Brak dostępnych dzierżaw DHCP",
"dnsRewrites": "Przepisywanie DNS",
"dnsRewritesDescription": "Konfigurowanie niestandardowych reguł DNS",
"loadingRewriteRules": "Wczytywanie reguł przepisywania...",
"rewriteRulesNotLoaded": "Nie można załadować reguł przepisywania DNS.",
"noRewriteRules": "Brak reguł przepisywania DNS.",
"answer": "Odpowiedź",
"deleteDnsRewrite": "Usuń przepisywanie DNS",
"deleteDnsRewriteMessage": "Czy na pewno chcesz usunąć to przepisanie DNS? Tej akcji nie można cofnąć.",
"dnsRewriteRuleDeleted": "Reguła przepisywania DNS została pomyślnie usunięta",
"dnsRewriteRuleNotDeleted": "Nie można usunąć reguły przepisywania DNS",
"addDnsRewrite": "Dodaj przepisywanie DNS",
"addingRewrite": "Dodawanie przepisywania...",
"dnsRewriteRuleAdded": "Pomyślnie dodano regułę przepisywania DNS",
"dnsRewriteRuleNotAdded": "Nie można dodać reguły przepisywania DNS",
"logsSettings": "Ustawienia dzienników logów",
"enableLog": "Włącz dziennik logów",
"clearLogs": "Czyszczenie dzienników logów",
"anonymizeClientIp": "Anonimizuj adres IP klienta",
"hours6": "co 6 godzin",
"days30": "co 30 dni",
"days90": "co 90 dni",
"retentionTime": "Czas retencji",
"selectOneItem": "Wybierz jeden element",
"logSettingsNotLoaded": "Nie można załadować ustawień dziennika logów.",
"updatingSettings": "Aktualizowanie ustawień...",
"logsConfigUpdated": "Ustawienia dzienników logów zostały pomyślnie zaktualizowane",
"logsConfigNotUpdated": "Nie można zaktualizować ustawień dzienników logów",
"deletingLogs": "Czyszczenie dzienników logów...",
"logsCleared": "Dzienniki logów wyczyszczone pomyślnie",
"logsNotCleared": "Nie można wyczyścić dzienników logów",
"runningHomeAssistant": "Działa na Home Assistant",
"serverError": "Błąd serwera",
"noItems": "Brak elementów do pokazania w tym miejscu",
"dnsSettings": "Ustawienia DNS",
"dnsSettingsDescription": "Konfigurowanie połączenia z serwerami DNS",
"upstreamDns": "Nadrzędne serwery DNS",
"bootstrapDns": "Serwery DNS Bootstrap",
"noUpstreamDns": "Nie dodano nadrzędnych serwerów DNS.",
"dnsMode": "Tryb DNS",
"noDnsMode": "Nie wybrano trybu DNS",
"loadBalancing": "Równoważenie obciążenia",
"parallelRequests": "Równoległe żądania",
"fastestIpAddress": "Najszybszy adres IP",
"loadBalancingDescription": "Wysyłaj zapytania do jednego serwera nadrzędnego naraz. AdGuard Home wykorzystuje ważony algorytm losowy, aby wybrać serwer, dzięki czemu najszybszy serwer jest używany częściej.",
"parallelRequestsDescription": "Użyj zapytań równoległych, aby przyspieszyć rozwiązywanie problemów, wysyłając jednocześnie zapytania do wszystkich serwerów nadrzędnych.",
"fastestIpAddressDescription": "Odpytuj wszystkie serwery DNS i zwracaj najszybszy adres IP spośród wszystkich odpowiedzi. Spowalnia to zapytania DNS, ponieważ AdGuard Home musi czekać na odpowiedzi ze wszystkich serwerów DNS, ale poprawia ogólną łączność.",
"noBootstrapDns": "Nie dodano żadnych serwerów Bootstrap DNS.",
"bootstrapDnsServersInfo": "Serwery DNS Bootstrap służą do rozpoznawania adresów IP programów rozpoznawania nazw DoH/DoT określonych jako nadrzędne.",
"privateReverseDnsServers": "Prywatne zwrotne serwery DNS",
"privateReverseDnsServersDescription": "Serwery DNS, których AdGuard Home używa do lokalnych zapytań PST. Serwery te są używane na przykład do rozwiązywania żądań PST dotyczących adresów w prywatnych zakresach adresów IP \"192.168.12.34\", przy użyciu odwrotnego DNS. Jeśli nie jest ustawiony, AdGuard Home używa adresów domyślnych programów rozpoznawania nazw DNS systemu operacyjnego, z wyjątkiem adresów samego AdGuard Home.",
"reverseDnsDefault": "Domyślnie AdGuard Home używa następujących programów do rozpoznawania odwrotnych nazw DNS",
"addItem": "Dodaj element",
"noServerAddressesAdded": "Nie dodano adresów serwerów.",
"usePrivateReverseDnsResolvers": "Użyj prywatnych programów do rozpoznawania nazw zwrotnych DNS",
"usePrivateReverseDnsResolversDescription": "Wykonaj odwrotne wyszukiwanie DNS dla adresów obsługiwanych lokalnie przy użyciu tych serwerów nadrzędnych. Jeśli jest wyłączona, AdGuard Home odpowiada NXDOMAIN na wszystkie takie żądania PST, z wyjątkiem klientów znanych z DHCP, /etc/hosts itd.",
"enableReverseResolving": "Włącz odwrotne rozpoznawanie adresów IP klientów",
"enableReverseResolvingDescription": "Odwrotne rozpoznawanie adresów IP klientów w ich nazwach hostów przez wysyłanie zapytań PTR do odpowiednich programów rozpoznawania nazw (prywatne serwery DNS dla klientów lokalnych, serwery nadrzędne dla klientów z publicznymi adresami IP).",
"dnsServerSettings": "Ustawienia serwera DNS AdGuard Home",
"limitRequestsSecond": "Limit szybkości na sekundę",
"valueNotNumber": "Wartość nie jest liczbą",
"enableEdns": "Włączanie podsieci klienta EDNS",
"enableEdnsDescription": "Dodaj opcję podsieci klienta EDNS (ECS) do żądań nadrzędnych i rejestruj wartości wysyłane przez klientów w dzienniku zapytań.",
"enableDnssec": "Włącz usługę DNSSEC",
"enableDnssecDescription": "Ustaw flagę DNSSEC w wychodzących zapytaniach DNS i sprawdź wynik (wymagany jest moduł rozpoznawania nazw obsługujący DNSSEC).",
"disableResolvingIpv6": "Wyłączanie rozpoznawania adresów IPv6",
"disableResolvingIpv6Description": "Usuń wszystkie zapytania DNS dotyczące adresów IPv6 (typ AAAA).",
"blockingMode": "Tryb blokowania",
"defaultMode": "Domyślny",
"defaultDescription": "Odpowiedz zerowym adresem IP (0.0.0.0 dla A; :: dla AAAA), gdy zostanie zablokowany przez regułę w stylu Adblock; odpowiedz adresem IP określonym w regule, jeśli zostanie zablokowany przez regułę w stylu /etc/hosts",
"refusedDescription": "Odpowiedz kodem REFUSED",
"nxdomainDescription": "Odpowiadanie za pomocą kodu NXDOMAIN",
"nullIp": "Null IP",
"nullIpDescription": "Odpowiedz, podając zerowy adres IP (0.0.0.0 dla A; :: dla AAAA)",
"customIp": "Niestandardowy adres IP",
"customIpDescription": "Odpowiadanie przy użyciu ręcznie ustawionego adresu IP",
"dnsCacheConfig": "Konfiguracja pamięci podręcznej DNS",
"cacheSize": "Rozmiar pamięci podręcznej",
"inBytes": "W bajtach",
"overrideMinimumTtl": "Zastąp minimalny czas TTL",
"overrideMinimumTtlDescription": "Wydłużanie wartości krótkiego czasu wygaśnięcia (sekund) odbieranych z serwera nadrzędnego podczas buforowania odpowiedzi DNS.",
"overrideMaximumTtl": "Zastąp maksymalne ustawienie TTL",
"overrideMaximumTtlDescription": "Ustaw maksymalną wartość czasu wygaśnięcia (sekundy) dla wpisów w pamięci podręcznej DNS.",
"optimisticCaching": "Optymistyczne buforowanie",
"optimisticCachingDescription": "Spraw, aby AdGuard Home odpowiadał z pamięci podręcznej, nawet gdy wpisy wygasły, a także spróbuj je odświeżyć.",
"loadingDnsConfig": "Ładowanie konfiguracji DNS...",
"dnsConfigNotLoaded": "Nie można załadować konfiguracji DNS.",
"blockingIpv4": "Blokowanie protokołu IPv4",
"blockingIpv4Description": "Adres IP do zwrócenia w przypadku zablokowanego żądania A",
"blockingIpv6": "Blokowanie protokołu IPv6",
"blockingIpv6Description": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania AAAA",
"invalidIp": "Nieprawidłowy adres IP",
"dnsConfigSaved": "Konfiguracja serwera DNS zapisana pomyślnie",
"dnsConfigNotSaved": "Nie można zapisać konfiguracji serwera DNS",
"savingConfig": "Zapisywanie konfiguracji...",
"someValueNotValid": "Niektóre wartości są nieprawidłowe",
"upstreamDnsDescription": "Konfigurowanie serwerów nadrzędnych i trybu DNS",
"bootstrapDnsDescription": "Konfigurowanie serwerów DNS ładowania początkowego",
"privateReverseDnsDescription": "Konfigurowanie niestandardowych programów rozpoznawania nazw DNS i włączanie prywatnego rozpoznawania zwrotnej domeny DNS",
"dnsServerSettingsDescription": "Konfigurowanie limitu szybkości, trybu blokowania i innych funkcji",
"dnsCacheConfigDescription": "Konfigurowanie sposobu zarządzania pamięcią podręczną DNS przez serwer",
"comment": "Komentarz",
"address": "Adres",
"commentsDescription": "Komentarze są zawsze poprzedzone znakiem #. Nie musisz go dodawać, zostanie dodany automatycznie.",
"encryptionSettings": "Ustawienia szyfrowania",
"encryptionSettingsDescription": "Obsługa szyfrowania (HTTPS/QUIC/TLS)",
"loadingEncryptionSettings": "Ładowanie ustawień szyfrowania...",
"encryptionSettingsNotLoaded": "Nie można załadować ustawień szyfrowania.",
"enableEncryption": "Włącz szyfrowanie",
"enableEncryptionTypes": "HTTPS, DNS przez HTTPS i DNS przez TLS",
"enableEncryptionDescription": "Jeśli szyfrowanie jest włączone, interfejs administratora AdGuard Home będzie działał przez HTTPS, a serwer DNS będzie nasłuchiwał żądań przez DNS przez HTTPS i DNS przez TLS.",
"serverConfiguration": "Konfiguracja serwera",
"domainName": "Nazwa domeny",
"domainNameDescription": "Jeśli jest ustawiony, AdGuard Home wykrywa identyfikatory klientów, odpowiada na zapytania DDR i wykonuje dodatkowe walidacje połączeń. Jeśli te funkcje nie są ustawione, są wyłączone. Musi być zgodna z jedną z nazw DNS w certyfikacie.",
"redirectHttps": "Automatyczne przekierowywanie do protokołu HTTPS",
"httpsPort": "Port HTTPS",
"tlsPort": "DNS przez port TLS",
"dnsOverQuicPort": "DNS przez port QUIC",
"certificates": "Certifikaty",
"certificatesDescription": "Aby korzystać z szyfrowania, musisz podać prawidłowy łańcuch certyfikatów SSL dla swojej domeny. Możesz uzyskać bezpłatny certyfikat na letsencrypt.org lub kupić go w jednym z zaufanych urzędów certyfikacji.",
"certificateFilePath": "Ustaw ścieżkę pliku certyfikatów",
"pasteCertificateContent": "Wklejanie zawartości certyfikatów",
"certificatePath": "Ścieżka certyfikatu",
"certificateContent": "Zawartość certyfikatu",
"privateKey": "Klucz prywatny",
"privateKeyFile": "Ustaw plik klucza prywatnego",
"pastePrivateKey": "Wklejanie zawartości klucza prywatnego",
"usePreviousKey": "Użyj wcześniej zapisanego klucza",
"privateKeyPath": "Ścieżka klucza prywatnego",
"invalidCertificate": "Nieprawidłowy certyfikat",
"invalidPrivateKey": "Nieprawidłowy klucz prywatny",
"validatingData": "Sprawdzanie poprawności danych",
"dataValid": "Dane prawidłowe",
"dataNotValid": "Dane nieprawidłowe",
"encryptionConfigSaved": "Konfiguracja szyfrowania zapisana pomyślnie",
"encryptionConfigNotSaved": "Nie można zapisać konfiguracji szyfrowania",
"configError": "Błąd konfiguracji",
"enterOnlyCertificate": "Wprowadź tylko certyfikat. Nie wpisuj linii ---BEGIN--- i ---END---.",
"enterOnlyPrivateKey": "Wprowadź tylko klucz. Nie wpisuj linii ---BEGIN--- i ---END---.",
"noItemsSearch": "Brak elementów dla tego wyszukiwania.",
"clearSearch": "Wyczyść wyszukiwanie",
"exitSearch": "Zakończ wyszukiwanie",
"searchClients": "Wyszukaj klientów",
"noClientsSearch": "Brak klientów dla tego wyszukiwania.",
"customization": "Personalizacja",
"customizationDescription": "Dostosuj tę aplikację",
"color": "Kolor",
"useDynamicTheme": "Użyj motywu dynamicznego",
"red": "Czerwony",
"green": "Zielony",
"blue": "Niebieski",
"yellow": "Żółty",
"orange": "Pomarańczowy",
"brown": "Brązowy",
"cyan": "Błękitny",
"purple": "Fioletowy",
"pink": "Różowy",
"deepOrange": "Głęboki pomarańczowy",
"indigo": "Indygo",
"useThemeColorStatus": "Użyj koloru motywu dla statusu",
"useThemeColorStatusDescription": "Zastępuje zielone i czerwone kolory statusu kolorami motywu i szarością",
"invalidCertificateChain": "Nieprawidłowy łańcuch certyfikatów",
"validCertificateChain": "Prawidłowy łańcuch certyfikatów",
"subject": "Temat",
"issuer": "Wydawca",
"expires": "Wygasa",
"validPrivateKey": "Prawidłowy klucz prywatny",
"expirationDate": "Data ważności",
"keysNotMatch": "Nieprawidłowy certyfikat lub klucz: TLS: klucz prywatny nie jest zgodny z kluczem publicznym",
"timeLogs": "Czas w dziennikach logów",
"timeLogsDescription": "Pokaż czas przetwarzania na liście dzienników logów",
"hostNames": "Nazwy hostów",
"keyType": "Typ klucza",
"updateAvailable": "Dostępna aktualizacja",
"installedVersion": "Zainstalowana wersja",
"newVersion": "Nowa wersja",
"source": "Źródło",
"downloadUpdate": "Pobierz aktualizację",
"download": "Pobierz",
"doNotRememberAgainUpdate": "Nie pamiętam ponownie dla tej wersji",
"downloadingUpdate": "Pobieranie aktualizacji",
"completed": "ukończone",
"permissionNotGranted": "Pozwolenie nie zostało udzielone",
"inputSearchTerm": "Wprowadź wyszukiwany termin.",
"answers": "Odpowiedzi",
"copyClipboard": "Kopiuj do schowka",
"domainCopiedClipboard": "Domena skopiowana do schowka",
"clearDnsCache": "Wyczyść pamięć podręczną DNS",
"clearDnsCacheMessage": "Czy na pewno chcesz wyczyścić pamięć podręczną DNS?",
"dnsCacheCleared": "Pamięć podręczna DNS została pomyślnie wyczyszczona",
"clearingDnsCache": "Czyszczenie pamięci podręcznej...",
"dnsCacheNotCleared": "Nie można wyczyścić pamięci podręcznej DNS",
"clientsSelected": "Wybrani klienci",
"invalidDomain": "Nieprawidłowa domena",
"loadingBlockedServicesList": "Ładowanie listy zablokowanych usług...",
"blockedServicesListNotLoaded": "Nie można załadować listy zablokowanych usług",
"error": "Błąd",
"updates": "Aktualizacje",
"updatesDescription": "Zaktualizuj serwer AdGuard Home",
"updateNow": "Aktualizuj teraz",
"currentVersion": "Aktualna wersja",
"requestStartUpdateFailed": "Żądanie rozpoczęcia aktualizacji nie powiodło się",
"requestStartUpdateSuccessful": "Żądanie rozpoczęcia aktualizacji powiodło się",
"serverUpdated": "Serwer jest aktualizowany",
"unknownStatus": "Status nieznany",
"checkingUpdates": "Sprawdzanie aktualizacji...",
"checkUpdates": "Sprawdź aktualizacje",
"requestingUpdate": "Żądanie aktualizacji...",
"autoupdateUnavailable": "Automatyczna aktualizacja jest niedostępna",
"autoupdateUnavailableDescription": "Usługa automatycznej aktualizacji nie jest dostępna dla tego serwera. Może to być spowodowane tym, że serwer działa w kontenerze Docker. Musisz zaktualizować serwer ręcznie.",
"minute": "{time} minut",
"minutes": "{time} minut",
"hour": "{time} godzina",
"hours": "{time} godzin",
"remainingTime": "Pozostały czas",
"safeSearchSettings": "Ustawienia bezpiecznego wyszukiwania",
"loadingSafeSearchSettings": "Ładowanie ustawień bezpiecznego wyszukiwania...",
"safeSearchSettingsNotLoaded": "Błąd podczas ładowania ustawień bezpiecznego wyszukiwania.",
"loadingLogsSettings": "Ładowanie ustawień dzienników logów...",
"selectOptionLeftColumn": "Wybierz opcję lewej kolumny",
"selectClientLeftColumn": "Wybierz klienta z lewej kolumny",
"disableList": "Wyłącz listę",
"enableList": "Włącz listę",
"screens": "Ekrany",
"copiedClipboard": "Skopiowane do schowka",
"seeDetails": "Zobacz szczegóły",
"listNotAvailable": "Lista niedostępna",
"copyListUrl": "Skopiuj adres URL listy",
"listUrlCopied": "Adres URL listy skopiowany do schowka",
"unsupportedVersion": "Nieobsługiwana wersja",
"unsupprtedVersionMessage": "Nie gwarantuje się wsparcia dla wersji serwera {version}. Ta aplikacja może mieć pewne problemy z działaniem na tej wersji serwera.\n\nAdGuard Home Manager został zaprojektowany do współpracy ze stabilnymi wersjami serwera AdGuard Home. Może działać z wersjami alfa i beta, ale kompatybilność nie jest gwarantowana, a aplikacja może mieć pewne problemy z działaniem w tych wersjach.",
"iUnderstand": "Rozumiem",
"appUpdates": "Aktualizacje aplikacji",
"usingLatestVersion": "Używasz najnowszej wersji",
"ipLogs": "IP w dziennikach logów",
"ipLogsDescription": "Pokaż zawsze adres IP w dziennikach logów zamiast nazwy klienta",
"application": "Aplikacja",
"combinedChart": "Wykres łączony",
"combinedChartDescription": "Połącz wszystkie wykresy w jeden",
"statistics": "Statystyka",
"errorLoadFilters": "Błąd podczas ładowania filtrów.",
"clientRemovedSuccessfully": "Klient został pomyślnie usunięty.",
"editRewriteRule": "Edytowanie reguły przepisywania",
"dnsRewriteRuleUpdated": "Reguła przepisywania DNS została pomyślnie zaktualizowana",
"dnsRewriteRuleNotUpdated": "Nie można zaktualizować reguły przepisywania DNS",
"updatingRule": "Aktualizuję regułę...",
"serverUpdateNeeded": "Wymagana aktualizacja serwera",
"updateYourServer": "Aby móc korzystać z tej funkcji, zaktualizuj serwer AdGuard Home do wersji {version} lub nowszej.",
"january": "Styczeń",
"february": "Luty",
"march": "Mrzec",
"april": "Kwiecień",
"may": "Maj",
"june": "Czerwiec",
"july": "Lipiec",
"august": "Sierpień",
"september": "Wrzesień",
"october": "Październik",
"november": "Listopad",
"december": "Grudzień",
"malwarePhising": "Złośliwe oprogramowanie / wyłudzanie informacji",
"queries": "Zapytania",
"adultSites": "Strony dla dorosłych",
"quickFilters": "Szybkie filtry",
"searchDomainInternet": "Wyszukaj domenę w Internecie"
}

View file

@ -228,7 +228,8 @@ class _MainState extends State<Main> {
Locale('en', ''),
Locale('es', ''),
Locale('zh', ''),
Locale('zh', 'CN')
Locale('zh', 'CN'),
Locale('pl', '')
],
scaffoldMessengerKey: scaffoldMessengerKey,
builder: (context, child) {

View file

@ -1,10 +1,15 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/scheduler.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:store_checker/store_checker.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:sqflite/sqlite_api.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/config/home_top_items_default_order.dart';
import 'package:adguard_home_manager/models/github_release.dart';
import 'package:adguard_home_manager/services/db/queries.dart';
import 'package:adguard_home_manager/functions/conversions.dart';
@ -31,6 +36,10 @@ class AppConfigProvider with ChangeNotifier {
int _selectedClientsTab = 0;
int _selectedFiltersTab = 0;
List<HomeTopItems> _homeTopItemsOrder = homeTopItemsDefaultOrder;
int _hideServerAddress = 0;
final List<AppLog> _logs = [];
int _overrideSslCheck = 0;
@ -151,6 +160,14 @@ class AppConfigProvider with ChangeNotifier {
return _installationSource;
}
List<HomeTopItems> get homeTopItemsOrder {
return _homeTopItemsOrder;
}
bool get hideServerAddress {
return _hideServerAddress == 1 ? true : false;
}
void setDbInstance(Database db) {
_dbInstance = db;
}
@ -353,6 +370,39 @@ class AppConfigProvider with ChangeNotifier {
}
}
Future<bool> setHomeTopItemsOrder(List<HomeTopItems> order) async {
final updated = await updateConfigQuery(
db: _dbInstance!,
column: 'homeTopItemsOrder',
value: jsonEncode(List<String>.from(order.map((e) => e.name)))
);
if (updated == true) {
_homeTopItemsOrder = order;
notifyListeners();
return true;
}
else {
return false;
}
}
Future<bool> setHideServerAddress(bool value) async {
final updated = await updateConfigQuery(
db: _dbInstance!,
column: 'hideServerAddress',
value: value == true ? 1 : 0
);
if (updated == true) {
_hideServerAddress = value == true ? 1 : 0;
notifyListeners();
return true;
}
else {
return false;
}
}
Future<bool> setDoNotRememberVersion(String value) async {
final updated = await updateConfigQuery(
db: _dbInstance!,
@ -373,6 +423,31 @@ class AppConfigProvider with ChangeNotifier {
_doNotRememberVersion = dbData['doNotRememberVersion'];
_showIpLogs = dbData['showIpLogs'] ?? 0;
_combinedChartHome = dbData['combinedChart'] ?? 0;
_hideServerAddress = dbData['hideServerAddress'];
if (dbData['homeTopItemsOrder'] != null) {
try {
_homeTopItemsOrder = List<HomeTopItems>.from(
List<String>.from(jsonDecode(dbData['homeTopItemsOrder'])).map((e) {
switch (e) {
case 'queriedDomains':
return HomeTopItems.queriedDomains;
case 'blockedDomains':
return HomeTopItems.blockedDomains;
case 'recurrentClients':
return HomeTopItems.recurrentClients;
default:
return null;
}
}).where((e) => e != null).toList()
);
} catch (e) {
Sentry.captureException(e);
_homeTopItemsOrder = homeTopItemsDefaultOrder;
}
}
_dbInstance = dbInstance;
notifyListeners();

View file

@ -90,18 +90,20 @@ class HomeAppBar extends StatelessWidget {
if (serversProvider.selectedServer != null) ...[
Text(
server!.name,
style: const TextStyle(
style: !appConfigProvider.hideServerAddress ? const TextStyle(
fontSize: 20
),
) : null,
),
const SizedBox(height: 5),
Text(
"${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}",
style: TextStyle(
fontSize: 14,
color: Theme.of(context).listTileTheme.textColor
),
)
if (!appConfigProvider.hideServerAddress) ...[
const SizedBox(height: 5),
Text(
"${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}",
style: TextStyle(
fontSize: 14,
color: Theme.of(context).listTileTheme.textColor
),
)
]
],
if (serversProvider.selectedServer == null) Text(
AppLocalizations.of(context)!.noServerSelected,

View file

@ -27,7 +27,7 @@ class HomeChart extends StatelessWidget {
Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final bool isEmpty = data.any((i) => i == 0);
final bool isEmpty = data.every((i) => i == 0);
if (!(appConfigProvider.hideZeroValues == true && isEmpty == true)) {
List<DateTime> dateTimes = [];

View file

@ -175,88 +175,107 @@ class _HomeState extends State<Home> {
child: CombinedHomeChart(),
),
if (width <= 700) ...[
TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: statusProvider.serverStatus!.stats.topQueriedDomains,
type: 'topQueriedDomains',
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
const SizedBox(height: 16),
TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: statusProvider.serverStatus!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
const SizedBox(height: 16),
TopItems(
label: AppLocalizations.of(context)!.topClients,
data: statusProvider.serverStatus!.stats.topClients,
type: 'topClients',
clients: true,
),
],
if (width <= 700) ...appConfigProvider.homeTopItemsOrder.asMap().entries.map((item) {
Widget list() {
switch (item.value) {
case HomeTopItems.queriedDomains:
return TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: statusProvider.serverStatus!.stats.topQueriedDomains,
type: 'topQueriedDomains',
);
case HomeTopItems.blockedDomains:
return TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: statusProvider.serverStatus!.stats.topBlockedDomains,
type: 'topBlockedDomains',
);
case HomeTopItems.recurrentClients:
return TopItems(
label: AppLocalizations.of(context)!.topClients,
data: statusProvider.serverStatus!.stats.topClients,
type: 'topClients',
clients: true,
);
default:
return const SizedBox();
}
}
return Column(
children: [
list(),
if (item.key < appConfigProvider.homeTopItemsOrder.length - 1) ...[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
const SizedBox(height: 16),
]
],
);
}),
if (width > 700) Column(
children: [
Wrap(
alignment: WrapAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: statusProvider.serverStatus!.stats.topQueriedDomains,
type: 'topQueriedDomains',
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: statusProvider.serverStatus!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topClients,
data: statusProvider.serverStatus!.stats.topClients,
type: 'topClients',
),
),
),
],
children: appConfigProvider.homeTopItemsOrder.map((item) {
switch (item) {
case HomeTopItems.queriedDomains:
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: statusProvider.serverStatus!.stats.topQueriedDomains,
type: 'topQueriedDomains',
),
),
);
case HomeTopItems.blockedDomains:
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: statusProvider.serverStatus!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
),
);
case HomeTopItems.recurrentClients:
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topClients,
data: statusProvider.serverStatus!.stats.topClients,
type: 'topClients',
),
),
);
default:
return const SizedBox();
}
}).toList(),
),
],
)
@ -282,6 +301,7 @@ class _HomeState extends State<Home> {
child: Builder(
builder: (context) => RefreshIndicator(
color: Theme.of(context).colorScheme.primary,
displacement: 95,
onRefresh: () async {
final result = await statusProvider.getServerStatus();
if (result == false) {

View file

@ -82,111 +82,15 @@ class LogDetailsScreen extends StatelessWidget {
}
}
Widget content() {
return ListView(
children: [
SectionLabel(label: AppLocalizations.of(context)!.status),
LogListTile(
icon: Icons.shield_rounded,
title: AppLocalizations.of(context)!.result,
subtitleWidget: getResult(),
trailing: log.cached == true
? Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5
),
decoration: BoxDecoration(
color: Theme.of(context).floatingActionButtonTheme.backgroundColor,
borderRadius: BorderRadius.circular(30)
),
child: Text(
"CACHE",
style: TextStyle(
fontSize: 12,
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
fontWeight: FontWeight.w500
),
),
)
: null,
),
if (log.rule != null) LogListTile(
icon: Icons.block,
title: AppLocalizations.of(context)!.blockingRule,
subtitle: log.rule
),
LogListTile(
icon: Icons.schedule,
title: AppLocalizations.of(context)!.time,
subtitle: convertTimestampLocalTimezone(log.time, 'HH:mm:ss')
),
SectionLabel(label: AppLocalizations.of(context)!.request),
LogListTile(
icon: Icons.domain_rounded,
title: AppLocalizations.of(context)!.domain,
subtitle: log.question.name
),
LogListTile(
icon: Icons.category_rounded,
title: AppLocalizations.of(context)!.type,
subtitle: log.question.type
),
LogListTile(
icon: Icons.class_rounded,
title: AppLocalizations.of(context)!.clas,
subtitle: log.question.questionClass
),
SectionLabel(label: AppLocalizations.of(context)!.response),
if (log.upstream != null && log.upstream != '') LogListTile(
icon: Icons.dns_rounded,
title: AppLocalizations.of(context)!.dnsServer,
subtitle: log.upstream
),
LogListTile(
icon: Icons.timer_rounded,
title: AppLocalizations.of(context)!.elapsedTime,
subtitle: "${double.parse(log.elapsedMs).toStringAsFixed(2)} ms"
),
if (log.status != null) LogListTile(
icon: Icons.system_update_alt_rounded,
title: AppLocalizations.of(context)!.responseCode,
subtitle: log.status
),
SectionLabel(label: AppLocalizations.of(context)!.client),
LogListTile(
icon: Icons.smartphone_rounded,
title: AppLocalizations.of(context)!.deviceIp,
subtitle: log.client
),
if (log.clientInfo != null && log.clientInfo!.name != '') LogListTile(
icon: Icons.abc_rounded,
title: AppLocalizations.of(context)!.deviceName,
subtitle: log.clientInfo!.name
),
if (log.rules.isNotEmpty) ...[
SectionLabel(label: AppLocalizations.of(context)!.rules),
...log.rules.map((rule) {
final Filter? list = getList(rule.filterListId);
if (list != null) {
return LogListTile(
icon: Icons.rule_rounded,
title: rule.text,
subtitle: list.name
);
}
else {
return const SizedBox();
}
}).toList()
],
if (log.answer.isNotEmpty) ...[
SectionLabel(label: AppLocalizations.of(context)!.answers),
...log.answer.map((a) => LogListTile(
icon: Icons.download_rounded,
title: a.value,
subtitle: "TTL: ${a.ttl.toString()}",
trailing: Container(
List<Widget> content() {
return [
SectionLabel(label: AppLocalizations.of(context)!.status),
LogListTile(
icon: Icons.shield_rounded,
title: AppLocalizations.of(context)!.result,
subtitleWidget: getResult(),
trailing: log.cached == true
? Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5
@ -196,7 +100,7 @@ class LogDetailsScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(30)
),
child: Text(
a.type,
"CACHE",
style: TextStyle(
fontSize: 12,
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
@ -204,10 +108,104 @@ class LogDetailsScreen extends StatelessWidget {
),
),
)
)).toList()
]
: null,
),
if (log.rule != null) LogListTile(
icon: Icons.block,
title: AppLocalizations.of(context)!.blockingRule,
subtitle: log.rule
),
LogListTile(
icon: Icons.schedule,
title: AppLocalizations.of(context)!.time,
subtitle: convertTimestampLocalTimezone(log.time, 'HH:mm:ss')
),
SectionLabel(label: AppLocalizations.of(context)!.request),
LogListTile(
icon: Icons.domain_rounded,
title: AppLocalizations.of(context)!.domain,
subtitle: log.question.name
),
LogListTile(
icon: Icons.category_rounded,
title: AppLocalizations.of(context)!.type,
subtitle: log.question.type
),
LogListTile(
icon: Icons.class_rounded,
title: AppLocalizations.of(context)!.clas,
subtitle: log.question.questionClass
),
SectionLabel(label: AppLocalizations.of(context)!.response),
if (log.upstream != null && log.upstream != '') LogListTile(
icon: Icons.dns_rounded,
title: AppLocalizations.of(context)!.dnsServer,
subtitle: log.upstream
),
LogListTile(
icon: Icons.timer_rounded,
title: AppLocalizations.of(context)!.elapsedTime,
subtitle: "${double.parse(log.elapsedMs).toStringAsFixed(2)} ms"
),
if (log.status != null) LogListTile(
icon: Icons.system_update_alt_rounded,
title: AppLocalizations.of(context)!.responseCode,
subtitle: log.status
),
SectionLabel(label: AppLocalizations.of(context)!.client),
LogListTile(
icon: Icons.smartphone_rounded,
title: AppLocalizations.of(context)!.deviceIp,
subtitle: log.client
),
if (log.clientInfo != null && log.clientInfo!.name != '') LogListTile(
icon: Icons.abc_rounded,
title: AppLocalizations.of(context)!.deviceName,
subtitle: log.clientInfo!.name
),
if (log.rules.isNotEmpty) ...[
SectionLabel(label: AppLocalizations.of(context)!.rules),
...log.rules.map((rule) {
final Filter? list = getList(rule.filterListId);
if (list != null) {
return LogListTile(
icon: Icons.rule_rounded,
title: rule.text,
subtitle: list.name
);
}
else {
return const SizedBox();
}
}).toList()
],
);
if (log.answer.isNotEmpty) ...[
SectionLabel(label: AppLocalizations.of(context)!.answers),
...log.answer.map((a) => LogListTile(
icon: Icons.download_rounded,
title: a.value,
subtitle: "TTL: ${a.ttl.toString()}",
trailing: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5
),
decoration: BoxDecoration(
color: Theme.of(context).floatingActionButtonTheme.backgroundColor,
borderRadius: BorderRadius.circular(30)
),
child: Text(
a.type,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
fontWeight: FontWeight.w500
),
),
)
)).toList()
]
];
}
if (dialog) {
@ -269,7 +267,9 @@ class LogDetailsScreen extends StatelessWidget {
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: content(),
child: ListView(
children: content(),
)
),
)
],
@ -279,35 +279,60 @@ class LogDetailsScreen extends StatelessWidget {
}
else {
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text(AppLocalizations.of(context)!.logDetails),
actions: [
IconButton(
onPressed: () => openUrl("${Urls.googleSearchUrl}?q=${log.question.name}"),
icon: const Icon(Icons.travel_explore_rounded),
tooltip: AppLocalizations.of(context)!.searchDomainInternet
),
if (statusProvider.filteringStatus != null) IconButton(
onPressed: log.question.name != null
? () => blockUnblock(
log.question.name!,
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'
)
: null,
icon: Icon(
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? Icons.check_circle_rounded
: Icons.block
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar.large(
pinned: true,
floating: true,
centerTitle: false,
forceElevated: innerBoxIsScrolled,
title: Text(AppLocalizations.of(context)!.logDetails),
actions: [
IconButton(
onPressed: () => openUrl("${Urls.googleSearchUrl}?q=${log.question.name}"),
icon: const Icon(Icons.travel_explore_rounded),
tooltip: AppLocalizations.of(context)!.searchDomainInternet
),
if (statusProvider.filteringStatus != null) IconButton(
onPressed: log.question.name != null
? () => blockUnblock(
log.question.name!,
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'
)
: null,
icon: Icon(
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? Icons.check_circle_rounded
: Icons.block
),
tooltip: getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? AppLocalizations.of(context)!.unblockDomain
: AppLocalizations.of(context)!.blockDomain,
),
const SizedBox(width: 10)
],
),
tooltip: getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? AppLocalizations.of(context)!.unblockDomain
: AppLocalizations.of(context)!.blockDomain,
),
const SizedBox(width: 10)
)
],
body: SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
SliverList.list(
children: content()
)
],
),
)
)
),
body: content(),
);
}
}

View file

@ -31,8 +31,6 @@ class Logs extends StatefulWidget {
}
class _LogsState extends State<Logs> {
late ScrollController scrollController;
bool showDivider = true;
Log? selectedLog;
@ -65,25 +63,26 @@ class _LogsState extends State<Logs> {
}
}
void scrollListener() {
bool scrollListener(ScrollUpdateNotification scrollNotification) {
final logsProvider = Provider.of<LogsProvider>(context, listen: false);
if (scrollController.position.extentAfter < 500 && logsProvider.isLoadingMore == false) {
if (scrollNotification.metrics.extentAfter < 500 && logsProvider.isLoadingMore == false) {
logsProvider.fetchLogs(loadingMore: true);
}
if (scrollController.position.pixels > 0) {
if (scrollNotification.metrics.pixels > 0) {
setState(() => showDivider = false);
}
else {
setState(() => showDivider = true);
}
return false;
}
@override
void initState() {
final logsProvider = Provider.of<LogsProvider>(context, listen: false);
scrollController = ScrollController()..addListener(scrollListener);
logsProvider.fetchLogs(inOffset: 0);
fetchFilteringRules();
fetchClients();
@ -192,123 +191,169 @@ class _LogsState extends State<Logs> {
Widget generateBody() {
switch (logsProvider.loadStatus) {
case LoadStatus.loading:
return SizedBox(
width: double.maxFinite,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const CircularProgressIndicator(),
const SizedBox(height: 30),
Text(
AppLocalizations.of(context)!.loadingLogs,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
return SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
)
],
),
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,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
)
],
),
)
)
],
),
)
);
case LoadStatus.loaded:
return RefreshIndicator(
onRefresh: () async {
await logsProvider.fetchLogs(inOffset: 0);
},
child: logsProvider.logsData!.data.isNotEmpty
? ListView.builder(
controller: scrollController,
padding: const EdgeInsets.only(top: 0),
itemCount: logsProvider.isLoadingMore == true
? logsProvider.logsData!.data.length+1
: logsProvider.logsData!.data.length,
itemBuilder: (context, index) {
if (logsProvider.isLoadingMore == true && index == logsProvider.logsData!.data.length) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Center(
child: CircularProgressIndicator(),
),
);
}
else if (logsProvider.logsData!.data[index].question.name != null) {
return LogTile(
log: logsProvider.logsData!.data[index],
index: index,
length: logsProvider.logsData!.data.length,
isLogSelected: selectedLog != null && selectedLog == logsProvider.logsData!.data[index],
onLogTap: (log) {
if (width <= 1100) {
Navigator.push(context, MaterialPageRoute(
builder: (context) => LogDetailsScreen(
log: log,
dialog: false,
)
));
}
setState(() => selectedLog = log);
}
);
}
else {
return null;
}
}
)
: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
AppLocalizations.of(context)!.noLogsDisplay,
style: TextStyle(
fontSize: 24,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
return SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (context) => RefreshIndicator(
onRefresh: () async {
await logsProvider.fetchLogs(inOffset: 0);
},
displacement: 95,
child: NotificationListener(
onNotification: scrollListener,
child: CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
if (logsProvider.logsOlderThan != null) Padding(
padding: const EdgeInsets.only(
top: 30,
left: 20,
right: 20
),
child: Text(
AppLocalizations.of(context)!.noLogsThatOld,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurfaceVariant,
if (logsProvider.logsData!.data.isNotEmpty) SliverList.builder(
itemCount: logsProvider.isLoadingMore
? logsProvider.logsData!.data.length + 1
: logsProvider.logsData!.data.length,
itemBuilder: (context, index) {
if (logsProvider.isLoadingMore == true && index == logsProvider.logsData!.data.length) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Center(
child: CircularProgressIndicator(),
),
);
}
else if (logsProvider.logsData!.data[index].question.name != null) {
return LogTile(
log: logsProvider.logsData!.data[index],
index: index,
length: logsProvider.logsData!.data.length,
isLogSelected: selectedLog != null && selectedLog == logsProvider.logsData!.data[index],
onLogTap: (log) {
if (width <= 1100) {
Navigator.push(context, MaterialPageRoute(
builder: (context) => LogDetailsScreen(
log: log,
dialog: false,
)
));
}
setState(() => selectedLog = log);
}
);
}
else {
return null;
}
}
),
if (logsProvider.logsData!.data.isEmpty) SliverFillRemaining(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
AppLocalizations.of(context)!.noLogsDisplay,
style: TextStyle(
fontSize: 24,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
if (logsProvider.logsOlderThan != null) Padding(
padding: const EdgeInsets.only(
top: 30,
left: 20,
right: 20
),
child: Text(
AppLocalizations.of(context)!.noLogsThatOld,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
]
),
),
),
]
)
],
),
)
),
),
)
);
case LoadStatus.error:
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,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
return SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
)
],
),
SliverFillRemaining(
child: 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,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
)
],
),
)
)
],
),
)
);
default:
@ -318,183 +363,195 @@ class _LogsState extends State<Logs> {
Widget logsScreen() {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.logs),
centerTitle: false,
actions: [
if (!(Platform.isAndroid || Platform.isIOS)) IconButton(
onPressed: () => logsProvider.fetchLogs(inOffset: 0),
icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.refresh,
),
logsProvider.loadStatus == LoadStatus.loaded
? IconButton(
onPressed: openFilersModal,
icon: const Icon(Icons.filter_list_rounded),
tooltip: AppLocalizations.of(context)!.filters,
)
: const SizedBox(),
if (statusProvider.serverStatus != null) IconButton(
tooltip: AppLocalizations.of(context)!.settings,
onPressed: () => {
if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) {
showDialog(
context: context,
builder: (context) => LogsConfigModal(
onConfirm: updateConfig,
onClear: clearQueries,
dialog: true,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
barrierDismissible: false
)
}
else {
showModalBottomSheet(
context: context,
builder: (context) => LogsConfigModal(
onConfirm: updateConfig,
onClear: clearQueries,
dialog: false,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
backgroundColor: Colors.transparent,
isScrollControlled: true
)
}
},
icon: const Icon(Icons.settings)
),
const SizedBox(width: 5),
],
bottom: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all' || logsProvider.appliedFilters.clients != null
? PreferredSize(
preferredSize: const Size(double.maxFinite, 50),
child: Container(
height: 50,
width: double.maxFinite,
padding: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: showDivider == true
? Theme.of(context).colorScheme.onSurface.withOpacity(0.1)
: Colors.transparent,
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar.large(
pinned: true,
floating: true,
centerTitle: false,
forceElevated: innerBoxIsScrolled,
title: Text(AppLocalizations.of(context)!.logs),
expandedHeight: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all' || logsProvider.appliedFilters.clients != null
? 170 : null,
actions: [
if (!(Platform.isAndroid || Platform.isIOS)) IconButton(
onPressed: () => logsProvider.fetchLogs(inOffset: 0),
icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.refresh,
),
logsProvider.loadStatus == LoadStatus.loaded
? IconButton(
onPressed: openFilersModal,
icon: const Icon(Icons.filter_list_rounded),
tooltip: AppLocalizations.of(context)!.filters,
)
: const SizedBox(),
if (statusProvider.serverStatus != null) IconButton(
tooltip: AppLocalizations.of(context)!.settings,
onPressed: () => {
if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) {
showDialog(
context: context,
builder: (context) => LogsConfigModal(
onConfirm: updateConfig,
onClear: clearQueries,
dialog: true,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
barrierDismissible: false
)
}
else {
showModalBottomSheet(
context: context,
builder: (context) => LogsConfigModal(
onConfirm: updateConfig,
onClear: clearQueries,
dialog: false,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
backgroundColor: Colors.transparent,
isScrollControlled: true
)
}
},
icon: const Icon(Icons.settings)
),
const SizedBox(width: 5),
],
bottom: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all' || logsProvider.appliedFilters.clients != null
? PreferredSize(
preferredSize: const Size(double.maxFinite, 70),
child: Container(
height: 50,
width: double.maxFinite,
padding: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: showDivider == true
? Theme.of(context).colorScheme.onSurface.withOpacity(0.1)
: Colors.transparent,
)
)
),
child: ListView(
scrollDirection: Axis.horizontal,
children: [
if (logsProvider.appliedFilters.searchText != null) ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.search_rounded,
),
label: Row(
children: [
Text(
logsProvider.appliedFilters.searchText!,
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: null,
clients: logsProvider.appliedFilters.clients
)
);
logsProvider.setSearchText(null);
logsProvider.fetchLogs(
inOffset: 0,
searchText: ''
);
},
),
],
if (logsProvider.appliedFilters.selectedResultStatus != 'all') ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.shield_rounded,
),
label: Row(
children: [
Text(
translatedString[logsProvider.appliedFilters.selectedResultStatus]!,
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: 'all',
searchText: logsProvider.appliedFilters.searchText,
clients: logsProvider.appliedFilters.clients
)
);
logsProvider.setSelectedResultStatus('all');
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: 'all'
);
},
),
],
if (logsProvider.appliedFilters.clients != null) ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.smartphone_rounded,
),
label: Row(
children: [
Text(
logsProvider.appliedFilters.clients!.length == 1
? logsProvider.appliedFilters.clients![0]
: "${logsProvider.appliedFilters.clients!.length} ${AppLocalizations.of(context)!.clients}",
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: logsProvider.appliedFilters.searchText,
clients: null
)
);
logsProvider.setSelectedClients(null);
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: logsProvider.appliedFilters.selectedResultStatus
);
},
),
],
const SizedBox(width: 15),
],
),
)
)
),
child: ListView(
scrollDirection: Axis.horizontal,
children: [
if (logsProvider.appliedFilters.searchText != null) ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.search_rounded,
),
label: Row(
children: [
Text(
logsProvider.appliedFilters.searchText!,
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: null,
clients: logsProvider.appliedFilters.clients
)
);
logsProvider.setSearchText(null);
logsProvider.fetchLogs(
inOffset: 0,
searchText: ''
);
},
),
],
if (logsProvider.appliedFilters.selectedResultStatus != 'all') ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.shield_rounded,
),
label: Row(
children: [
Text(
translatedString[logsProvider.appliedFilters.selectedResultStatus]!,
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: 'all',
searchText: logsProvider.appliedFilters.searchText,
clients: logsProvider.appliedFilters.clients
)
);
logsProvider.setSelectedResultStatus('all');
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: 'all'
);
},
),
],
if (logsProvider.appliedFilters.clients != null) ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.smartphone_rounded,
),
label: Row(
children: [
Text(
logsProvider.appliedFilters.clients!.length == 1
? logsProvider.appliedFilters.clients![0]
: "${logsProvider.appliedFilters.clients!.length} ${AppLocalizations.of(context)!.clients}",
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: logsProvider.appliedFilters.searchText,
clients: null
)
);
logsProvider.setSelectedClients(null);
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: logsProvider.appliedFilters.selectedResultStatus
);
},
),
],
const SizedBox(width: 15),
],
),
)
)
: null,
: null,
),
)
],
body: generateBody()
),
body: generateBody()
);
}

View file

@ -7,6 +7,8 @@ import 'package:provider/provider.dart';
import 'package:store_checker/store_checker.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/general_settings/reorderable_top_items_home.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/widgets/section_label.dart';
@ -159,6 +161,36 @@ class _GeneralSettingsState extends State<GeneralSettings> {
right: 10
)
),
CustomListTile(
icon: Icons.remove_red_eye_rounded,
title: AppLocalizations.of(context)!.hideServerAddress,
subtitle: AppLocalizations.of(context)!.hideServerAddressDescription,
trailing: Switch(
value: appConfigProvider.hideServerAddress,
onChanged: (value) => updateSettings(
newStatus: value,
function: appConfigProvider.setHideServerAddress
),
),
onTap: () => updateSettings(
newStatus: !appConfigProvider.hideServerAddress,
function: appConfigProvider.setHideServerAddress
),
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
left: 16,
right: 10
)
),
CustomListTile(
icon: Icons.reorder_rounded,
title: AppLocalizations.of(context)!.topItemsOrder,
subtitle: AppLocalizations.of(context)!.topItemsOrderDescription,
onTap: () => Navigator.push(context, MaterialPageRoute(
builder: (context) => const ReorderableTopItemsHome()
)),
),
SectionLabel(label: AppLocalizations.of(context)!.logs),
CustomListTile(
icon: Icons.timer_rounded,

View file

@ -0,0 +1,301 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_reorderable_list/flutter_reorderable_list.dart' as reorderable_list_library;
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
class ItemData {
final HomeTopItems title;
final Key key;
const ItemData({
required this.title,
required this.key
});
}
enum DraggingMode {
iOS,
android,
}
class ReorderableTopItemsHome extends StatefulWidget {
const ReorderableTopItemsHome({Key? key}) : super(key: key);
@override
State<ReorderableTopItemsHome> createState() => _ReorderableTopItemsHomeState();
}
class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
List<HomeTopItems> homeTopItemsList = [];
List<HomeTopItems> persistHomeTopItemsList = [];
List<ItemData> renderItems = [];
int _indexOfKey(Key key) {
return renderItems.indexWhere((ItemData d) => d.key == key);
}
bool _reorderCallback(Key item, Key newPosition) {
int draggingIndex = _indexOfKey(item);
int newPositionIndex = _indexOfKey(newPosition);
final draggedItem = renderItems[draggingIndex];
final List<HomeTopItems> reorderedItems = reorderEnumItems(draggingIndex, newPositionIndex);
setState(() {
renderItems.removeAt(draggingIndex);
renderItems.insert(newPositionIndex, draggedItem);
homeTopItemsList = reorderedItems;
});
return true;
}
void _reorderDone(Key item) {
renderItems[_indexOfKey(item)];
setState(() => persistHomeTopItemsList = homeTopItemsList);
}
List<HomeTopItems> reorderEnumItems(int oldIndex, int newIndex) {
final List<HomeTopItems> list = [...homeTopItemsList];
final HomeTopItems item = list.removeAt(oldIndex);
list.insert(newIndex, item);
return list;
}
@override
void initState() {
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
homeTopItemsList = appConfigProvider.homeTopItemsOrder;
persistHomeTopItemsList = appConfigProvider.homeTopItemsOrder;
renderItems = appConfigProvider.homeTopItemsOrder.asMap().entries.map(
(e) => ItemData(
key: ValueKey(e.key),
title: e.value,
)
).toList();
super.initState();
}
@override
Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
Widget tile(HomeTopItems title) {
switch (title) {
case HomeTopItems.queriedDomains:
return CustomListTile(
title: AppLocalizations.of(context)!.topQueriedDomains,
icon: Icons.install_desktop_outlined,
padding: const EdgeInsets.all(16)
);
case HomeTopItems.blockedDomains:
return CustomListTile(
title: AppLocalizations.of(context)!.topBlockedDomains,
icon: Icons.block_rounded,
padding: const EdgeInsets.all(16)
);
case HomeTopItems.recurrentClients:
return CustomListTile(
title: AppLocalizations.of(context)!.topClients,
icon: Icons.smartphone_rounded,
padding: const EdgeInsets.all(16)
);
default:
return const SizedBox();
}
}
Future<bool> onWillPopScope() async {
if (!listEquals(appConfigProvider.homeTopItemsOrder, persistHomeTopItemsList)) {
showDialog(
context: context,
builder: (dialogContext) => AlertDialog(
title: Text(AppLocalizations.of(context)!.discardChanges),
content: Text(AppLocalizations.of(context)!.discardChangesDescription),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(dialogContext);
Navigator.pop(context);
},
child: Text(AppLocalizations.of(context)!.confirm)
),
const SizedBox(width: 8),
TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: Text(AppLocalizations.of(context)!.cancel)
),
],
)
],
)
);
return false;
}
else {
return true;
}
}
void saveSettings() async {
final result = await appConfigProvider.setHomeTopItemsOrder(homeTopItemsList);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsSaved,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved,
color: Colors.red
);
}
}
return WillPopScope(
onWillPop: onWillPopScope,
child: Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.topItemsOrder),
actions: [
IconButton(
onPressed: !listEquals(appConfigProvider.homeTopItemsOrder, persistHomeTopItemsList)
? () => saveSettings()
: null,
icon: const Icon(Icons.save_rounded),
tooltip: AppLocalizations.of(context)!.save,
),
const SizedBox(width: 8)
],
),
body: Column(
children: [
Card(
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(
Icons.info_rounded,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(width: 16),
Flexible(
child: Text(AppLocalizations.of(context)!.topItemsReorderInfo)
)
],
),
),
),
Expanded(
child: reorderable_list_library.ReorderableList(
onReorder: _reorderCallback,
onReorderDone: _reorderDone,
child: ListView.builder(
itemBuilder: (context, index) => reorderable_list_library.ReorderableItem(
key: renderItems[index].key,
childBuilder: (context, state) => Item(
tileWidget: tile(renderItems[index].title),
isFirst: index == 0,
isLast: index == renderItems.length - 1,
state: state
),
),
itemCount: renderItems.length,
)
),
),
],
),
),
);
}
}
class Item extends StatelessWidget {
final Widget tileWidget;
final bool isFirst;
final bool isLast;
final reorderable_list_library.ReorderableItemState state;
const Item({
Key? key,
required this.tileWidget,
required this.isFirst,
required this.isLast,
required this.state,
}) : super(key: key);
@override
Widget build(BuildContext context) {
BoxDecoration decoration;
if (
state == reorderable_list_library.ReorderableItemState.dragProxy ||
state == reorderable_list_library.ReorderableItemState.dragProxyFinished
) {
decoration = BoxDecoration(
color: Theme.of(context).colorScheme.surface.withOpacity(0.7)
);
}
else {
bool placeholder = state == reorderable_list_library.ReorderableItemState.placeholder;
decoration = BoxDecoration(
border: Border(
top: isFirst && !placeholder ? BorderSide(
width: 1,
color: Theme.of(context).colorScheme.primary.withOpacity(0.1)
) : BorderSide.none,
bottom: isLast && placeholder ? BorderSide.none : BorderSide(
width: 1,
color: Theme.of(context).colorScheme.primary.withOpacity(0.1)
),
),
);
}
return reorderable_list_library.DelayedReorderableListener(
child: Container(
decoration: decoration,
child: SafeArea(
top: false,
bottom: false,
child: Opacity(
opacity: state == reorderable_list_library.ReorderableItemState.placeholder ? 0.0 : 1.0,
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: tileWidget
),
],
),
),
)
),
)
);
}
}

View file

@ -17,7 +17,7 @@ import 'package:adguard_home_manager/screens/settings/dns/dns.dart';
import 'package:adguard_home_manager/screens/settings/dns_rewrites/dns_rewrites.dart';
import 'package:adguard_home_manager/screens/servers/servers.dart';
import 'package:adguard_home_manager/screens/settings/advanced_setings.dart';
import 'package:adguard_home_manager/screens/settings/general_settings.dart';
import 'package:adguard_home_manager/screens/settings/general_settings/general_settings.dart';
import 'package:adguard_home_manager/widgets/custom_settings_tile.dart';
import 'package:adguard_home_manager/widgets/section_label.dart';

View file

@ -1,5 +1,7 @@
import 'package:sqflite/sqflite.dart';
import 'package:adguard_home_manager/config/home_top_items_default_order.dart';
Future<Map<String, dynamic>> loadDb(bool acceptsDynamicTheme) async {
List<Map<String, Object?>>? servers;
List<Map<String, Object?>>? appConfig;
@ -102,13 +104,25 @@ Future<Map<String, dynamic>> loadDb(bool acceptsDynamicTheme) async {
}
}
Future upgradeDbToV9(Database db) async {
await db.execute("ALTER TABLE appConfig ADD COLUMN hideServerAddress NUMERIC");
await db.execute("ALTER TABLE appConfig ADD COLUMN homeTopItemsOrder TEXT");
await db.execute("UPDATE appConfig SET hideServerAddress = 0, homeTopItemsOrder = '$homeTopItemsDefaultOrderString'");
await db.transaction((txn) async{
await txn.rawQuery(
'SELECT * FROM appConfig',
);
});
}
Database db = await openDatabase(
'adguard_home_manager.db',
version: 8,
version: 9,
onCreate: (Database db, int version) async {
await db.execute("CREATE TABLE servers (id TEXT PRIMARY KEY, name TEXT, connectionMethod TEXT, domain TEXT, path TEXT, port INTEGER, user TEXT, password TEXT, defaultServer INTEGER, authToken TEXT, runningOnHa INTEGER)");
await db.execute("CREATE TABLE appConfig (theme NUMERIC, overrideSslCheck NUMERIC, hideZeroValues NUMERIC, useDynamicColor NUMERIC, staticColor NUMERIC, useThemeColorForStatus NUMERIC, showTimeLogs NUMERIC, showIpLogs NUMERIC, combinedChart NUMERIC, doNotRememberVersion TEXT)");
await db.execute("INSERT INTO appConfig (theme, overrideSslCheck, hideZeroValues, useDynamicColor, staticColor, useThemeColorForStatus, showTimeLogs, showIpLogs, combinedChart) VALUES (0, 0, 0, ${acceptsDynamicTheme == true ? 1 : 0}, 0, 0, 0, 0, 0)");
await db.execute("CREATE TABLE appConfig (theme NUMERIC, overrideSslCheck NUMERIC, hideZeroValues NUMERIC, useDynamicColor NUMERIC, staticColor NUMERIC, useThemeColorForStatus NUMERIC, showTimeLogs NUMERIC, showIpLogs NUMERIC, combinedChart NUMERIC, doNotRememberVersion TEXT, hideServerAddress NUMERIC, homeTopItemsOrder TEXT)");
await db.execute("INSERT INTO appConfig (theme, overrideSslCheck, hideZeroValues, useDynamicColor, staticColor, useThemeColorForStatus, showTimeLogs, showIpLogs, combinedChart, hideServerAddress, homeTopItemsOrder) VALUES (0, 0, 0, ${acceptsDynamicTheme == true ? 1 : 0}, 0, 0, 0, 0, 0, 0, $homeTopItemsDefaultOrderString)");
},
onUpgrade: (Database db, int oldVersion, int newVersion) async {
if (oldVersion == 1) {
@ -119,6 +133,7 @@ Future<Map<String, dynamic>> loadDb(bool acceptsDynamicTheme) async {
await upgradeDbToV6(db);
await upgradeDbToV7(db);
await upgradeDbToV8(db);
await upgradeDbToV9(db);
}
if (oldVersion == 2) {
await upgradeDbToV3(db);
@ -127,6 +142,7 @@ Future<Map<String, dynamic>> loadDb(bool acceptsDynamicTheme) async {
await upgradeDbToV6(db);
await upgradeDbToV7(db);
await upgradeDbToV8(db);
await upgradeDbToV9(db);
}
if (oldVersion == 3) {
await upgradeDbToV4(db);
@ -134,24 +150,32 @@ Future<Map<String, dynamic>> loadDb(bool acceptsDynamicTheme) async {
await upgradeDbToV6(db);
await upgradeDbToV7(db);
await upgradeDbToV8(db);
await upgradeDbToV9(db);
}
if (oldVersion == 4) {
await upgradeDbToV5(db);
await upgradeDbToV6(db);
await upgradeDbToV7(db);
await upgradeDbToV8(db);
await upgradeDbToV9(db);
}
if (oldVersion == 5) {
await upgradeDbToV6(db);
await upgradeDbToV7(db);
await upgradeDbToV8(db);
await upgradeDbToV9(db);
}
if (oldVersion == 6) {
await upgradeDbToV7(db);
await upgradeDbToV8(db);
await upgradeDbToV9(db);
}
if (oldVersion == 7) {
await upgradeDbToV8(db);
await upgradeDbToV9(db);
}
if (oldVersion == 8) {
await upgradeDbToV9(db);
}
},
onOpen: (Database db) async {

View file

@ -85,6 +85,7 @@ class CustomCombinedLineChart extends StatelessWidget {
lineTouchData: LineTouchData(
enabled: true,
touchTooltipData: LineTouchTooltipData(
fitInsideHorizontally: true,
tooltipBgColor: selectedTheme == ThemeMode.light
? const Color.fromRGBO(220, 220, 220, 0.9)
: const Color.fromRGBO(35, 35, 35, 0.9),

View file

@ -90,6 +90,7 @@ class CustomLineChart extends StatelessWidget {
lineTouchData: LineTouchData(
enabled: true,
touchTooltipData: LineTouchTooltipData(
fitInsideHorizontally: true,
tooltipBgColor: selectedTheme == ThemeMode.light
? const Color.fromRGBO(220, 220, 220, 0.9)
: const Color.fromRGBO(35, 35, 35, 0.9),

View file

@ -19,18 +19,18 @@ PODS:
- sqflite (0.0.2):
- FlutterMacOS
- FMDB (>= 2.7.5)
- sqlite3 (3.41.2):
- sqlite3/common (= 3.41.2)
- sqlite3/common (3.41.2)
- sqlite3/fts5 (3.41.2):
- sqlite3 (3.43.0):
- sqlite3/common (= 3.43.0)
- sqlite3/common (3.43.0)
- sqlite3/fts5 (3.43.0):
- sqlite3/common
- sqlite3/perf-threadsafe (3.41.2):
- sqlite3/perf-threadsafe (3.43.0):
- sqlite3/common
- sqlite3/rtree (3.41.2):
- sqlite3/rtree (3.43.0):
- sqlite3/common
- sqlite3_flutter_libs (0.0.1):
- FlutterMacOS
- sqlite3 (~> 3.41.2)
- sqlite3 (~> 3.43.0)
- sqlite3/fts5
- sqlite3/perf-threadsafe
- sqlite3/rtree
@ -87,9 +87,9 @@ SPEC CHECKSUMS:
sentry_flutter: 8f0ffd53088e6a4d50c095852c5cad9e4405025c
SentryPrivate: 5e3683390f66611fc7c6215e27645873adb55d13
sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
sqlite3: fd89671d969f3e73efe503ce203e28b016b58f68
sqlite3_flutter_libs: 00a50503d69f7ab0fe85a5ff25b33082f4df4ce9
url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451
sqlite3: 7afcf055d3700254769a4dcba56f27d26b5515c9
sqlite3_flutter_libs: 03613b0558ba0bb5544aa3ba3d0862c09c7a19b3
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
window_size: 339dafa0b27a95a62a843042038fa6c3c48de195
PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7

View file

@ -202,7 +202,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View file

@ -13,26 +13,26 @@ packages:
dependency: "direct main"
description:
name: animations
sha256: fe8a6bdca435f718bb1dc8a11661b2c22504c6da40ef934cee8327ed77934164
sha256: ef57563eed3620bd5d75ad96189846aca1e033c0c45fc9a7d26e80ab02b88a70
url: "https://pub.dev"
source: hosted
version: "2.0.7"
version: "2.0.8"
archive:
dependency: transitive
description:
name: archive
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e"
url: "https://pub.dev"
source: hosted
version: "3.3.7"
version: "3.3.8"
args:
dependency: transitive
description:
name: args
sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.4.2"
async:
dependency: "direct main"
description:
@ -85,10 +85,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.17.1"
version: "1.17.2"
contextmenu:
dependency: "direct main"
description:
@ -117,26 +117,26 @@ packages:
dependency: transitive
description:
name: csslib
sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745
sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f"
url: "https://pub.dev"
source: hosted
version: "0.17.2"
version: "0.17.3"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
url: "https://pub.dev"
source: hosted
version: "1.0.5"
version: "1.0.6"
device_info_plus:
dependency: "direct main"
description:
name: device_info_plus
sha256: "499c61743e13909c13374a8c209075385858c614b9c0f2487b5f9995eeaf7369"
sha256: "86add5ef97215562d2e090535b0a16f197902b10c369c558a100e74ea06e8659"
url: "https://pub.dev"
source: hosted
version: "9.0.1"
version: "9.0.3"
device_info_plus_platform_interface:
dependency: transitive
description:
@ -149,10 +149,10 @@ packages:
dependency: "direct main"
description:
name: dynamic_color
sha256: "74dff1435a695887ca64899b8990004f8d1232b0e84bfc4faa1fdda7c6f57cc1"
sha256: de4798a7069121aee12d5895315680258415de9b00e717723a1bd73d58f0126d
url: "https://pub.dev"
source: hosted
version: "1.6.5"
version: "1.6.6"
equatable:
dependency: transitive
description:
@ -181,18 +181,18 @@ packages:
dependency: transitive
description:
name: ffi
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
version: "2.1.0"
file:
dependency: transitive
description:
name: file
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "6.1.4"
version: "7.0.0"
fl_chart:
dependency: "direct main"
description:
@ -218,18 +218,18 @@ packages:
dependency: "direct main"
description:
name: flutter_dotenv
sha256: d9283d92059a22e9834bc0a31336658ffba77089fb6f3cc36751f1fc7c6661a3
sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77"
url: "https://pub.dev"
source: hosted
version: "5.0.2"
version: "5.1.0"
flutter_html:
dependency: "direct main"
description:
name: flutter_html
sha256: "850c07bc6c1ed060d3eb3e88469a598260a13eb45d8978b197c1348e0a2b101f"
sha256: "02ad69e813ecfc0728a455e4bf892b9379983e050722b1dce00192ee2e41d1ee"
url: "https://pub.dev"
source: hosted
version: "3.0.0-beta.1"
version: "3.0.0-beta.2"
flutter_launcher_icons:
dependency: "direct dev"
description:
@ -242,10 +242,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "2.0.3"
flutter_localizations:
dependency: "direct main"
description: flutter
@ -255,18 +255,26 @@ packages:
dependency: "direct main"
description:
name: flutter_markdown
sha256: "7b25c10de1fea883f3c4f9b8389506b54053cd00807beab69fd65c8653a2711f"
sha256: d4a1cb250c4e059586af0235f32e02882860a508e189b61f2b31b8810c1e1330
url: "https://pub.dev"
source: hosted
version: "0.6.14"
version: "0.6.17+2"
flutter_native_splash:
dependency: "direct dev"
description:
name: flutter_native_splash
sha256: "02df24aec455c26428dadc637f20d4c548bda23ee2179479a8e8c39f1ecb75b3"
sha256: ecff62b3b893f2f665de7e4ad3de89f738941fcfcaaba8ee601e749efafa4698
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.3.2"
flutter_reorderable_list:
dependency: "direct main"
description:
name: flutter_reorderable_list
sha256: "0400ef34fa00b7cac69f71efc92d7e49727f425bc1080180ebe70bf47618afe0"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
flutter_split_view:
dependency: "direct main"
description:
@ -306,18 +314,18 @@ packages:
dependency: "direct main"
description:
name: html
sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
url: "https://pub.dev"
source: hosted
version: "0.15.3"
version: "0.15.4"
http:
dependency: transitive
description:
name: http
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev"
source: hosted
version: "0.13.6"
version: "1.1.0"
http_parser:
dependency: transitive
description:
@ -338,10 +346,10 @@ packages:
dependency: "direct main"
description:
name: intl
sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
version: "0.18.0"
version: "0.18.1"
js:
dependency: transitive
description:
@ -362,10 +370,10 @@ packages:
dependency: transitive
description:
name: lints
sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015"
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
list_counter:
dependency: transitive
description:
@ -378,26 +386,26 @@ packages:
dependency: "direct main"
description:
name: markdown
sha256: "8e332924094383133cee218b676871f42db2514f1f6ac617b6cf6152a7faab8e"
sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd
url: "https://pub.dev"
source: hosted
version: "7.1.0"
version: "7.1.1"
matcher:
dependency: transitive
description:
name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.15"
version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.5.0"
meta:
dependency: transitive
description:
@ -418,10 +426,10 @@ packages:
dependency: "direct main"
description:
name: package_info_plus
sha256: "28386bbe89ab5a7919a47cea99cdd1128e5a6e0bbd7eaafe20440ead84a15de3"
sha256: "6ff267fcd9d48cb61c8df74a82680e8b82e940231bb5f68356672fde0397334a"
url: "https://pub.dev"
source: hosted
version: "4.0.1"
version: "4.1.0"
package_info_plus_platform_interface:
dependency: transitive
description:
@ -474,10 +482,10 @@ packages:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.6"
pointycastle:
dependency: transitive
description:
@ -519,50 +527,50 @@ packages:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
sqflite:
dependency: "direct main"
description:
name: sqflite
sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9
sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a"
url: "https://pub.dev"
source: hosted
version: "2.2.8+4"
version: "2.3.0"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: e77abf6ff961d69dfef41daccbb66b51e9983cdd5cb35bf30733598057401555
sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a"
url: "https://pub.dev"
source: hosted
version: "2.4.5"
version: "2.5.0"
sqflite_common_ffi:
dependency: "direct main"
description:
name: sqflite_common_ffi
sha256: f86de82d37403af491b21920a696b19f01465b596f545d1acd4d29a0a72418ad
sha256: "0d5cc1be2eb18400ac6701c31211d44164393aa75886093002ecdd947be04f93"
url: "https://pub.dev"
source: hosted
version: "2.2.5"
version: "2.3.0+2"
sqlite3:
dependency: transitive
description:
name: sqlite3
sha256: "2cef47b59d310e56f8275b13734ee80a9cf4a48a43172020cb55a620121fbf66"
sha256: db65233e6b99e99b2548932f55a987961bc06d82a31a0665451fa0b4fff4c3fb
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "2.1.0"
sqlite3_flutter_libs:
dependency: "direct main"
description:
name: sqlite3_flutter_libs
sha256: "1e20a88d5c7ae8400e009f38ddbe8b001800a6dffa37832481a86a219bc904c7"
sha256: fb115050b0c2589afe2085a62d77f5deda4db65db20a5c65a6e0c92fda89b45e
url: "https://pub.dev"
source: hosted
version: "0.5.15"
version: "0.5.16"
stack_trace:
dependency: transitive
description:
@ -575,10 +583,10 @@ packages:
dependency: "direct main"
description:
name: store_checker
sha256: "9a08c82715fc72b8ef3520b18be98715e95e623ca6dc9693451606c276062b63"
sha256: c9c1a93f11fa756fea23a2a08d7e54e84626a8d3c759cf49fc694a3a5afdc705
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.4.0"
stream_channel:
dependency: transitive
description:
@ -615,10 +623,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
version: "0.6.0"
typed_data:
dependency: transitive
description:
@ -631,74 +639,74 @@ packages:
dependency: transitive
description:
name: universal_io
sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d"
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.2.2"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3
sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27"
url: "https://pub.dev"
source: hosted
version: "6.1.11"
version: "6.1.14"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: "1a5848f598acc5b7d8f7c18b8cb834ab667e59a13edc3c93e9d09cf38cc6bc87"
sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330
url: "https://pub.dev"
source: hosted
version: "6.0.34"
version: "6.1.0"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2"
sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f"
url: "https://pub.dev"
source: hosted
version: "6.1.4"
version: "6.1.5"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5"
sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.6"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e"
sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.7"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370"
sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.5"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa"
sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5"
url: "https://pub.dev"
source: hosted
version: "2.0.16"
version: "2.0.20"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771"
sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
version: "3.0.8"
uuid:
dependency: "direct main"
description:
@ -715,14 +723,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
web:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
win32:
dependency: transitive
description:
name: win32
sha256: "6ca3aaab1790eeb1f5cad232e33d9c53ba66e884dd3e7686c4e730bffc45f1a3"
sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa"
url: "https://pub.dev"
source: hosted
version: "5.0.2"
version: "5.0.7"
win32_registry:
dependency: transitive
description:
@ -757,5 +773,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.0.0 <4.0.0"
flutter: ">=3.4.0-17.0.pre"
dart: ">=3.1.0 <4.0.0"
flutter: ">=3.13.0"

View file

@ -40,7 +40,7 @@ dependencies:
sdk: flutter
intl: any
provider: ^6.0.3
sqflite: ^2.2.5
sqflite: ^2.3.0
package_info_plus: ^4.0.1
flutter_displaymode: ^0.6.0
dynamic_color: ^1.6.5
@ -57,8 +57,8 @@ dependencies:
markdown: ^7.0.2
html: ^0.15.2
flutter_html: ^3.0.0-alpha.6
sqlite3_flutter_libs: ^0.5.13
sqflite_common_ffi: ^2.2.3
sqlite3_flutter_libs: ^0.5.16
sqflite_common_ffi: ^2.3.0+2
window_size:
git:
url: https://github.com/google/flutter-desktop-embedding
@ -72,6 +72,7 @@ dependencies:
async: ^2.10.0
sentry_flutter: ^7.9.0
flutter_dotenv: ^5.0.2
flutter_reorderable_list: ^1.3.1
dev_dependencies:
flutter_test: