diff --git a/LIBCWTCH-GO-MACOS.version b/LIBCWTCH-GO-MACOS.version index 3c6d2eca..dcda997e 100644 --- a/LIBCWTCH-GO-MACOS.version +++ b/LIBCWTCH-GO-MACOS.version @@ -1 +1 @@ -2021-12-08-00-32-v1.5.0-7-g28a13aa \ No newline at end of file +2021-12-11-02-00-v1.5.0-9-gaa102bd \ No newline at end of file diff --git a/LIBCWTCH-GO.version b/LIBCWTCH-GO.version index 33bf0526..8f72ef13 100644 --- a/LIBCWTCH-GO.version +++ b/LIBCWTCH-GO.version @@ -1 +1 @@ -2021-12-08-05-32-v1.5.0-7-g28a13aa \ No newline at end of file +2021-12-11-07-00-v1.5.0-9-gaa102bd \ No newline at end of file diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index d3c01c55..29ec9ce4 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -79,6 +79,12 @@ class CwtchNotifier { server.setRunning(data["Intent"] == "running"); } break; + case "ServerStatsUpdate": + EnvironmentConfig.debugLog("ServerStatsUpdate $data"); + var totalMessages = int.parse(data["TotalMessages"]); + var connections = int.parse(data["Connections"]); + serverListState.updateServerStats(data["Identity"], totalMessages, connections); + break; case "GroupCreated": // Retrieve Server Status from Cache... String status = ""; diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index b3793cca..3c7bdb25 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,33 @@ { "@@locale": "de", - "@@last_modified": "2021-11-11T01:02:08+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", "newMessagesLabel": "New Messages", "localeRU": "Russian", "copyServerKeys": "Copy keys", @@ -8,8 +35,8 @@ "fileCheckingStatus": "Checking download status", "fileInterrupted": "Interrupted", "fileSavedTo": "Saved to", - "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", "encryptedServerDescription": "Encrypting a server with a password protects it from other people who may also use this device. Encrypted servers cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", + "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", "deleteServerConfirmBtn": "Really delete server", "deleteServerSuccess": "Successfully deleted server", "enterCurrentPasswordForDeleteServer": "Please enter current password to delete this server", @@ -32,8 +59,8 @@ "serverAddress": "Server Address", "editServerTitle": "Edit Server", "addServerTitle": "Add Server", + "downloadFileButton": "Herunterladen", "titleManageProfilesShort": "Profiles", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", "settingFileSharing": "File Sharing", "tooltipSendFile": "Send File", @@ -42,25 +69,12 @@ "messageEnableFileSharing": "Enable the file sharing experiment to view this message.", "labelFilesize": "Size", "labelFilename": "Filename", - "downloadFileButton": "Herunterladen", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", - "profileOnionLabel": "Senden Sie diese Adresse an Peers, mit denen Sie sich verbinden möchten", - "addPeerTab": "Einen anderen Nutzer hinzufügen", - "addPeer": "Anderen Nutzer hinzufügen", - "peerNotOnline": "Der andere Nutzer ist offline. Die App kann momentan nicht verwendet werden.", - "peerBlockedMessage": "Anderer Nutzer ist blockiert", - "peerOfflineMessage": "Anderer Nutzer ist offline, Nachrichten können derzeit nicht zugestellt werden", - "blockBtn": "Anderen Nutzer blockieren", - "savePeerHistory": "Peer-Verlauf speichern", - "savePeerHistoryDescription": "Legt fest, ob ein mit dem anderen Nutzer verknüpfter Verlauf gelöscht werden soll oder nicht.", - "dontSavePeerHistory": "Verlauf mit anderem Nutzer löschen", - "unblockBtn": "Anderen Nutzer entsperren", - "blockUnknownLabel": "Unbekannte Peers blockieren", "blockUnknownConnectionsEnabledDescription": "Connections from unknown contacts are blocked. You can change this in Settings", - "networkStatusConnecting": "Verbinde zu Netzwerk und Peers ...", "showMessageButton": "Show Message", "blockedMessageMessage": "This message is from a profile you have blocked.", "placeholderEnterMessage": "Type a message...", @@ -80,17 +94,31 @@ "tooltipReplyToThisMessage": "Reply to this message", "tooltipRejectContactRequest": "Reject this contact request", "tooltipAcceptContactRequest": "Accept this contact request.", + "experimentsEnabled": "Experimente aktiviert", + "malformedMessage": "Fehlerhafte Nachricht", + "contactSuggestion": "Dieser Kontaktvorschlag ist für: ", + "descriptionBlockUnknownConnections": "Falls aktiviert, wird diese Einstellung alle Verbindungen von Cwtch Usern autmoatisch schliessen, wenn sie nicht in deinen Kontakten sind.", + "descriptionExperimentsGroups": "Mit experimentellen Gruppen kann Cwtch über nicht vertrauenswürdige Serverinfrastruktur die Kommunikation mit mehr als einem Kontakt vereinfachen.", + "descriptionExperiments": "Experimentelle Cwtch Features sind optionale, opt-in Features für die andere Privatsphärenaspekte berücksichtigt werden als bei traditionellen 1:1 metadatenresistenten Chats, wie z. B. Gruppennachrichten, Bots usw.", + "networkStatusDisconnected": "Vom Internet getrennt, überprüfe deine Verbindung", + "yourServers": "Deine Server", + "yourProfiles": "Deine Profile", + "enterProfilePassword": "Gib ein Passwort ein, um deine Profile anzuzeigen", + "deleteConfirmLabel": "Gib LÖSCHEN ein um zu bestätigen", + "profileOnionLabel": "Senden Sie diese Adresse an Peers, mit denen Sie sich verbinden möchten", + "cycleColoursAndroid": "Klicken um Farbe zu wechseln.\nGedrückt halten zum zurücksetzen.", + "cycleMorphsDesktop": "Klicken um Morph zu wechseln.\nRechtsklick zum zurücksetzen.", + "cycleMorphsAndroid": "Klicken um Morph zu wechseln.\nGedrückt halten zum zurücksetzen.", + "pasteAddressToAddContact": "Adresse, Einladung oder Schlüssel hier hinzufügen, um einen Kontakt hinzuzufügen", "notificationNewMessageFromGroup": "Neue Nachricht in einer Gruppe!", "notificationNewMessageFromPeer": "Neue Nachricht von einem Kontakt!", "tooltipHidePassword": "Password verstecken", "tooltipShowPassword": "Password anzeigen", - "serverNotSynced": "Neue Nachrichten abrufen (Dies kann eine Weile dauern...)", "groupInviteSettingsWarning": "Du wurdest eingeladen einer Gruppe beizutreten! Bitte aktiviere das Gruppenchat Experiment in den Einstellungen um diese Einladung anzusehen.", "shutdownCwtchAction": "Cwtch schliessen", "shutdownCwtchDialog": "Bist du sicher, dass du Cwtch schliessen möchtest? Alle Verbindungen werden geschlossen und die App wird beendet.", "shutdownCwtchDialogTitle": "Cwtch schliessen?", "shutdownCwtchTooltip": "Cwtch schliessen", - "malformedMessage": "Fehlerhafte Nachricht", "profileDeleteSuccess": "Profil erfolgreich gelöscht", "debugLog": "Konsolendebuglogging aktivivieren", "torNetworkStatus": "Tor Netzwerkstatus", @@ -106,7 +134,6 @@ "torStatus": "Tor Status", "torVersion": "Tor Version", "sendAnInvitation": "Du hast eine Einladung geschickt für: ", - "contactSuggestion": "Dieser Kontaktvorschlag ist für: ", "rejected": "Abgelehnt!", "accepted": "Angenommen!", "chatHistoryDefault": "Diese Unterhaltung wird gelöscht sobald Cwtch geschlossen wird! Der Nachrichtenverlauf für jede Unterhaltung kann im Einstellungsmenü oben rechts geändert werden.", @@ -115,9 +142,6 @@ "reallyLeaveThisGroupPrompt": "Bist du sicher, dass du diese Unterhaltung beenden möchtest? Alle Nachrichten und Attribute werden gelöscht.", "leaveGroup": "Unterhaltung beenden", "inviteToGroup": "Du wurdest eingeladen einer Gruppe beizutreten:", - "pasteAddressToAddContact": "Adresse, Einladung oder Schlüssel hier hinzufügen, um einen Kontakt hinzuzufügen", - "tooltipAddContact": "Neuen Kontakt oder Unterhaltung hinzufügen", - "titleManageContacts": "Unterhaltungen", "titleManageServers": "Server verwalten", "dateNever": "Nie", "dateLastYear": "Letzes Jahr", @@ -125,81 +149,110 @@ "dateLastMonth": "Letzter Monat", "dateRightNow": "Jetzt", "successfullAddedContact": "Erfolgreich hinzugefügt", - "descriptionBlockUnknownConnections": "Falls aktiviert, wird diese Einstellung alle Verbindungen von Cwtch Usern autmoatisch schliessen, wenn sie nicht in deinen Kontakten sind.", - "descriptionExperimentsGroups": "Mit experimentellen Gruppen kann Cwtch über nicht vertrauenswürdige Serverinfrastruktur die Kommunikation mit mehr als einem Kontakt vereinfachen.", - "descriptionExperiments": "Experimentelle Cwtch Features sind optionale, opt-in Features für die andere Privatsphärenaspekte berücksichtigt werden als bei traditionellen 1:1 metadatenresistenten Chats, wie z. B. Gruppennachrichten, Bots usw.", "titleManageProfiles": "Cwtch Profile verwalten", "tooltipUnlockProfiles": "Entsperre verschlüsselte Profile durch Eingabe des Passworts.", + "titleManageContacts": "Unterhaltungen", + "tooltipAddContact": "Neuen Kontakt oder Unterhaltung hinzufügen", "tooltipOpenSettings": "Öfffne das Einstellungsmenü", - "invalidImportString": "Ungültiger Importstring", "contactAlreadyExists": "Kontakt existiert bereits", + "invalidImportString": "Ungültiger Importstring", "conversationSettings": "Unterhaltungseinstellungen", "enterCurrentPasswordForDelete": "Bitte gib das aktuelle Passwort ein, um diese Profil zu löschen.", "enableGroups": "Gruppenchat aktivieren", - "experimentsEnabled": "Experimente aktiviert", "localeIt": "Italiana", "localeEs": "Espanol", - "addListItem": "Liste hinzufügen", - "addNewItem": "Ein neues Element zur Liste hinzufügen", - "todoPlaceholder": "noch zu erledigen", - "newConnectionPaneTitle": "Neue Verbindung", - "networkStatusOnline": "Online", - "networkStatusAttemptingTor": "Versuche, eine Verbindung mit dem Tor-Netzwerk herzustellen", - "networkStatusDisconnected": "Vom Internet getrennt, überprüfe deine Verbindung", - "viewGroupMembershipTooltip": "Gruppenmitgliedschaft anzeigen", - "loadingTor": "Tor wird geladen...", - "smallTextLabel": "Klein", - "defaultScalingText": "defaultmäßige Textgröße (Skalierungsfaktor:", - "builddate": "Aufgebaut auf: %2", - "version": "Version %1", - "versionTor": "Version %1 mit tor %2", - "themeDark": "Dunkel", - "themeLight": "Licht", - "settingTheme": "Thema", - "largeTextLabel": "Groß", - "settingInterfaceZoom": "Zoomstufe", - "localeDe": "Deutsche", "localePt": "Portuguesa", "localeFr": "Frances", "localeEn": "English", - "settingLanguage": "Sprache", - "zoomLabel": "Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)", - "versionBuilddate": "Version: %1 Aufgebaut auf: %2", - "cwtchSettingsTitle": "Cwtch Einstellungen", - "unlock": "Entsperren", - "yourServers": "Deine Server", - "yourProfiles": "Deine Profile", - "error0ProfilesLoadedForPassword": "0 Profile mit diesem Passwort geladen", - "password": "Passwort", - "enterProfilePassword": "Gib ein Passwort ein, um deine Profile anzuzeigen", - "addNewProfileBtn": "Neues Profil hinzufügen", - "deleteConfirmText": "LÖSCHEN", - "deleteProfileConfirmBtn": "Profil wirklich löschen", - "deleteConfirmLabel": "Gib LÖSCHEN ein um zu bestätigen", - "deleteProfileBtn": "Profil löschen", - "passwordChangeError": "Fehler beim Ändern des Passworts: Das Passwort wurde abgelehnt", - "passwordErrorMatch": "Passwörter stimmen nicht überein", - "saveProfileBtn": "Profil speichern", - "createProfileBtn": "Profil speichern", "passwordErrorEmpty": "Passwort darf nicht leer sein", - "password2Label": "Passwort erneut eingeben", - "password1Label": "Passwort", "currentPasswordLabel": "aktuelles Passwort", "yourDisplayName": "Dein Anzeigename", - "noPasswordWarning": "Wenn für dieses Konto kein Passwort verwendet wird, bedeutet dies, dass alle lokal gespeicherten Daten nicht verschlüsselt werden.", - "radioNoPassword": "Unverschlüsselt (kein Passwort)", - "radioUsePassword": "Passwort", - "copiedToClipboardNotification": "in die Zwischenablage kopiert", - "copyBtn": "Kopieren", - "editProfile": "Profil bearbeiten", - "newProfile": "Neues Profil", - "defaultProfileName": "Alice", - "profileName": "Anzeigename", - "editProfileTitle": "Profil bearbeiten", + "unblockBtn": "Anderen Nutzer entsperren", + "dontSavePeerHistory": "Verlauf mit anderem Nutzer löschen", + "savePeerHistoryDescription": "Legt fest, ob ein mit dem anderen Nutzer verknüpfter Verlauf gelöscht werden soll oder nicht.", + "blockBtn": "Anderen Nutzer blockieren", + "displayNameLabel": "Angezeigename", + "peerOfflineMessage": "Anderer Nutzer ist offline, Nachrichten können derzeit nicht zugestellt werden", + "peerBlockedMessage": "Anderer Nutzer ist blockiert", + "dmTooltip": "Klicken, um Direktnachricht zu senden", + "peerNotOnline": "Der andere Nutzer ist offline. Die App kann momentan nicht verwendet werden.", + "searchList": "Liste durchsuchen", + "update": "Update", + "viewServerInfo": "Serverinfo", + "serverNotSynced": "Neue Nachrichten abrufen (Dies kann eine Weile dauern...)", + "serverSynced": "synchronisiert", + "cycleColoursDesktop": "Klicken um Farbe zu wechseln.\nRechtsklick zum zurücksetzen.", + "cycleCatsDesktop": "Klicken um Kategorie zu wechseln.\nRechtslick zum zurücksetzen.", + "cycleCatsAndroid": "Klicken um Kategorie zu wechseln.\nLanger Klick zum zurücksetzen.", + "addPeer": "Anderen Nutzer hinzufügen", + "addPeerTab": "Einen anderen Nutzer hinzufügen", + "todoPlaceholder": "noch zu erledigen", + "addListItem": "Liste hinzufügen", + "addNewItem": "Ein neues Element zur Liste hinzufügen", + "createGroupTab": "Eine Gruppe erstellen", + "joinGroupTab": "Einer Gruppe beitreten", + "peerAddress": "Adresse", + "peerName": "Namen", + "groupName": "Gruppenname", + "server": "Server", + "invitation": "Einladung", + "groupAddr": "Adresse", + "createGroup": "Gruppe erstellen", + "joinGroup": "Gruppe beitreten", + "blocked": "Blockiert", + "search": "Suche...", + "serverInfo": "Server-Informationen", + "serverConnectivityConnected": "Server verbunden", + "serverConnectivityDisconnected": "Server getrennt", + "addListItemBtn": "Element hinzufügen", + "savePeerHistory": "Peer-Verlauf speichern", "addProfileTitle": "Neues Profil hinzufügen", + "editProfileTitle": "Profil bearbeiten", + "profileName": "Anzeigename", + "defaultProfileName": "Alice", + "newProfile": "Neues Profil", + "editProfile": "Profil bearbeiten", + "radioUsePassword": "Passwort", + "radioNoPassword": "Unverschlüsselt (kein Passwort)", + "noPasswordWarning": "Wenn für dieses Konto kein Passwort verwendet wird, bedeutet dies, dass alle lokal gespeicherten Daten nicht verschlüsselt werden.", + "deleteProfileBtn": "Profil löschen", + "deleteConfirmText": "LÖSCHEN", + "deleteProfileConfirmBtn": "Profil wirklich löschen", + "addNewProfileBtn": "Neues Profil hinzufügen", + "networkStatusConnecting": "Verbinde zu Netzwerk und Peers ...", + "newConnectionPaneTitle": "Neue Verbindung", + "password1Label": "Passwort", + "password2Label": "Passwort erneut eingeben", + "createProfileBtn": "Profil speichern", + "saveProfileBtn": "Profil speichern", + "passwordErrorMatch": "Passwörter stimmen nicht überein", + "passwordChangeError": "Fehler beim Ändern des Passworts: Das Passwort wurde abgelehnt", + "password": "Passwort", + "error0ProfilesLoadedForPassword": "0 Profile mit diesem Passwort geladen", + "unlock": "Entsperren", + "versionBuilddate": "Version: %1 Aufgebaut auf: %2", + "blockUnknownLabel": "Unbekannte Peers blockieren", + "settingLanguage": "Sprache", + "localeDe": "Deutsche", + "settingInterfaceZoom": "Zoomstufe", + "settingTheme": "Thema", + "themeLight": "Licht", + "themeDark": "Dunkel", + "versionTor": "Version %1 mit tor %2", + "version": "Version %1", + "builddate": "Aufgebaut auf: %2", + "loadingTor": "Tor wird geladen...", + "viewGroupMembershipTooltip": "Gruppenmitgliedschaft anzeigen", + "networkStatusAttemptingTor": "Versuche, eine Verbindung mit dem Tor-Netzwerk herzustellen", + "networkStatusOnline": "Online", + "smallTextLabel": "Klein", + "defaultScalingText": "defaultmäßige Textgröße (Skalierungsfaktor:", + "largeTextLabel": "Groß", + "zoomLabel": "Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)", + "cwtchSettingsTitle": "Cwtch Einstellungen", + "copiedToClipboardNotification": "in die Zwischenablage kopiert", "deleteBtn": "Löschen", "saveBtn": "Speichern", - "displayNameLabel": "Angezeigename", "addressLabel": "Adresse", "puzzleGameBtn": "Puzzlespiel", "bulletinsBtn": "Meldungen", @@ -210,45 +263,19 @@ "acceptGroupInviteLabel": "Möchtest Du die Einladung annehmen", "newGroupBtn": "Neue Gruppe anlegen", "copiedClipboardNotification": "in die Zwischenablage kopiert", + "copyBtn": "Kopieren", "pendingLabel": "Bestätigung ausstehend", "acknowledgedLabel": "bestätigt", "couldNotSendMsgError": "Nachricht konnte nicht gesendet werden", - "dmTooltip": "Klicken, um Direktnachricht zu senden", "membershipDescription": "Unten steht eine Liste der Benutzer, die Nachrichten an die Gruppe gesendet haben. Möglicherweise enthält diese Benutzerzliste nicht alle, die Zugang zur Gruppe haben.", - "addListItemBtn": "Element hinzufügen", - "searchList": "Liste durchsuchen", - "update": "Update", "inviteBtn": "Einladen", "inviteToGroupLabel": "In die Gruppe einladen", "groupNameLabel": "Gruppenname", - "viewServerInfo": "Serverinfo", - "serverSynced": "synchronisiert", - "serverConnectivityDisconnected": "Server getrennt", - "serverConnectivityConnected": "Server verbunden", - "serverInfo": "Server-Informationen", "invitationLabel": "Einladung", "serverLabel": "Server", - "search": "Suche...", - "cycleColoursDesktop": "Klicken um Farbe zu wechseln.\nRechtsklick zum zurücksetzen.", - "cycleColoursAndroid": "Klicken um Farbe zu wechseln.\nGedrückt halten zum zurücksetzen.", - "cycleMorphsDesktop": "Klicken um Morph zu wechseln.\nRechtsklick zum zurücksetzen.", - "cycleMorphsAndroid": "Klicken um Morph zu wechseln.\nGedrückt halten zum zurücksetzen.", - "cycleCatsDesktop": "Klicken um Kategorie zu wechseln.\nRechtslick zum zurücksetzen.", - "cycleCatsAndroid": "Klicken um Kategorie zu wechseln.\nLanger Klick zum zurücksetzen.", - "blocked": "Blockiert", "titlePlaceholder": "Titel...", "postNewBulletinLabel": "Neue Meldung veröffentlichen", "newBulletinLabel": "Neue Meldung", - "joinGroup": "Gruppe beitreten", - "createGroup": "Gruppe erstellen", - "groupAddr": "Adresse", - "invitation": "Einladung", - "server": "Server", - "groupName": "Gruppenname", - "peerName": "Namen", - "peerAddress": "Adresse", - "joinGroupTab": "Einer Gruppe beitreten", - "createGroupTab": "Eine Gruppe erstellen", "createGroupBtn": "Anlegen", "defaultGroupName": "Tolle Gruppe", "createGroupTitle": "Gruppe Anlegen" diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 70f13992..42b7fca9 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,6 +1,34 @@ { "@@locale": "en", - "@@last_modified": "2021-11-11T01:02:08+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", + "savePeerHistoryDescription": "Determines whether to delete any history associated with the contact.", "newMessagesLabel": "New Messages", "localeRU": "Russian", "copyServerKeys": "Copy keys", @@ -55,7 +83,6 @@ "peerOfflineMessage": "Contact is offline, messages can't be delivered right now", "blockBtn": "Block Contact", "savePeerHistory": "Save History", - "savePeerHistoryDescription": "Determines whether or not to delete any history associated with the contact.", "dontSavePeerHistory": "Delete History", "unblockBtn": "Unblock Contact", "blockUnknownLabel": "Block Unknown Contacts", @@ -190,7 +217,6 @@ "radioNoPassword": "Unencrypted (No password)", "radioUsePassword": "Password", "copiedToClipboardNotification": "Copied to Clipboard", - "copyBtn": "Copy", "editProfile": "Edit Profille", "newProfile": "New Profile", "defaultProfileName": "Alice", @@ -210,6 +236,7 @@ "acceptGroupInviteLabel": "Do you want to accept the invitation to", "newGroupBtn": "Create new group", "copiedClipboardNotification": "Copied to clipboard", + "copyBtn": "Copy", "pendingLabel": "Pending", "acknowledgedLabel": "Acknowledged", "couldNotSendMsgError": "Could not send this message", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index ba0a54bc..809b2d91 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,33 @@ { "@@locale": "es", - "@@last_modified": "2021-11-11T01:02:08+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", "newMessagesLabel": "New Messages", "localeRU": "Russian", "copyServerKeys": "Copy keys", @@ -8,8 +35,8 @@ "fileCheckingStatus": "Checking download status", "fileInterrupted": "Interrupted", "fileSavedTo": "Saved to", - "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", "encryptedServerDescription": "Encrypting a server with a password protects it from other people who may also use this device. Encrypted servers cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", + "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", "deleteServerConfirmBtn": "Really delete server", "deleteServerSuccess": "Successfully deleted server", "enterCurrentPasswordForDeleteServer": "Please enter current password to delete this server", @@ -33,7 +60,6 @@ "editServerTitle": "Edit Server", "addServerTitle": "Add Server", "titleManageProfilesShort": "Profiles", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", "settingFileSharing": "File Sharing", "tooltipSendFile": "Send File", @@ -45,22 +71,10 @@ "downloadFileButton": "Download", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", - "profileOnionLabel": "Envía esta dirección a los contactos con los que quieras conectarte", - "addPeerTab": "Agregar Contacto", - "addPeer": "Agregar Contacto", - "peerNotOnline": "Este contacto no está en línea, la aplicación no puede ser usada en este momento", - "peerBlockedMessage": "Contacto bloqueado", - "peerOfflineMessage": "Este contacto no está en línea, los mensajes no pueden ser entregados en este momento", - "blockBtn": "Bloquear contacto", - "savePeerHistory": "Guardar el historial con contacto", - "savePeerHistoryDescription": "Determina si eliminar o no el historial asociado con el contacto.", - "dontSavePeerHistory": "Eliminar historial de contacto", - "unblockBtn": "Desbloquear contacto", - "blockUnknownLabel": "Bloquear conexiones desconocidas", "blockUnknownConnectionsEnabledDescription": "Connections from unknown contacts are blocked. You can change this in Settings", - "networkStatusConnecting": "Conectando a la red y a los contactos...", "showMessageButton": "Show Message", "blockedMessageMessage": "This message is from a profile you have blocked.", "placeholderEnterMessage": "Type a message...", @@ -84,7 +98,6 @@ "notificationNewMessageFromPeer": "New message from a contact!", "tooltipHidePassword": "Hide Password", "tooltipShowPassword": "Show Password", - "serverNotSynced": "Fuera de sincronización con el servidor", "groupInviteSettingsWarning": "You have been invited to join a group! Please enable the Group Chat Experiment in Settings to view this Invitation.", "shutdownCwtchAction": "Shutdown Cwtch", "shutdownCwtchDialog": "Are you sure you want to shutdown Cwtch? This will close all connections, and exit the application.", @@ -115,9 +128,6 @@ "reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.", "leaveGroup": "Leave This Conversation", "inviteToGroup": "You have been invited to join a group:", - "pasteAddressToAddContact": "...pegar una dirección aquí para añadir contacto...", - "tooltipAddContact": "Add a new contact or conversation", - "titleManageContacts": "Conversations", "titleManageServers": "Manage Servers", "dateNever": "Never", "dateLastYear": "Last Year", @@ -130,126 +140,143 @@ "descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.", "titleManageProfiles": "Manage Cwtch Profiles", "tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.", + "titleManageContacts": "Conversations", + "tooltipAddContact": "Add a new contact or conversation", "tooltipOpenSettings": "Open the settings pane", - "invalidImportString": "Invalid import string", "contactAlreadyExists": "Contact Already Exists", + "invalidImportString": "Invalid import string", "conversationSettings": "Conversation Settings", "enterCurrentPasswordForDelete": "Please enter current password to delete this profile.", "enableGroups": "Enable Group Chat", - "experimentsEnabled": "Experimentos habilitados", - "localeIt": "Italiano", - "localeEs": "Español", - "addListItem": "Añadir un nuevo elemento a la lista", - "addNewItem": "Añadir un nuevo elemento a la lista", - "todoPlaceholder": "Por hacer...", - "newConnectionPaneTitle": "Nueva conexión", - "networkStatusOnline": "En línea", - "networkStatusAttemptingTor": "Intentando conectarse a la red Tor", - "networkStatusDisconnected": "Sin conexión, comprueba tu conexión", - "viewGroupMembershipTooltip": "Ver membresía del grupo", - "loadingTor": "Cargando tor...", - "smallTextLabel": "Pequeño", "defaultScalingText": "Tamaño predeterminado de texto (factor de escala:", - "builddate": "Basado en: %2", - "version": "Versión %1", - "versionTor": "Versión %1 con tor %2", + "todoPlaceholder": "Por hacer...", + "bulletinsBtn": "Boletines", + "radioNoPassword": "Sin cifrado (sin contraseña)", "themeDark": "Oscuro", - "themeLight": "Claro", - "settingTheme": "Tema", - "largeTextLabel": "Grande", - "settingInterfaceZoom": "Nivel de zoom", + "smallTextLabel": "Pequeño", + "loadingTor": "Cargando tor...", + "cycleCatsAndroid": "Click para cambiar categoría. Mantenga pulsado para reiniciar.", + "cycleCatsDesktop": "Click para cambiar categoría. Click derecho para reiniciar.", + "cycleColoursDesktop": "Click para cambiar colores. Click derecho para reiniciar.", + "cycleColoursAndroid": "Click para cambiar colores. Mantenga pulsado para reiniciar.", + "builddate": "Basado en: %2", + "cycleMorphsAndroid": "Click para cambiar transformaciones. Mantenga pulsado para reiniciar.", + "cycleMorphsDesktop": "Click para cambiar transformaciones. Click derecho para reiniciar.", "localeDe": "Alemán", "localePt": "Portugués", "localeFr": "Francés", - "localeEn": "Inglés", - "settingLanguage": "Idioma", - "zoomLabel": "Zoom de la interfaz (afecta principalmente el tamaño del texto y de los botones)", - "versionBuilddate": "Versión: %1 Basado en %2", - "cwtchSettingsTitle": "Configuración de Cwtch", - "unlock": "Desbloquear", - "yourServers": "Tus servidores", - "yourProfiles": "Tus perfiles", - "error0ProfilesLoadedForPassword": "0 perfiles cargados con esa contraseña", - "password": "Contraseña", - "enterProfilePassword": "Ingresa tu contraseña para ver tus perfiles", - "addNewProfileBtn": "Agregar nuevo perfil", - "deleteConfirmText": "ELIMINAR", - "deleteProfileConfirmBtn": "Confirmar eliminar perfil", - "deleteConfirmLabel": "Escribe ELIMINAR para confirmar", - "deleteProfileBtn": "Eliminar Perfil", - "passwordChangeError": "Hubo un error cambiando tu contraseña: la contraseña ingresada fue rechazada", - "passwordErrorMatch": "Las contraseñas no coinciden", - "saveProfileBtn": "Guardar perfil", - "createProfileBtn": "Crear perfil", - "passwordErrorEmpty": "El campo de contraseña no puede estar vacío", - "password2Label": "Vuelve a ingresar tu contraseña", - "password1Label": "Contraseña", - "currentPasswordLabel": "Contraseña actual", - "yourDisplayName": "Tu nombre de usuario", - "noPasswordWarning": "No usar una contraseña para esta cuenta significa que los datos almacenados localmente no serán encriptados", - "radioNoPassword": "Sin cifrado (sin contraseña)", - "radioUsePassword": "Contraseña", - "copiedToClipboardNotification": "Copiado al portapapeles", - "copyBtn": "Copiar", - "editProfile": "Editar perfil", - "newProfile": "Nuevo perfil", - "defaultProfileName": "Alicia", - "profileName": "Nombre de Usuario", - "editProfileTitle": "Editar perfil", - "addProfileTitle": "Agregar nuevo perfil", - "deleteBtn": "Eliminar", - "saveBtn": "Guardar", - "displayNameLabel": "Nombre de Usuario", - "addressLabel": "Dirección", - "puzzleGameBtn": "Juego de rompecabezas", - "bulletinsBtn": "Boletines", - "listsBtn": "Listas", - "chatBtn": "Chat", - "rejectGroupBtn": "Rechazar", - "acceptGroupBtn": "Aceptar", - "acceptGroupInviteLabel": "¿Quieres aceptar la invitación a ", - "newGroupBtn": "Crear un nuevo grupo de chat", - "copiedClipboardNotification": "Copiado al portapapeles", - "pendingLabel": "Pendiente", - "acknowledgedLabel": "Reconocido", - "couldNotSendMsgError": "No se pudo enviar este mensaje", - "dmTooltip": "Haz clic para enviar mensaje directo", - "membershipDescription": "La lista a continuación solo muestra los miembros que han enviado mensajes al grupo, no incluye a todos los usuarios dentro del grupo", - "addListItemBtn": "Agregar artículo", - "searchList": "Buscar en la lista", - "update": "Actualizar", - "inviteBtn": "Invitar", - "inviteToGroupLabel": "Invitar al grupo", - "groupNameLabel": "Nombre del grupo", - "viewServerInfo": "Información del servidor", - "serverSynced": "Sincronizado", - "serverConnectivityDisconnected": "Servidor desconectado", - "serverConnectivityConnected": "Servidor conectado", - "serverInfo": "Información del servidor", - "invitationLabel": "Invitación", - "serverLabel": "Servidor", - "search": "Búsqueda...", - "cycleColoursDesktop": "Click para cambiar colores. Click derecho para reiniciar.", - "cycleColoursAndroid": "Click para cambiar colores. Mantenga pulsado para reiniciar.", - "cycleMorphsDesktop": "Click para cambiar transformaciones. Click derecho para reiniciar.", - "cycleMorphsAndroid": "Click para cambiar transformaciones. Mantenga pulsado para reiniciar.", - "cycleCatsDesktop": "Click para cambiar categoría. Click derecho para reiniciar.", - "cycleCatsAndroid": "Click para cambiar categoría. Mantenga pulsado para reiniciar.", - "blocked": "Bloqueado", - "titlePlaceholder": "título...", - "postNewBulletinLabel": "Publicar nuevo boletín", - "newBulletinLabel": "Nuevo Boletín", - "joinGroup": "Únete al grupo", - "createGroup": "Crear perfil", - "groupAddr": "Dirección", - "invitation": "Invitación", - "server": "Servidor", - "groupName": "Nombre del grupo", - "peerName": "Nombre", - "peerAddress": "Dirección", + "addListItem": "Añadir un nuevo elemento a la lista", + "unblockBtn": "Desbloquear contacto", "joinGroupTab": "Únete a un grupo", - "createGroupTab": "Crear un grupo", - "createGroupBtn": "Crear", + "viewGroupMembershipTooltip": "Ver membresía del grupo", + "peerBlockedMessage": "Contacto bloqueado", + "peerOfflineMessage": "Este contacto no está en línea, los mensajes no pueden ser entregados en este momento", + "profileOnionLabel": "Envía esta dirección a los contactos con los que quieras conectarte", + "couldNotSendMsgError": "No se pudo enviar este mensaje", + "pendingLabel": "Pendiente", + "chatBtn": "Chat", + "dontSavePeerHistory": "Eliminar historial de contacto", + "password": "Contraseña", + "peerNotOnline": "Este contacto no está en línea, la aplicación no puede ser usada en este momento", + "enterProfilePassword": "Ingresa tu contraseña para ver tus perfiles", + "networkStatusConnecting": "Conectando a la red y a los contactos...", + "localeIt": "Italiano", + "savePeerHistoryDescription": "Determina si eliminar o no el historial asociado con el contacto.", + "acknowledgedLabel": "Reconocido", + "blockBtn": "Bloquear contacto", + "savePeerHistory": "Guardar el historial con contacto", + "defaultProfileName": "Alicia", + "versionBuilddate": "Versión: %1 Basado en %2", + "zoomLabel": "Zoom de la interfaz (afecta principalmente el tamaño del texto y de los botones)", + "settingTheme": "Tema", + "themeLight": "Claro", + "experimentsEnabled": "Experimentos habilitados", + "versionTor": "Versión %1 con tor %2", + "localeEs": "Español", + "networkStatusOnline": "En línea", + "newConnectionPaneTitle": "Nueva conexión", + "addNewItem": "Añadir un nuevo elemento a la lista", + "createGroupTitle": "Crear un grupo", + "serverLabel": "Servidor", + "groupNameLabel": "Nombre del grupo", "defaultGroupName": "El Grupo Asombroso", - "createGroupTitle": "Crear un grupo" + "createGroupBtn": "Crear", + "copiedToClipboardNotification": "Copiado al portapapeles", + "addPeerTab": "Agregar Contacto", + "createGroupTab": "Crear un grupo", + "peerAddress": "Dirección", + "peerName": "Nombre", + "groupName": "Nombre del grupo", + "server": "Servidor", + "invitation": "Invitación", + "groupAddr": "Dirección", + "addPeer": "Agregar Contacto", + "createGroup": "Crear perfil", + "joinGroup": "Únete al grupo", + "newBulletinLabel": "Nuevo Boletín", + "postNewBulletinLabel": "Publicar nuevo boletín", + "titlePlaceholder": "título...", + "pasteAddressToAddContact": "...pegar una dirección aquí para añadir contacto...", + "blocked": "Bloqueado", + "search": "Búsqueda...", + "invitationLabel": "Invitación", + "serverInfo": "Información del servidor", + "serverConnectivityConnected": "Servidor conectado", + "serverConnectivityDisconnected": "Servidor desconectado", + "serverSynced": "Sincronizado", + "serverNotSynced": "Fuera de sincronización con el servidor", + "viewServerInfo": "Información del servidor", + "saveBtn": "Guardar", + "inviteToGroupLabel": "Invitar al grupo", + "inviteBtn": "Invitar", + "deleteBtn": "Eliminar", + "update": "Actualizar", + "searchList": "Buscar en la lista", + "addListItemBtn": "Agregar artículo", + "membershipDescription": "La lista a continuación solo muestra los miembros que han enviado mensajes al grupo, no incluye a todos los usuarios dentro del grupo", + "dmTooltip": "Haz clic para enviar mensaje directo", + "copyBtn": "Copiar", + "copiedClipboardNotification": "Copiado al portapapeles", + "newGroupBtn": "Crear un nuevo grupo de chat", + "acceptGroupInviteLabel": "¿Quieres aceptar la invitación a ", + "acceptGroupBtn": "Aceptar", + "rejectGroupBtn": "Rechazar", + "listsBtn": "Listas", + "puzzleGameBtn": "Juego de rompecabezas", + "addressLabel": "Dirección", + "displayNameLabel": "Nombre de Usuario", + "addProfileTitle": "Agregar nuevo perfil", + "editProfileTitle": "Editar perfil", + "profileName": "Nombre de Usuario", + "newProfile": "Nuevo perfil", + "editProfile": "Editar perfil", + "radioUsePassword": "Contraseña", + "noPasswordWarning": "No usar una contraseña para esta cuenta significa que los datos almacenados localmente no serán encriptados", + "password2Label": "Vuelve a ingresar tu contraseña", + "yourDisplayName": "Tu nombre de usuario", + "currentPasswordLabel": "Contraseña actual", + "password1Label": "Contraseña", + "passwordErrorEmpty": "El campo de contraseña no puede estar vacío", + "createProfileBtn": "Crear perfil", + "saveProfileBtn": "Guardar perfil", + "passwordErrorMatch": "Las contraseñas no coinciden", + "passwordChangeError": "Hubo un error cambiando tu contraseña: la contraseña ingresada fue rechazada", + "deleteProfileBtn": "Eliminar Perfil", + "deleteConfirmLabel": "Escribe ELIMINAR para confirmar", + "deleteProfileConfirmBtn": "Confirmar eliminar perfil", + "deleteConfirmText": "ELIMINAR", + "addNewProfileBtn": "Agregar nuevo perfil", + "error0ProfilesLoadedForPassword": "0 perfiles cargados con esa contraseña", + "yourProfiles": "Tus perfiles", + "yourServers": "Tus servidores", + "unlock": "Desbloquear", + "cwtchSettingsTitle": "Configuración de Cwtch", + "blockUnknownLabel": "Bloquear conexiones desconocidas", + "settingLanguage": "Idioma", + "localeEn": "Inglés", + "settingInterfaceZoom": "Nivel de zoom", + "largeTextLabel": "Grande", + "version": "Versión %1", + "networkStatusDisconnected": "Sin conexión, comprueba tu conexión", + "networkStatusAttemptingTor": "Intentando conectarse a la red Tor" } \ No newline at end of file diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index bb6e8810..8140da2c 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,74 +1,101 @@ { "@@locale": "fr", - "@@last_modified": "2021-11-11T01:02:08+01:00", - "newMessagesLabel": "New Messages", - "localeRU": "Russian", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverMetricsLabel": "Métriques du serveur", + "serverTotalMessagesLabel": "Nombre total de messages", + "serverConnectionsLabel": "Connexion", + "manageKnownServersShort": "Serveurs", + "manageKnownServersLong": "Gérer les serveurs connus", + "manageKnownServersButton": "Gérer les serveurs connus", + "importLocalServerSelectText": "Sélectionnez le serveur local", + "importLocalServerLabel": "Importer un serveur hébergé localement", + "importLocalServerButton": "Importer %1", + "groupsOnThisServerLabel": "Les groupes dont je fais partie sont hébergés sur ce serveur", + "fieldDescriptionLabel": "Description", + "displayNameTooltip": "Veuillez entrer un nom d'usage s'il vous plaît", + "savePeerHistoryDescription": "Détermine s'il faut ou non supprimer tout historique associé au contact.", + "newMessagesLabel": "Nouveaux messages", + "localeRU": "Russe", "copyServerKeys": "Copier les clés", "verfiyResumeButton": "Vérifier\/reprendre", - "fileCheckingStatus": "Vérification de l'état du téléchargement", - "fileInterrupted": "Interrompu", "fileSavedTo": "Enregistré dans", + "fileInterrupted": "Interrompu", + "fileCheckingStatus": "Vérification de l'état du téléchargement", "plainServerDescription": "Nous vous recommandons de protéger vos serveurs Cwtch par un mot de passe. Si vous ne définissez pas de mot de passe sur ce serveur, toute personne ayant accès à cet appareil peut être en mesure d'accéder aux informations concernant ce serveur, y compris les clés cryptographiques sensibles.", - "encryptedServerDescription": "Le chiffrement d’un serveur avec un mot de passe le protège des autres personnes qui peuvent également utiliser cet appareil. Les serveurs cryptés ne peuvent pas être déchiffrés, affichés ou accessibles tant que le mot de passe correct n’est pas entré pour les déverrouiller.", - "deleteServerConfirmBtn": "Supprimer vraiment le serveur", - "deleteServerSuccess": "Le serveur a été supprimé avec succès", "enterCurrentPasswordForDeleteServer": "Veuillez saisir le mot de passe actuel pour supprimer ce serveur", - "copyAddress": "Copier l'adresse", + "encryptedServerDescription": "Le chiffrement d’un serveur avec un mot de passe le protège des autres personnes qui peuvent également utiliser cet appareil. Les serveurs cryptés ne peuvent pas être déchiffrés, affichés ou accessibles tant que le mot de passe correct n’est pas entré pour les déverrouiller.", + "deleteServerSuccess": "Le serveur a été supprimé avec succès", + "deleteServerConfirmBtn": "Supprimer vraiment le serveur", + "unlockServerTip": "Veuillez créer ou déverrouiller un serveur pour commencer !", + "unlockProfileTip": "Veuillez créer ou déverrouiller un profil pour commencer !", "settingServersDescription": "L'expérience des serveurs d'hébergement permet d'héberger et de gérer les serveurs Cwtch.", "settingServers": "Serveurs d'hébergement", - "enterServerPassword": "Entrez le mot de passe pour déverrouiller le serveur", - "unlockProfileTip": "Veuillez créer ou déverrouiller un profil pour commencer !", - "unlockServerTip": "Veuillez créer ou déverrouiller un serveur pour commencer !", - "addServerTooltip": "Ajouter un nouveau serveur", "serversManagerTitleShort": "Serveurs", "serversManagerTitleLong": "Serveurs que vous hébergez", - "saveServerButton": "Enregistrer le serveur", - "serverAutostartDescription": "Contrôle si l'application lance automatiquement le serveur au démarrage.", - "serverAutostartLabel": "Démarrage automatique", "serverEnabledDescription": "Démarrer ou arrêter le serveur", "serverEnabled": "Serveur activé", - "serverDescriptionDescription": "Votre description du serveur est à des fins de gestion personnelle uniquement, elle ne sera jamais partagée.", "serverDescriptionLabel": "Description du serveur", + "serverDescriptionDescription": "Votre description du serveur est à des fins de gestion personnelle uniquement, elle ne sera jamais partagée.", + "serverAutostartLabel": "Démarrage automatique", + "serverAutostartDescription": "Contrôle si l'application lance automatiquement le serveur au démarrage.", "serverAddress": "Adresse du serveur", + "saveServerButton": "Enregistrer le serveur", + "enterServerPassword": "Entrez le mot de passe pour déverrouiller le serveur", "editServerTitle": "Modifier le serveur", + "copyAddress": "Copier l'adresse", + "addServerTooltip": "Ajouter un nouveau serveur", "addServerTitle": "Ajouter un serveur", "titleManageProfilesShort": "Profils", "descriptionStreamerMode": "Si elle est activée, cette option donne un rendu visuel plus privé à l'application pour la diffusion en direct ou la présentation, par exemple, en masquant profil et adresses de contacts.", - "descriptionFileSharing": "L'expérience de partage de fichiers vous permet d'envoyer et de recevoir des fichiers à partir de contacts et de groupes Cwtch. Notez que si vous partagez un fichier avec un groupe, les membres de ce groupe se connecteront avec vous directement via Cwtch pour le télécharger.", - "settingFileSharing": "Partage de fichiers", "tooltipSendFile": "Envoyer le fichier", - "messageFileOffered": "Contact vous propose de vous envoyer un fichier", + "settingFileSharing": "Partage de fichiers", + "retrievingManifestMessage": "Récupération des informations sur le fichier...", + "openFolderButton": "Ouvrir le dossier", "messageFileSent": "Vous avez envoyé un fichier", + "messageFileOffered": "Contact vous propose de vous envoyer un fichier", "messageEnableFileSharing": "Activez l'expérience de partage de fichiers pour afficher ce message.", "labelFilesize": "Taille", "labelFilename": "Nom de fichier", "downloadFileButton": "Télécharger", - "openFolderButton": "Ouvrir le dossier", - "retrievingManifestMessage": "Récupération des informations sur le fichier...", + "descriptionFileSharing": "L'expérience de partage de fichiers vous permet d'envoyer et de recevoir des fichiers à partir de contacts et de groupes Cwtch. Notez que si vous partagez un fichier avec un groupe, les membres de ce groupe se connecteront avec vous directement via Cwtch pour le télécharger.", "streamerModeLabel": "Mode Streamer\/Présentation", - "archiveConversation": "Archiver cette conversation", + "addPeer": "Ajouter le contact", + "networkStatusConnecting": "Connexion au réseau et aux contacts...", "profileOnionLabel": "Envoyez cette adresse aux personnes avec lesquelles vous souhaitez entrer en contact.", "addPeerTab": "Ajouter un contact", - "addPeer": "Ajouter le contact", "peerNotOnline": "Le contact est hors ligne. Les applications ne peuvent pas être utilisées pour le moment.", "peerBlockedMessage": "Le contact est bloqué", "peerOfflineMessage": "Le contact est hors ligne, les messages ne peuvent pas être transmis pour le moment.", "blockBtn": "Bloquer le contact", "savePeerHistory": "Enregistrer l'historique", - "savePeerHistoryDescription": "Détermine s'il faut ou non supprimer tout historique associé au contact.", "dontSavePeerHistory": "Supprimer l'historique", "unblockBtn": "Débloquer le contact", "blockUnknownLabel": "Bloquer les pairs inconnus", "blockUnknownConnectionsEnabledDescription": "Les connexions provenant de contacts inconnus sont bloquées. Vous pouvez modifier cela dans les paramètres", - "networkStatusConnecting": "Connexion au réseau et aux contacts...", - "showMessageButton": "Afficher le message", + "archiveConversation": "Archiver cette conversation", "blockedMessageMessage": "Ce message provient d'un profil que vous avez bloqué.", + "showMessageButton": "Afficher le message", "placeholderEnterMessage": "saisissez un message", - "plainProfileDescription": "Nous vous recommandons de protéger vos profils Cwtch par un mot de passe. Si vous ne définissez pas de mot de passe sur ce profil, toute personne ayant accès à cet appareil peut être en mesure d'accéder aux informations relatives à ce profil, y compris les contacts, les messages et les clés de chiffrement sensibles.", "encryptedProfileDescription": "Le chiffrement d'un profil à l'aide d'un mot de passe le protège des autres personnes susceptibles d'utiliser également cet appareil. Les profils chiffrés ne peuvent pas être déchiffrés , affichés ou accessibles tant que le mot de passe correct n'a pas été saisi pour les déverrouiller.", + "plainProfileDescription": "Nous vous recommandons de protéger vos profils Cwtch par un mot de passe. Si vous ne définissez pas de mot de passe sur ce profil, toute personne ayant accès à cet appareil peut être en mesure d'accéder aux informations relatives à ce profil, y compris les contacts, les messages et les clés de chiffrement sensibles.", "addContactConfirm": "Ajouter le contact %1", - "addContact": "Ajouter le contact", "contactGoto": "Aller à la conversation avec %1", + "addContact": "Ajouter le contact", "settingUIColumnOptionSame": "Même réglage que pour le mode portrait", "settingUIColumnDouble14Ratio": "Double (1:4)", "settingUIColumnDouble12Ratio": "Double (1:2)", @@ -76,128 +103,158 @@ "settingUIColumnLandscape": "Colonnes de l'interface utilisateur en mode paysage", "settingUIColumnPortrait": "Colonnes de l'interface utilisateur en mode portrait", "localePl": "Polonais", - "tooltipRemoveThisQuotedMessage": "Supprimer le message cité.", "tooltipReplyToThisMessage": "Répondre à ce message", - "tooltipRejectContactRequest": "Refuser cette demande de contact", - "tooltipAcceptContactRequest": "Acceptez cette demande de contact.", - "notificationNewMessageFromGroup": "Nouveau message dans un groupe !", - "notificationNewMessageFromPeer": "Nouveau message d'un contact !", - "tooltipHidePassword": "Masquer le mot de passe", - "tooltipShowPassword": "Afficher le mot de passe", - "serverNotSynced": "Synchronisation des nouveaux messages (Cela peut prendre un certain temps)...", - "groupInviteSettingsWarning": "Vous avez été invité à rejoindre un groupe ! Veuillez activer l'expérience de discussion de groupe dans les paramètres pour afficher cette invitation.", - "shutdownCwtchAction": "Arrêt de Cwtch", - "shutdownCwtchDialog": "Êtes-vous sûr de vouloir arrêter Cwtch ? Ceci fermera toutes les connexions, et quittera l'application.", - "shutdownCwtchDialogTitle": "Arrêter Cwtch ?", + "tooltipRemoveThisQuotedMessage": "Supprimer le message cité.", + "deleteProfileConfirmBtn": "Supprimer vraiment le profil ?", + "groupNameLabel": "Nom du groupe", + "defaultGroupName": "Un groupe génial", + "inviteToGroupLabel": "Inviter au groupe", + "membershipDescription": "Liste des utilisateurs ayant envoyés un ou plusieurs messages au groupe. Cette liste peut ne pas être représentatives de l'ensemble des membres du groupe.", "shutdownCwtchTooltip": "Arrêt de Cwtch", - "malformedMessage": "Message mal formé", - "profileDeleteSuccess": "Le profil a été supprimé avec succès", - "debugLog": "Activer le journal de la console de débogage", - "torNetworkStatus": "Statut du réseau Tor", - "addContactFirst": "Ajoutez ou choisissez un contact pour commencer à discuter.", - "createProfileToBegin": "Veuillez créer ou déverrouiller un profil pour commencer", - "nickChangeSuccess": "Le pseudo du profil a été modifié avec succès", - "addServerFirst": "Vous devez ajouter un serveur avant de pouvoir créer un groupe.", - "deleteProfileSuccess": "Le profil a été supprimé avec succès", - "sendInvite": "Envoyer une invitation à un contact ou à un groupe", - "sendMessage": "Envoyer un message", - "cancel": "Annuler", - "resetTor": "Réinitialiser", - "torStatus": "Statut de Tor", - "torVersion": "Version de Tor", - "sendAnInvitation": "Vous avez envoyé une invitation pour : ", - "contactSuggestion": "Il s'agit d'une suggestion de contact pour : ", - "rejected": "Rejeté !", - "accepted": "Accepté !", - "chatHistoryDefault": "Cette conversation sera supprimée lorsque Cwtch sera fermé ! L'historique des messages peut être activé pour la conversation via le menu Paramètres en haut à droite.", - "newPassword": "Nouveau mot de passe", - "yesLeave": "Oui, quittez cette conversation", - "reallyLeaveThisGroupPrompt": "Êtes-vous sûr de vouloir quitter cette conversation ? Tous les messages et attributs seront supprimés.", - "leaveGroup": "Quittez cette conversation", - "inviteToGroup": "Vous avez été invité à rejoindre un groupe :", + "shutdownCwtchAction": "Arrêt de Cwtch", + "deleteBtn": "Effacer", + "acknowledgedLabel": "Accusé de réception", + "zoomLabel": "Zoom de l'interface (affecte principalement la taille du texte et des boutons)", + "localeIt": "Italien", + "versionTor": "Version %1 avec tor %2", + "version": "Version %1", + "builddate": "Construit le : %2", + "versionBuilddate": "Version : %1 Construite le : %2", + "tooltipAcceptContactRequest": "Acceptez cette demande de contact.", + "tooltipRejectContactRequest": "Refuser cette demande de contact", + "addNewItem": "Ajouter un nouvel élément à la liste", + "localeEs": "Espagnol", + "todoPlaceholder": "À faire...", "pasteAddressToAddContact": "Collez une adresse cwtch, une invitation ou un ensemble de clés ici pour ajouter une nouvelle conversation", - "tooltipAddContact": "Ajouter un nouveau contact ou une nouvelle conversation", - "titleManageContacts": "Conversations", - "titleManageServers": "Gérer les serveurs", - "dateNever": "Jamais", + "addListItem": "Ajouter un nouvel élément de liste", + "cycleMorphsAndroid": "Cliquez pour faire défiler les morphes.\n Appuyez longuement pour réinitialiser.", + "cycleMorphsDesktop": "Cliquez pour faire défiler les morphes.\n Faites un clic droit pour réinitialiser.", + "debugLog": "Activer le journal de la console de débogage", + "joinGroupTab": "Rejoindre un groupe", + "createGroupTab": "Créer un groupe", + "peerAddress": "Adresse", + "peerName": "Nom", + "groupName": "Nom du groupe", + "server": "Serveur", + "invitation": "Invitation", + "cycleCatsAndroid": "Cliquez pour faire défiler les catégories.\nAppuyez longuement pour réinitialiser.", + "cycleCatsDesktop": "Cliquez pour parcourir la catégorie.\n Faites un clic droit pour réinitialiser.", + "cycleColoursAndroid": "Cliquez pour faire défiler les couleurs.\nAppuyez longuement pour réinitialiser.", + "groupAddr": "Adresse", + "createGroup": "Créer un groupe", + "joinGroup": "Rejoindre le groupe", + "blocked": "Bloqué", + "cycleColoursDesktop": "Cliquez pour faire défiler les couleurs.\nCliquez avec le bouton droit de la souris pour réinitialiser.", + "search": "Recherche...", + "serverInfo": "Informations sur le serveur", + "serverConnectivityConnected": "Serveur connecté", + "serverConnectivityDisconnected": "Serveur déconnecté", + "serverSynced": "Synchronisé", + "serverNotSynced": "Synchronisation des nouveaux messages (Cela peut prendre un certain temps)...", + "viewServerInfo": "Informations sur le serveur", + "update": "Mise à jour", + "searchList": "Liste de recherche", + "addListItemBtn": "Ajouter un élément", + "addProfileTitle": "Ajouter un nouveau profil", + "editProfileTitle": "Modifier le profil", + "profileName": "Pseudo", + "defaultProfileName": "Alice", + "newProfile": "Nouveau profil", + "deleteConfirmText": "SUPPRIMER", + "deleteConfirmLabel": "Tapez SUPPRIMER pour confirmer", + "addNewProfileBtn": "Ajouter un nouveau profil", + "enterProfilePassword": "Entrez un mot de passe pour consulter vos profils", + "editProfile": "Modifier le profil", + "radioUsePassword": "Mot de passe", + "radioNoPassword": "Non chiffré (pas de mot de passe)", + "saveProfileBtn": "Sauvegarder le profil", + "passwordErrorMatch": "Les mots de passe ne correspondent pas", + "passwordChangeError": "Erreur lors de la modification du mot de passe : le mot de passe fourni est rejeté", + "deleteProfileBtn": "Supprimer le profil", + "password": "Mot de passe", + "error0ProfilesLoadedForPassword": "Aucun profils chargés avec ce mot de passe", + "yourProfiles": "Vos profils", + "yourServers": "Vos serveurs", + "unlock": "Déverrouiller", + "settingLanguage": "Langue", + "localeEn": "Anglais", + "localeFr": "Français", + "localePt": "Portugais", + "localeDe": "Allemand", + "settingInterfaceZoom": "Niveau de zoom", + "settingTheme": "Thème", + "themeLight": "Clair", + "themeDark": "Sombre", + "experimentsEnabled": "Activer les expériences", "dateLastYear": "L'année dernière", - "dateYesterday": "Hier", - "dateLastMonth": "Le mois dernier", - "dateRightNow": "Maintenant", - "successfullAddedContact": "Ajouté avec succès ", - "descriptionBlockUnknownConnections": "Si elle est activée, cette option fermera automatiquement les connexions des utilisateurs de Cwtch qui n'ont pas été ajoutés à votre liste de contacts.", - "descriptionExperimentsGroups": "L'expérience de groupe permet à Cwtch de se connecter à une infrastructure de serveurs non fiables pour faciliter la communication avec plus d'un contact.", - "descriptionExperiments": "Les expériences de Cwtch sont des fonctionnalités optionnelles et facultatives qui ajoutent des fonctionnalités supplémentaires à Cwtch et qui peuvent avoir des considérations de confidentialité différentes de celles du chat traditionnel résistant aux métadonnées 1:1, par exemple le chat de groupe, l'intégration de robots, etc.", - "titleManageProfiles": "Gérer les profils Cwtch", - "tooltipUnlockProfiles": "Déverrouillez les profils chiffrés en saisissant leur mot de passe.", - "tooltipOpenSettings": "Ouvrez le volet des paramètres", + "dateNever": "Jamais", + "titleManageServers": "Gérer les serveurs", + "inviteToGroup": "Vous avez été invité à rejoindre un groupe :", + "leaveGroup": "Quittez cette conversation", + "reallyLeaveThisGroupPrompt": "Êtes-vous sûr de vouloir quitter cette conversation ? Tous les messages et attributs seront supprimés.", + "yesLeave": "Oui, quittez cette conversation", + "noPasswordWarning": "Ne pas utiliser de mot de passe sur ce compte signifie que toutes les données stockées localement ne seront pas chiffrées.", + "yourDisplayName": "Pseudo", + "currentPasswordLabel": "Mot de passe actuel", + "password1Label": "Mot de passe", + "password2Label": "Saisissez à nouveau le mot de passe", + "passwordErrorEmpty": "Le mot de passe ne peut pas être vide", + "createProfileBtn": "Créer un profil", + "loadingTor": "Chargement de tor...", + "viewGroupMembershipTooltip": "Afficher les membres du groupe", + "networkStatusDisconnected": "Déconnecté d'Internet, vérifiez votre connexion", + "networkStatusAttemptingTor": "Tentative de connexion au réseau Tor", + "networkStatusOnline": "En ligne", + "newConnectionPaneTitle": "Nouvelle connexion", + "enableGroups": "Activer la discussion de groupe", + "enterCurrentPasswordForDelete": "Veuillez entrer le mot de passe actuel pour supprimer ce profil.", + "conversationSettings": "Paramètres de conversation", "invalidImportString": "Chaîne d'importation non valide", "contactAlreadyExists": "Le contact existe déjà", - "conversationSettings": "Paramètres de conversation", - "enterCurrentPasswordForDelete": "Veuillez entrer le mot de passe actuel pour supprimer ce profil.", - "enableGroups": "Activer la discussion de groupe", - "experimentsEnabled": "Activer les expériences", - "localeIt": "Italien", - "localeEs": "Espagnol", - "addListItem": "Ajouter un nouvel élément de liste", - "addNewItem": "Ajouter un nouvel élément à la liste", - "todoPlaceholder": "À faire...", - "newConnectionPaneTitle": "Nouvelle connexion", - "networkStatusOnline": "En ligne", - "networkStatusAttemptingTor": "Tentative de connexion au réseau Tor", - "networkStatusDisconnected": "Déconnecté d'Internet, vérifiez votre connexion", - "viewGroupMembershipTooltip": "Afficher les membres du groupe", - "loadingTor": "Chargement de tor...", + "tooltipOpenSettings": "Ouvrez le volet des paramètres", + "tooltipAddContact": "Ajouter un nouveau contact ou une nouvelle conversation", + "titleManageContacts": "Conversations", + "tooltipUnlockProfiles": "Déverrouillez les profils chiffrés en saisissant leur mot de passe.", + "titleManageProfiles": "Gérer les profils Cwtch", + "descriptionExperiments": "Les expériences de Cwtch sont des fonctionnalités optionnelles et facultatives qui ajoutent des fonctionnalités supplémentaires à Cwtch et qui peuvent avoir des considérations de confidentialité différentes de celles du chat traditionnel résistant aux métadonnées 1:1, par exemple le chat de groupe, l'intégration de robots, etc.", + "descriptionExperimentsGroups": "L'expérience de groupe permet à Cwtch de se connecter à une infrastructure de serveurs non fiables pour faciliter la communication avec plus d'un contact.", + "descriptionBlockUnknownConnections": "Si elle est activée, cette option fermera automatiquement les connexions des utilisateurs de Cwtch qui n'ont pas été ajoutés à votre liste de contacts.", + "successfullAddedContact": "Ajouté avec succès ", + "dateRightNow": "Maintenant", + "dateLastMonth": "Le mois dernier", + "dateYesterday": "Hier", + "newPassword": "Nouveau mot de passe", + "chatHistoryDefault": "Cette conversation sera supprimée lorsque Cwtch sera fermé ! L'historique des messages peut être activé pour la conversation via le menu Paramètres en haut à droite.", + "accepted": "Accepté !", + "rejected": "Rejeté !", + "contactSuggestion": "Il s'agit d'une suggestion de contact pour : ", + "sendAnInvitation": "Vous avez envoyé une invitation pour : ", + "torVersion": "Version de Tor", + "torStatus": "Statut de Tor", + "resetTor": "Réinitialiser", + "cancel": "Annuler", + "sendMessage": "Envoyer un message", + "sendInvite": "Envoyer une invitation à un contact ou à un groupe", + "deleteProfileSuccess": "Le profil a été supprimé avec succès", + "addServerFirst": "Vous devez ajouter un serveur avant de pouvoir créer un groupe.", + "nickChangeSuccess": "Le pseudo du profil a été modifié avec succès", + "createProfileToBegin": "Veuillez créer ou déverrouiller un profil pour commencer", + "addContactFirst": "Ajoutez ou choisissez un contact pour commencer à discuter.", + "torNetworkStatus": "Statut du réseau Tor", + "profileDeleteSuccess": "Le profil a été supprimé avec succès", + "malformedMessage": "Message mal formé", + "shutdownCwtchDialogTitle": "Arrêter Cwtch ?", + "shutdownCwtchDialog": "Êtes-vous sûr de vouloir arrêter Cwtch ? Ceci fermera toutes les connexions, et quittera l'application.", + "groupInviteSettingsWarning": "Vous avez été invité à rejoindre un groupe ! Veuillez activer l'expérience de discussion de groupe dans les paramètres pour afficher cette invitation.", + "tooltipShowPassword": "Afficher le mot de passe", + "tooltipHidePassword": "Masquer le mot de passe", + "notificationNewMessageFromPeer": "Nouveau message d'un contact !", + "notificationNewMessageFromGroup": "Nouveau message dans un groupe !", "smallTextLabel": "Petit", "defaultScalingText": "Taille par défaut du texte (échelle:", - "builddate": "Construit le : %2", - "version": "Version %1", - "versionTor": "Version %1 avec tor %2", - "themeDark": "Sombre", - "themeLight": "Clair", - "settingTheme": "Thème", "largeTextLabel": "Large", - "settingInterfaceZoom": "Niveau de zoom", - "localeDe": "Allemand", - "localePt": "Portugais", - "localeFr": "Français", - "localeEn": "Anglais", - "settingLanguage": "Langue", - "zoomLabel": "Zoom de l'interface (affecte principalement la taille du texte et des boutons)", - "versionBuilddate": "Version : %1 Construite le : %2", "cwtchSettingsTitle": "Préférences Cwtch", - "unlock": "Déverrouiller", - "yourServers": "Vos serveurs", - "yourProfiles": "Vos profils", - "error0ProfilesLoadedForPassword": "Aucun profils chargés avec ce mot de passe", - "password": "Mot de passe", - "enterProfilePassword": "Entrez un mot de passe pour consulter vos profils", - "addNewProfileBtn": "Ajouter un nouveau profil", - "deleteConfirmText": "SUPPRIMER", - "deleteProfileConfirmBtn": "Supprimer vraiment le profil ?", - "deleteConfirmLabel": "Tapez SUPPRIMER pour confirmer", - "deleteProfileBtn": "Supprimer le profil", - "passwordChangeError": "Erreur lors de la modification du mot de passe : le mot de passe fourni est rejeté", - "passwordErrorMatch": "Les mots de passe ne correspondent pas", - "saveProfileBtn": "Sauvegarder le profil", - "createProfileBtn": "Créer un profil", - "passwordErrorEmpty": "Le mot de passe ne peut pas être vide", - "password2Label": "Saisissez à nouveau le mot de passe", - "password1Label": "Mot de passe", - "currentPasswordLabel": "Mot de passe actuel", - "yourDisplayName": "Pseudo", - "noPasswordWarning": "Ne pas utiliser de mot de passe sur ce compte signifie que toutes les données stockées localement ne seront pas chiffrées.", - "radioNoPassword": "Non chiffré (pas de mot de passe)", - "radioUsePassword": "Mot de passe", "copiedToClipboardNotification": "Copié dans le presse-papier", - "copyBtn": "Copier", - "editProfile": "Modifier le profil", - "newProfile": "Nouveau profil", - "defaultProfileName": "Alice", - "profileName": "Pseudo", - "editProfileTitle": "Modifier le profil", - "addProfileTitle": "Ajouter un nouveau profil", - "deleteBtn": "Effacer", "saveBtn": "Sauvegarder", "displayNameLabel": "Pseudo", "addressLabel": "Adresse", @@ -210,46 +267,16 @@ "acceptGroupInviteLabel": "Voulez-vous accepter l'invitation au groupe", "newGroupBtn": "Créer un nouveau groupe", "copiedClipboardNotification": "Copié dans le presse-papier", + "copyBtn": "Copier", "pendingLabel": "En attente", - "acknowledgedLabel": "Accusé de réception", "couldNotSendMsgError": "Impossible d'envoyer ce message", "dmTooltip": "Envoyer un message privé", - "membershipDescription": "Liste des utilisateurs ayant envoyés un ou plusieurs messages au groupe. Cette liste peut ne pas être représentatives de l'ensemble des membres du groupe.", - "addListItemBtn": "Ajouter un élément", - "searchList": "Liste de recherche", - "update": "Mise à jour", "inviteBtn": "Invitation", - "inviteToGroupLabel": "Inviter au groupe", - "groupNameLabel": "Nom du groupe", - "viewServerInfo": "Informations sur le serveur", - "serverSynced": "Synchronisé", - "serverConnectivityDisconnected": "Serveur déconnecté", - "serverConnectivityConnected": "Serveur connecté", - "serverInfo": "Informations sur le serveur", "invitationLabel": "Invitation", "serverLabel": "Serveur", - "search": "Recherche...", - "cycleColoursDesktop": "Cliquez pour faire défiler les couleurs.\nCliquez avec le bouton droit de la souris pour réinitialiser.", - "cycleColoursAndroid": "Cliquez pour faire défiler les couleurs.\nAppuyez longuement pour réinitialiser.", - "cycleMorphsDesktop": "Cliquez pour faire défiler les morphes.\n Faites un clic droit pour réinitialiser.", - "cycleMorphsAndroid": "Cliquez pour faire défiler les morphes.\n Appuyez longuement pour réinitialiser.", - "cycleCatsDesktop": "Cliquez pour parcourir la catégorie.\n Faites un clic droit pour réinitialiser.", - "cycleCatsAndroid": "Cliquez pour faire défiler les catégories.\nAppuyez longuement pour réinitialiser.", - "blocked": "Bloqué", "titlePlaceholder": "titre...", "postNewBulletinLabel": "Envoyer un nouveau bulletin", "newBulletinLabel": "Nouveau bulletin", - "joinGroup": "Rejoindre le groupe", - "createGroup": "Créer un groupe", - "groupAddr": "Adresse", - "invitation": "Invitation", - "server": "Serveur", - "groupName": "Nom du groupe", - "peerName": "Nom", - "peerAddress": "Adresse", - "joinGroupTab": "Rejoindre un groupe", - "createGroupTab": "Créer un groupe", "createGroupBtn": "Créer", - "defaultGroupName": "Un groupe génial", "createGroupTitle": "Créer un groupe" -} \ No newline at end of file +} diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index fce93d69..e30cfb70 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,255 +1,282 @@ { "@@locale": "it", - "@@last_modified": "2021-11-11T01:02:08+01:00", - "newMessagesLabel": "New Messages", - "localeRU": "Russian", - "copyServerKeys": "Copy keys", - "verfiyResumeButton": "Verify\/resume", - "fileCheckingStatus": "Checking download status", - "fileInterrupted": "Interrupted", - "fileSavedTo": "Saved to", - "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", - "encryptedServerDescription": "Encrypting a server with a password protects it from other people who may also use this device. Encrypted servers cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", - "deleteServerConfirmBtn": "Really delete server", - "deleteServerSuccess": "Successfully deleted server", - "enterCurrentPasswordForDeleteServer": "Please enter current password to delete this server", - "copyAddress": "Copy Address", - "settingServersDescription": "The hosting servers experiment enables hosting and managing Cwtch servers", - "settingServers": "Hosting Servers", - "enterServerPassword": "Enter password to unlock server", - "unlockProfileTip": "Please create or unlock a profile to begin!", - "unlockServerTip": "Please create or unlock a server to begin!", - "addServerTooltip": "Add new server", - "serversManagerTitleShort": "Servers", - "serversManagerTitleLong": "Servers You Host", - "saveServerButton": "Save Server", - "serverAutostartDescription": "Controls if the application will automatically launch the server on start", - "serverAutostartLabel": "Autostart", - "serverEnabledDescription": "Start or stop the server", - "serverEnabled": "Server Enabled", - "serverDescriptionDescription": "Your description of the server for personal management use only, will never be shared", - "serverDescriptionLabel": "Server Description", - "serverAddress": "Server Address", - "editServerTitle": "Edit Server", - "addServerTitle": "Add Server", - "titleManageProfilesShort": "Profiles", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", - "descriptionFileSharing": "L'esperimento di condivisione dei file ti consente di inviare e ricevere file dai contatti e dai gruppi di Cwtch. Tieni presente che la condivisione di un file con un gruppo farà sì che i membri di quel gruppo si colleghino con te direttamente su Cwtch per scaricarlo.", - "settingFileSharing": "Condivisione file", - "tooltipSendFile": "Invia file", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", + "descriptionStreamerMode": "Se attivata, questa opzione rende l'applicazione visivamente più privata per lo streaming o la presentazione, ad esempio nascondendo il profilo e gli indirizzi di contatto", + "retrievingManifestMessage": "Recupero delle informazioni sul file in corso...", + "openFolderButton": "Apri cartella", + "downloadFileButton": "Scarica", + "labelFilename": "Nome del file", + "labelFilesize": "Dimensione", + "messageEnableFileSharing": "Abilita l'esperimento di condivisione dei file per visualizzare questo messaggio.", + "messageFileSent": "Hai inviato un file", + "titleManageProfilesShort": "Profili", + "addServerTitle": "Aggiungi server", + "tooltipReplyToThisMessage": "Rispondi a questo messaggio", + "tooltipRemoveThisQuotedMessage": "Rimuovi il messaggio citato.", + "localePl": "Polacco", + "settingUIColumnPortrait": "Colonne dell'interfaccia utente in modalità verticale", + "settingUIColumnLandscape": "Colonne dell'interfaccia utente in modalità orizzontale", + "settingUIColumnSingle": "Singola", + "settingUIColumnDouble12Ratio": "Doppia (1:2)", + "settingUIColumnDouble14Ratio": "Doppia (1:4)", + "settingUIColumnOptionSame": "Stessa impostazione della modalità verticale", + "contactGoto": "Vai alla conversazione con %1", + "addContact": "Aggiungi contatto", + "addContactConfirm": "Aggiungi %1 come contatto", + "encryptedProfileDescription": "Criptare un profilo con una password lo protegge da altre persone che potrebbero usare questo dispositivo. I profili criptati non possono essere decriptati, visualizzati o accessibili finché non viene inserita la password corretta per sbloccarli.", + "plainServerDescription": "Ti raccomandiamo di proteggere i tuoi server Cwtch con una password. Se non imposti una password su questo server, chiunque abbia accesso a questo dispositivo potrebbe essere in grado di accedere alle relativ informazioni, compresi dati sensibili come le chiavi crittografiche.", + "plainProfileDescription": "Ti raccomandiamo di proteggere i tuoi profili Cwtch con una password. Se non imposti una password su questo profilo, chiunque abbia accesso a questo dispositivo potrebbe essere in grado di accedere alle relative informazioni, compresi contatti, messaggi e altri dati sensibili come le chiavi crittografiche.", + "placeholderEnterMessage": "Scrivi un messaggio...", + "blockedMessageMessage": "Questo messaggio proviene da un profilo che hai bloccato.", + "showMessageButton": "Mostra il messaggio", + "blockUnknownConnectionsEnabledDescription": "Le connessioni da contatti sconosciuti sono bloccate. Puoi modificare questa impostazione in Impostazioni", + "archiveConversation": "Archivia questa conversazione", + "streamerModeLabel": "Modalità Streamer\/Presentazione", + "editServerTitle": "Modifica il server", + "serverAddress": "Indirizzo del server", + "serverDescriptionLabel": "Descrizione del server", + "serverDescriptionDescription": "La tua descrizione del server solo per gestione personale, non sarà mai condivisa", + "serverEnabled": "Server abilitato", + "serverEnabledDescription": "Avvia o arresta il server", + "serverAutostartLabel": "Avvio automatico", + "serverAutostartDescription": "Controlla se l'applicazione avvierà automaticamente il server all'avvio", + "saveServerButton": "Salva il server", + "serversManagerTitleLong": "Server che gestisci", + "serversManagerTitleShort": "Gestisci i server", + "addServerTooltip": "Aggiungi nuovo server", + "unlockServerTip": "Crea o sblocca un server per iniziare!", + "unlockProfileTip": "Crea o sblocca un profilo per iniziare!", + "enterServerPassword": "Inserisci la password per sbloccare il server", + "settingServers": "Server di hosting", + "settingServersDescription": "L'esperimento dei server di hosting permette di allocare e gestire i server Cwtch", + "copyAddress": "Copia indirizzo", + "enterCurrentPasswordForDeleteServer": "Inserisci la password attuale per eliminare questo server", + "deleteServerSuccess": "Server eliminato con successo", + "deleteServerConfirmBtn": "Elimina davvero il server", + "encryptedServerDescription": "Criptare un server con una password lo protegge da altre persone che potrebbero usare questo dispositivo. I server criptati non possono essere decriptati, visualizzati o accessibili finché non viene inserita la password corretta per sbloccarli.", + "fileSavedTo": "Salvato in", + "fileInterrupted": "Interrotto", + "fileCheckingStatus": "Controllo dello stato del download", + "verfiyResumeButton": "Verifica\/riprendi", + "copyServerKeys": "Copia chiavi", + "localeRU": "Russo", + "newMessagesLabel": "Nuovi messaggi", "messageFileOffered": "Il contatto offre l'invio di un file", - "messageFileSent": "You sent a file", - "messageEnableFileSharing": "Enable the file sharing experiment to view this message.", - "labelFilesize": "Size", - "labelFilename": "Filename", - "downloadFileButton": "Download", - "openFolderButton": "Open Folder", - "retrievingManifestMessage": "Retrieving file information...", - "streamerModeLabel": "Streamer\/Presentation Mode", - "archiveConversation": "Archive this Conversation", - "profileOnionLabel": "Inviare questo indirizzo ai peer con cui si desidera connettersi", - "addPeerTab": "Aggiungi un peer", - "addPeer": "Aggiungi peer", - "peerNotOnline": "Il peer è offline. Le applicazioni non possono essere utilizzate in questo momento.", - "peerBlockedMessage": "Il peer è bloccato", - "peerOfflineMessage": "Il peer è offline, i messaggi non possono essere recapitati in questo momento", - "blockBtn": "Blocca il peer", - "savePeerHistory": "Salva cronologia peer", - "savePeerHistoryDescription": "Determina se eliminare o meno ogni cronologia eventualmente associata al peer.", - "dontSavePeerHistory": "Elimina cronologia dei peer", - "unblockBtn": "Sblocca il peer", - "blockUnknownLabel": "Blocca peer sconosciuti", - "blockUnknownConnectionsEnabledDescription": "Connections from unknown contacts are blocked. You can change this in Settings", - "networkStatusConnecting": "Connessione alla rete e ai peer ...", - "showMessageButton": "Show Message", - "blockedMessageMessage": "This message is from a profile you have blocked.", - "placeholderEnterMessage": "Type a message...", - "plainProfileDescription": "We recommend that you protect your Cwtch profiles with a password. If you do not set a password on this profile then anyone who has access to this device may be able to access information about this profile, including contacts, messages and sensitive cryptographic keys.", - "encryptedProfileDescription": "Encrypting a profile with a password protects it from other people who may also use this device. Encrypted profiles cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", - "addContactConfirm": "Add contact %1", - "addContact": "Add contact", - "contactGoto": "Go to conversation with %1", - "settingUIColumnOptionSame": "Same as portrait mode setting", - "settingUIColumnDouble14Ratio": "Double (1:4)", - "settingUIColumnDouble12Ratio": "Double (1:2)", - "settingUIColumnSingle": "Single", - "settingUIColumnLandscape": "UI Columns in Landscape Mode", - "settingUIColumnPortrait": "UI Columns in Portrait Mode", - "localePl": "Polish", - "tooltipRemoveThisQuotedMessage": "Remove quoted message.", - "tooltipReplyToThisMessage": "Reply to this message", - "tooltipRejectContactRequest": "Rifiuta questa richiesta di contatto", - "tooltipAcceptContactRequest": "Accetta questa richiesta di contatto.", - "notificationNewMessageFromGroup": "Nuovo messaggio in un gruppo!", - "notificationNewMessageFromPeer": "Nuovo messaggio da un contatto!", - "tooltipHidePassword": "Nascondi la password", - "tooltipShowPassword": "Mostra la password", + "tooltipSendFile": "Invia file", + "settingFileSharing": "Condivisione file", + "descriptionFileSharing": "L'esperimento di condivisione dei file ti consente di inviare e ricevere file dai contatti e dai gruppi di Cwtch. Tieni presente che la condivisione di un file con un gruppo farà sì che i membri di quel gruppo si colleghino con te direttamente su Cwtch per scaricarlo.", + "experimentsEnabled": "Abilita esperimenti", "serverNotSynced": "Sincronizzazione nuovi messaggi (l'operazione può richiedere del tempo)...", - "groupInviteSettingsWarning": "Sei stato invitato ad unirti ad un gruppo! Abilita l'Esperimento di chat di gruppo in Impostazioni per visualizzare questo Invito.", - "shutdownCwtchAction": "Chiudi Cwtch", - "shutdownCwtchDialog": "Sei sicuro di voler chiudere Cwtch? Questo chiuderà tutte le connessioni e uscirà dall'applicazione.", - "shutdownCwtchDialogTitle": "Chiudi Cwtch?", - "shutdownCwtchTooltip": "Chiudi Cwtch", - "malformedMessage": "Messaggio non valido", - "profileDeleteSuccess": "Profilo eliminato con successo", - "debugLog": "Attiva la registrazione del debug della console", - "torNetworkStatus": "Stato della rete Tor", - "addContactFirst": "Aggiungi o scegli un contatto per iniziare a chattare.", - "createProfileToBegin": "Crea o sblocca un profilo per iniziare", - "nickChangeSuccess": "Nickname del profilo modificato con successo", - "addServerFirst": "È necessario aggiungere un server prima di poter creare un gruppo", - "deleteProfileSuccess": "Profilo eliminato con successo", - "sendInvite": "Invia un invito a un contatto o a un gruppo", - "sendMessage": "Invia messaggio", - "cancel": "Annulla", - "resetTor": "Resettare", - "torStatus": "Stato di Tor", - "torVersion": "Versione di Tor", - "sendAnInvitation": "Hai inviato un invito per:", - "contactSuggestion": "Questo è un suggerimento di contatto per:", - "rejected": "Rifiutato!", - "accepted": "Accettato!", - "chatHistoryDefault": "Questa conversazione sarà cancellata quando Cwtch sarà chiuso! La cronologia dei messaggi può essere abilitata per ogni conversazione tramite il menu Impostazioni in alto a destra.", - "newPassword": "Nuova password", - "yesLeave": "Sì, lascia questa conversazione", - "reallyLeaveThisGroupPrompt": "Uscire da questa conversazione? Tutti i messaggi e gli attributi verranno eliminati.", - "leaveGroup": "Lascia questa conversazione", - "inviteToGroup": "Hai ricevuto un invito a unirti a un gruppo:", "pasteAddressToAddContact": "Incolla qui un indirizzo cwtch, un invito o un mazzo di chiavi per aggiungere una nuova conversazione", - "tooltipAddContact": "Aggiungi un nuovo contatto o conversazione", - "titleManageContacts": "Conversazioni", - "titleManageServers": "Gestisci i server", - "dateNever": "Mai", - "dateLastYear": "L'anno scorso", - "dateYesterday": "Ieri", - "dateLastMonth": "Mese scorso", - "dateRightNow": "Ora", - "successfullAddedContact": "Aggiunto con successo ", - "descriptionBlockUnknownConnections": "Se attivata, questa opzione chiuderà automaticamente le connessioni degli utenti Cwtch che non sono stati aggiunti alla tua lista di contatti.", - "descriptionExperimentsGroups": "L'esperimento di gruppo permette a Cwtch di connettersi con un'infrastruttura server non fidata per facilitare la comunicazione con più di un contatto.", - "descriptionExperiments": "Gli esperimenti di Cwtch sono opzioni a scelta che aggiungono a Cwtch funzionalità che possono avere diverse considerazioni sulla privacy rispetto alla tradizionale chat 1:1 resistente ai metadati, ad esempio chat di gruppo, integrazione di bot ecc.", - "titleManageProfiles": "Gestisci i profili Cwtch", - "tooltipUnlockProfiles": "Sblocca i profili crittografati inserendo la loro password.", - "tooltipOpenSettings": "Aprire il pannello delle impostazioni", + "enableGroups": "Abilita la chat di gruppo", + "enterCurrentPasswordForDelete": "Inserisci la password attuale per eliminare questo profilo.", + "conversationSettings": "Impostazioni di conversazione", "invalidImportString": "Importazione stringa non valida", "contactAlreadyExists": "Il contatto esiste già", - "conversationSettings": "Impostazioni di conversazione", - "enterCurrentPasswordForDelete": "Inserisci la password attuale per eliminare questo profilo.", - "enableGroups": "Abilita la chat di gruppo", - "experimentsEnabled": "Abilita esperimenti", + "tooltipOpenSettings": "Aprire il pannello delle impostazioni", + "tooltipAddContact": "Aggiungi un nuovo contatto o conversazione", + "titleManageContacts": "Conversazioni", + "tooltipUnlockProfiles": "Sblocca i profili crittografati inserendo la loro password.", + "titleManageProfiles": "Gestisci i profili Cwtch", + "descriptionExperiments": "Gli esperimenti di Cwtch sono opzioni a scelta che aggiungono a Cwtch funzionalità che possono avere diverse considerazioni sulla privacy rispetto alla tradizionale chat 1:1 resistente ai metadati, ad esempio chat di gruppo, integrazione di bot ecc.", + "descriptionExperimentsGroups": "L'esperimento di gruppo permette a Cwtch di connettersi con un'infrastruttura server non fidata per facilitare la comunicazione con più di un contatto.", + "descriptionBlockUnknownConnections": "Se attivata, questa opzione chiuderà automaticamente le connessioni degli utenti Cwtch che non sono stati aggiunti alla tua lista di contatti.", + "successfullAddedContact": "Aggiunto con successo ", + "dateRightNow": "Ora", + "dateLastMonth": "Mese scorso", + "dateYesterday": "Ieri", + "dateLastYear": "L'anno scorso", + "dateNever": "Mai", + "titleManageServers": "Gestisci i server", + "inviteToGroup": "Hai ricevuto un invito a unirti a un gruppo:", + "leaveGroup": "Lascia questa conversazione", + "reallyLeaveThisGroupPrompt": "Uscire da questa conversazione? Tutti i messaggi e gli attributi verranno eliminati.", + "yesLeave": "Sì, lascia questa conversazione", + "newPassword": "Nuova password", + "chatHistoryDefault": "Questa conversazione sarà cancellata quando Cwtch sarà chiuso! La cronologia dei messaggi può essere abilitata per ogni conversazione tramite il menu Impostazioni in alto a destra.", + "accepted": "Accettato!", + "rejected": "Rifiutato!", + "contactSuggestion": "Questo è un suggerimento di contatto per:", + "sendAnInvitation": "Hai inviato un invito per:", + "torVersion": "Versione di Tor", + "torStatus": "Stato di Tor", + "resetTor": "Resettare", + "cancel": "Annulla", + "sendMessage": "Invia messaggio", + "sendInvite": "Invia un invito a un contatto o a un gruppo", + "deleteProfileSuccess": "Profilo eliminato con successo", + "addServerFirst": "È necessario aggiungere un server prima di poter creare un gruppo", + "nickChangeSuccess": "Nickname del profilo modificato con successo", + "createProfileToBegin": "Crea o sblocca un profilo per iniziare", + "addContactFirst": "Aggiungi o scegli un contatto per iniziare a chattare.", + "torNetworkStatus": "Stato della rete Tor", + "debugLog": "Attiva la registrazione del debug della console", + "profileDeleteSuccess": "Profilo eliminato con successo", + "malformedMessage": "Messaggio non valido", + "shutdownCwtchTooltip": "Chiudi Cwtch", + "shutdownCwtchDialogTitle": "Chiudi Cwtch?", + "shutdownCwtchAction": "Chiudi Cwtch", + "shutdownCwtchDialog": "Sei sicuro di voler chiudere Cwtch? Questo chiuderà tutte le connessioni e uscirà dall'applicazione.", + "groupInviteSettingsWarning": "Sei stato invitato ad unirti ad un gruppo! Abilita l'Esperimento di chat di gruppo in Impostazioni per visualizzare questo Invito.", + "tooltipShowPassword": "Mostra la password", + "tooltipHidePassword": "Nascondi la password", + "notificationNewMessageFromPeer": "Nuovo messaggio da un contatto!", + "notificationNewMessageFromGroup": "Nuovo messaggio in un gruppo!", + "tooltipAcceptContactRequest": "Accetta questa richiesta di contatto.", + "tooltipRejectContactRequest": "Rifiuta questa richiesta di contatto", + "versionBuilddate": "Versione: %1 Costruito il: %2", + "versionTor": "Versione %1 con tor %2", + "version": "Versione %1", + "builddate": "Costruito il: %2", + "cycleMorphsAndroid": "Fare clic per scorrere i morph.\nPressione lunga per resettare.", + "cycleMorphsDesktop": "Fare clic per scorrere i morph.\nCliccare con il tasto destro per resettare.", + "localeEn": "Inglese", "localeIt": "Italiano", "localeEs": "Spagnolo", - "addListItem": "Aggiungi un nuovo elemento alla lista", - "addNewItem": "Aggiungi un nuovo elemento alla lista", - "todoPlaceholder": "Da fare...", - "newConnectionPaneTitle": "Nuova connessione", - "networkStatusOnline": "Online", - "networkStatusAttemptingTor": "Tentativo di connessione alla rete Tor", - "networkStatusDisconnected": "Disconnesso da Internet, controlla la tua connessione", - "viewGroupMembershipTooltip": "Visualizza i membri del gruppo", - "loadingTor": "Caricamento di tor...", - "smallTextLabel": "Piccolo", - "defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:", - "builddate": "Costruito il: %2", - "version": "Versione %1", - "versionTor": "Versione %1 con tor %2", - "themeDark": "Scuro", - "themeLight": "Chiaro", - "settingTheme": "Tema", - "largeTextLabel": "Grande", - "settingInterfaceZoom": "Livello di zoom", "localeDe": "Tedesco", "localePt": "Portoghese", "localeFr": "Francese", - "localeEn": "Inglese", - "settingLanguage": "Lingua", - "zoomLabel": "Zoom dell'interfaccia (influisce principalmente sulle dimensioni del testo e dei pulsanti)", - "versionBuilddate": "Versione: %1 Costruito il: %2", - "cwtchSettingsTitle": "Impostazioni di Cwtch", - "unlock": "Sblocca", - "yourServers": "I tuoi server", - "yourProfiles": "I tuoi profili", - "error0ProfilesLoadedForPassword": "0 profili caricati con quella password", - "password": "Password", - "enterProfilePassword": "Inserisci una password per visualizzare i tuoi profili", - "addNewProfileBtn": "Aggiungi nuovo profilo", - "deleteConfirmText": "ELIMINA", - "deleteProfileConfirmBtn": "Elimina realmente il profilo", - "deleteConfirmLabel": "Digita ELIMINA per confermare", - "deleteProfileBtn": "Elimina profilo", - "passwordChangeError": "Errore durante la modifica della password: password fornita rifiutata", - "passwordErrorMatch": "Le password non corrispondono", - "saveProfileBtn": "Salva il profilo", - "createProfileBtn": "Crea un profilo", - "passwordErrorEmpty": "La password non può essere vuota", - "password2Label": "Reinserire la password", - "password1Label": "Password", - "currentPasswordLabel": "Password corrente", - "yourDisplayName": "Il tuo nome visualizzato", - "noPasswordWarning": "Non utilizzare una password su questo account significa che tutti i dati archiviati localmente non verranno criptati", - "radioNoPassword": "Non criptato (senza password)", - "radioUsePassword": "Password", + "addListItem": "Aggiungi un nuovo elemento alla lista", + "savePeerHistoryDescription": "Determina se eliminare o meno ogni cronologia eventualmente associata al peer.", + "unblockBtn": "Sblocca il peer", "copiedToClipboardNotification": "Copiato negli Appunti", - "copyBtn": "Copia", - "editProfile": "Modifica profilo", - "newProfile": "Nuovo profilo", - "defaultProfileName": "Alice", - "profileName": "Nome visualizzato", - "editProfileTitle": "Modifica profilo", - "addProfileTitle": "Aggiungi nuovo profilo", - "deleteBtn": "Elimina", - "saveBtn": "Salva", - "displayNameLabel": "Nome visualizzato", - "addressLabel": "Indirizzo", - "puzzleGameBtn": "Gioco di puzzle", - "bulletinsBtn": "Bollettini", - "listsBtn": "Liste", - "chatBtn": "Chat", - "rejectGroupBtn": "Rifiuta", - "acceptGroupBtn": "Accetta", - "acceptGroupInviteLabel": "Vuoi accettare l'invito a", - "newGroupBtn": "Crea un nuovo gruppo", - "copiedClipboardNotification": "Copiato negli Appunti", - "pendingLabel": "In corso", - "acknowledgedLabel": "Riconosciuto", - "couldNotSendMsgError": "Impossibile inviare questo messaggio", - "dmTooltip": "Clicca per inviare un Messagio Diretto", - "membershipDescription": "Di seguito è riportato un elenco di utenti che hanno inviato messaggi al gruppo. Questo elenco potrebbe non corrispondere a tutti gli utenti che hanno accesso al gruppo.", - "addListItemBtn": "Aggiungi elemento", - "searchList": "Cerca nella lista", - "update": "Aggiornamento", - "inviteBtn": "Invitare", - "inviteToGroupLabel": "Invitare nel gruppo", - "groupNameLabel": "Nome del gruppo", - "viewServerInfo": "Informazioni sul server", - "serverSynced": "Sincronizzato", - "serverConnectivityDisconnected": "Server disconnesso", - "serverConnectivityConnected": "Server connesso", - "serverInfo": "Informazioni sul server", - "invitationLabel": "Invito", + "createGroupTitle": "Crea un gruppo", "serverLabel": "Server", - "search": "Ricerca...", + "groupNameLabel": "Nome del gruppo", + "defaultGroupName": "Gruppo fantastico", + "createGroupBtn": "Crea", + "addPeerTab": "Aggiungi un peer", + "createGroupTab": "Crea un gruppo", + "joinGroupTab": "Unisciti a un gruppo", + "peerAddress": "Indirizzo", + "peerName": "Nome", + "groupName": "Nome del gruppo", + "server": "Server", + "invitation": "Invito", + "groupAddr": "Indirizzo", + "newBulletinLabel": "Nuovo bollettino", + "addPeer": "Aggiungi peer", + "createGroup": "Crea un gruppo", + "joinGroup": "Unisciti al gruppo", + "postNewBulletinLabel": "Pubblica un nuovo bollettino", + "titlePlaceholder": "titolo...", + "blocked": "Bloccato", + "cycleCatsAndroid": "Fare clic per scorrere le categorie.\nPressione lunga per resettare.", + "cycleCatsDesktop": "Fare clic per scorrere le categorie.\nCliccare con il tasto destro per resettare.", + "viewGroupMembershipTooltip": "Visualizza i membri del gruppo", "cycleColoursDesktop": "Fare clic per scorrere i colori.\nCliccare con il tasto destro per resettare.", "cycleColoursAndroid": "Fare clic per scorrere i colori.\nPressione lunga per resettare.", - "cycleMorphsDesktop": "Fare clic per scorrere i morph.\nCliccare con il tasto destro per resettare.", - "cycleMorphsAndroid": "Fare clic per scorrere i morph.\nPressione lunga per resettare.", - "cycleCatsDesktop": "Fare clic per scorrere le categorie.\nCliccare con il tasto destro per resettare.", - "cycleCatsAndroid": "Fare clic per scorrere le categorie.\nPressione lunga per resettare.", - "blocked": "Bloccato", - "titlePlaceholder": "titolo...", - "postNewBulletinLabel": "Pubblica un nuovo bollettino", - "newBulletinLabel": "Nuovo bollettino", - "joinGroup": "Unisciti al gruppo", - "createGroup": "Crea un gruppo", - "groupAddr": "Indirizzo", - "invitation": "Invito", - "server": "Server", - "groupName": "Nome del gruppo", - "peerName": "Nome", - "peerAddress": "Indirizzo", - "joinGroupTab": "Unisciti a un gruppo", - "createGroupTab": "Crea un gruppo", - "createGroupBtn": "Crea", - "defaultGroupName": "Gruppo fantastico", - "createGroupTitle": "Crea un gruppo" + "search": "Ricerca...", + "peerBlockedMessage": "Il peer è bloccato", + "peerOfflineMessage": "Il peer è offline, i messaggi non possono essere recapitati in questo momento", + "copyBtn": "Copia", + "copiedClipboardNotification": "Copiato negli Appunti", + "newGroupBtn": "Crea un nuovo gruppo", + "profileOnionLabel": "Inviare questo indirizzo ai peer con cui si desidera connettersi", + "invitationLabel": "Invito", + "serverInfo": "Informazioni sul server", + "serverConnectivityConnected": "Server connesso", + "serverConnectivityDisconnected": "Server disconnesso", + "membershipDescription": "Di seguito è riportato un elenco di utenti che hanno inviato messaggi al gruppo. Questo elenco potrebbe non corrispondere a tutti gli utenti che hanno accesso al gruppo.", + "dmTooltip": "Clicca per inviare un Messagio Diretto", + "couldNotSendMsgError": "Impossibile inviare questo messaggio", + "acknowledgedLabel": "Riconosciuto", + "pendingLabel": "In corso", + "acceptGroupInviteLabel": "Vuoi accettare l'invito a", + "acceptGroupBtn": "Accetta", + "rejectGroupBtn": "Rifiuta", + "chatBtn": "Chat", + "listsBtn": "Liste", + "bulletinsBtn": "Bollettini", + "puzzleGameBtn": "Gioco di puzzle", + "addressLabel": "Indirizzo", + "displayNameLabel": "Nome visualizzato", + "saveBtn": "Salva", + "blockBtn": "Blocca il peer", + "savePeerHistory": "Salva cronologia peer", + "dontSavePeerHistory": "Elimina cronologia dei peer", + "password": "Password", + "error0ProfilesLoadedForPassword": "0 profili caricati con quella password", + "yourProfiles": "I tuoi profili", + "yourServers": "I tuoi server", + "unlock": "Sblocca", + "newConnectionPaneTitle": "Nuova connessione", + "addNewItem": "Aggiungi un nuovo elemento alla lista", + "todoPlaceholder": "Da fare...", + "serverSynced": "Sincronizzato", + "viewServerInfo": "Informazioni sul server", + "inviteToGroupLabel": "Invitare nel gruppo", + "inviteBtn": "Invitare", + "deleteBtn": "Elimina", + "update": "Aggiornamento", + "searchList": "Cerca nella lista", + "peerNotOnline": "Il peer è offline. Le applicazioni non possono essere utilizzate in questo momento.", + "addListItemBtn": "Aggiungi elemento", + "addProfileTitle": "Aggiungi nuovo profilo", + "editProfileTitle": "Modifica profilo", + "profileName": "Nome visualizzato", + "defaultProfileName": "Alice", + "editProfile": "Modifica profilo", + "newProfile": "Nuovo profilo", + "radioUsePassword": "Password", + "radioNoPassword": "Non criptato (senza password)", + "noPasswordWarning": "Non utilizzare una password su questo account significa che tutti i dati archiviati localmente non verranno criptati", + "yourDisplayName": "Il tuo nome visualizzato", + "currentPasswordLabel": "Password corrente", + "password1Label": "Password", + "password2Label": "Reinserire la password", + "passwordErrorEmpty": "La password non può essere vuota", + "createProfileBtn": "Crea un profilo", + "saveProfileBtn": "Salva il profilo", + "passwordErrorMatch": "Le password non corrispondono", + "passwordChangeError": "Errore durante la modifica della password: password fornita rifiutata", + "deleteProfileBtn": "Elimina profilo", + "deleteConfirmLabel": "Digita ELIMINA per confermare", + "deleteProfileConfirmBtn": "Elimina realmente il profilo", + "deleteConfirmText": "ELIMINA", + "addNewProfileBtn": "Aggiungi nuovo profilo", + "enterProfilePassword": "Inserisci una password per visualizzare i tuoi profili", + "cwtchSettingsTitle": "Impostazioni di Cwtch", + "zoomLabel": "Zoom dell'interfaccia (influisce principalmente sulle dimensioni del testo e dei pulsanti)", + "blockUnknownLabel": "Blocca peer sconosciuti", + "settingLanguage": "Lingua", + "settingInterfaceZoom": "Livello di zoom", + "largeTextLabel": "Grande", + "settingTheme": "Tema", + "themeLight": "Chiaro", + "themeDark": "Scuro", + "defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:", + "smallTextLabel": "Piccolo", + "loadingTor": "Caricamento di tor...", + "networkStatusDisconnected": "Disconnesso da Internet, controlla la tua connessione", + "networkStatusAttemptingTor": "Tentativo di connessione alla rete Tor", + "networkStatusConnecting": "Connessione alla rete e ai peer ...", + "networkStatusOnline": "Online" } \ No newline at end of file diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index aa2e5366..78708ee7 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,124 +1,134 @@ { "@@locale": "pl", - "@@last_modified": "2021-11-11T01:02:08+01:00", - "newMessagesLabel": "New Messages", - "localeRU": "Russian", - "copyServerKeys": "Kopiuj klucze", - "verfiyResumeButton": "Zweryfikuj\/wznów", - "fileCheckingStatus": "Sprawdzanie stanu pobierania", - "fileInterrupted": "Przerwane", - "fileSavedTo": "Zapisano do", - "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", - "encryptedServerDescription": "Encrypting a server with a password protects it from other people who may also use this device. Encrypted servers cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", - "deleteServerConfirmBtn": "Naprawdę usuń serwer", - "deleteServerSuccess": "Pomyślnie usunięto serwer", - "enterCurrentPasswordForDeleteServer": "Please enter current password to delete this server", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", + "titleManageServers": "Zarządzaj serwerami", + "leaveGroup": "Wyjdź z tej rozmowy", + "yesLeave": "Tak, wyjdź z tej rozmowy", + "newPassword": "Nowe hasło", + "accepted": "Przyjęte!", + "rejected": "Odrzucone!", + "sendAnInvitation": "You sent an invitation for: ", + "torVersion": "Wersja Tor", + "torStatus": "Status Tor", + "resetTor": "Reset", + "cancel": "Anuluj", + "sendMessage": "Wyślij wiadomość", + "sendInvite": "Wyślij kontakt lub zaproszenie do grupy", + "deleteProfileSuccess": "Pomyślnie usunięto profil", + "nickChangeSuccess": "Nick w profilu został zmieniony pomyślnie", + "torNetworkStatus": "Stan sieci Tor", + "debugLog": "Włącz logowanie debugowania konsoli", + "profileDeleteSuccess": "Pomyślnie usunięto profil", + "malformedMessage": "Źle sformatowana wiadomość", + "shutdownCwtchTooltip": "Zamknij Cwtch", + "shutdownCwtchDialogTitle": "Zamknąć Cwtch?", + "shutdownCwtchAction": "Zamknij Cwtch", + "tooltipShowPassword": "Pokaż hasło", + "tooltipHidePassword": "Ukryj hasło", + "notificationNewMessageFromPeer": "Nowa wiadomość od kontaktu!", + "notificationNewMessageFromGroup": "Nowa wiadomość w grupie!", + "tooltipAcceptContactRequest": "Zaakceptuj tę prośbę o kontakt.", + "tooltipRejectContactRequest": "Odrzuć tę prośbę o kontakt", + "tooltipReplyToThisMessage": "Odpowiedz na tę wiadomość", + "tooltipRemoveThisQuotedMessage": "Usuń cytowaną wiadomość.", + "settingUIColumnDouble12Ratio": "Podwójny (1:2)", + "settingUIColumnSingle": "Pojedynczy", + "settingUIColumnDouble14Ratio": "Podwójny (1:4)", + "settingUIColumnOptionSame": "Tak samo jak w przypadku trybu portretowego", + "contactGoto": "Przejdź do rozmowy z %1", + "addContact": "Dodaj kontakt", + "addContactConfirm": "Dodaj kontakt %1", + "placeholderEnterMessage": "Wpisz wiadomość...", + "blockedMessageMessage": "Ta wiadomość pochodzi z profilu, który został przez Ciebie zablokowany.", + "showMessageButton": "Pokaż wiadomość", + "addServerTitle": "Dodaj serwer", + "editServerTitle": "Edytuj serwer", + "serverAddress": "Adres serwera", + "serverDescriptionLabel": "Opis serwera", + "serverEnabled": "Serwer włączony", + "serverEnabledDescription": "Uruchom lub zatrzymaj serwer", + "serverAutostartLabel": "Autostart", + "saveServerButton": "Zapisz serwer", + "serversManagerTitleLong": "Serwery, które hostujesz", + "serversManagerTitleShort": "Serwery", + "addServerTooltip": "Dodaj nowy serwer", + "enterServerPassword": "Wprowadź hasło, aby odblokować serwer", + "settingServers": "Hosting serwerów", + "enterCurrentPasswordForDeleteServer": "Wprowadź aktualne hasło, aby usunąć ten serwer", + "newMessagesLabel": "Nowe wiadomości", + "localePl": "Polski", + "localeRU": "Rosyjski", "copyAddress": "Skopiuj adres", + "deleteServerSuccess": "Pomyślnie usunięto serwer", + "deleteServerConfirmBtn": "Naprawdę usuń serwer", + "fileSavedTo": "Zapisano do", + "fileCheckingStatus": "Sprawdzanie stanu pobierania", + "verfiyResumeButton": "Zweryfikuj\/wznów", + "copyServerKeys": "Kopiuj klucze", + "fileInterrupted": "Przerwane", + "encryptedServerDescription": "Encrypting a server with a password protects it from other people who may also use this device. Encrypted servers cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", + "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", "settingServersDescription": "The hosting servers experiment enables hosting and managing Cwtch servers", - "settingServers": "Hosting Servers", - "enterServerPassword": "Enter password to unlock server", "unlockProfileTip": "Please create or unlock a profile to begin!", "unlockServerTip": "Please create or unlock a server to begin!", - "addServerTooltip": "Add new server", - "serversManagerTitleShort": "Servers", - "serversManagerTitleLong": "Servers You Host", - "saveServerButton": "Save Server", "serverAutostartDescription": "Controls if the application will automatically launch the server on start", - "serverAutostartLabel": "Autostart", - "serverEnabledDescription": "Start or stop the server", - "serverEnabled": "Server Enabled", "serverDescriptionDescription": "Your description of the server for personal management use only, will never be shared", - "serverDescriptionLabel": "Server Description", - "serverAddress": "Server Address", - "editServerTitle": "Edit Server", - "addServerTitle": "Add Server", + "blockUnknownConnectionsEnabledDescription": "Połączenia od nieznanych kontaktów są blokowane. Można to zmienić w Ustawieniach", + "archiveConversation": "Zarchiwizuj tę rozmowę", + "streamerModeLabel": "Tryb streamera\/prezentacji", + "retrievingManifestMessage": "Pobieranie informacji o pliku...", + "openFolderButton": "Otwórz folder", + "downloadFileButton": "Pobierz", + "labelFilename": "Nazwa pliku", + "labelFilesize": "Rozmiar", + "messageEnableFileSharing": "Włącz eksperyment udostępniania plików, aby wyświetlić tę wiadomość.", + "messageFileSent": "Plik został wysłany", + "messageFileOffered": "Kontakt proponuje wysłanie Ci pliku", + "tooltipSendFile": "Wyślij plik", + "settingFileSharing": "Udostępnianie plików", + "descriptionFileSharing": "Eksperyment udostępniania plików pozwala na wysyłanie i odbieranie plików od kontaktów i grup Cwtch. Zauważ, że udostępnienie pliku grupie spowoduje, że członkowie tej grupy połączą się z Tobą bezpośrednio przez Cwtch, aby go pobrać.", "titleManageProfilesShort": "Profile", "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", - "descriptionFileSharing": "Eksperyment udostępniania plików pozwala na wysyłanie i odbieranie plików od kontaktów i grup Cwtch. Zauważ, że udostępnienie pliku grupie spowoduje, że członkowie tej grupy połączą się z Tobą bezpośrednio przez Cwtch, aby go pobrać.", - "settingFileSharing": "Udostępnianie plików", - "tooltipSendFile": "Wyślij plik", - "messageFileOffered": "Kontakt proponuje wysłanie Ci pliku", - "messageFileSent": "Plik został wysłany", - "messageEnableFileSharing": "Włącz eksperyment udostępniania plików, aby wyświetlić tę wiadomość.", - "labelFilesize": "Rozmiar", - "labelFilename": "Nazwa pliku", - "downloadFileButton": "Pobierz", - "openFolderButton": "Otwórz folder", - "retrievingManifestMessage": "Pobieranie informacji o pliku...", - "streamerModeLabel": "Tryb streamera\/prezentacji", - "archiveConversation": "Zarchiwizuj tę rozmowę", - "profileOnionLabel": "Send this address to contacts you want to connect with", - "addPeerTab": "Add a contact", - "addPeer": "Add Contact", - "peerNotOnline": "Contact is offline. Applications cannot be used right now.", - "peerBlockedMessage": "Contact is blocked", - "peerOfflineMessage": "Contact is offline, messages can't be delivered right now", - "blockBtn": "Block Contact", - "savePeerHistory": "Save History", - "savePeerHistoryDescription": "Determines whether or not to delete any history associated with the contact.", - "dontSavePeerHistory": "Delete History", - "unblockBtn": "Unblock Contact", - "blockUnknownLabel": "Block Unknown Contacts", - "blockUnknownConnectionsEnabledDescription": "Połączenia od nieznanych kontaktów są blokowane. Można to zmienić w Ustawieniach", - "networkStatusConnecting": "Connecting to network and contacts...", - "showMessageButton": "Show Message", - "blockedMessageMessage": "This message is from a profile you have blocked.", - "placeholderEnterMessage": "Type a message...", "plainProfileDescription": "We recommend that you protect your Cwtch profiles with a password. If you do not set a password on this profile then anyone who has access to this device may be able to access information about this profile, including contacts, messages and sensitive cryptographic keys.", "encryptedProfileDescription": "Encrypting a profile with a password protects it from other people who may also use this device. Encrypted profiles cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", - "addContactConfirm": "Add contact %1", - "addContact": "Add contact", - "contactGoto": "Go to conversation with %1", - "settingUIColumnOptionSame": "Same as portrait mode setting", - "settingUIColumnDouble14Ratio": "Double (1:4)", - "settingUIColumnDouble12Ratio": "Double (1:2)", - "settingUIColumnSingle": "Single", "settingUIColumnLandscape": "UI Columns in Landscape Mode", "settingUIColumnPortrait": "UI Columns in Portrait Mode", - "localePl": "Polish", - "tooltipRemoveThisQuotedMessage": "Remove quoted message.", - "tooltipReplyToThisMessage": "Reply to this message", - "tooltipRejectContactRequest": "Reject this contact request", - "tooltipAcceptContactRequest": "Accept this contact request.", - "notificationNewMessageFromGroup": "New message in a group!", - "notificationNewMessageFromPeer": "New message from a contact!", - "tooltipHidePassword": "Hide Password", - "tooltipShowPassword": "Show Password", - "serverNotSynced": "Syncing New Messages (This can take some time)...", "groupInviteSettingsWarning": "You have been invited to join a group! Please enable the Group Chat Experiment in Settings to view this Invitation.", - "shutdownCwtchAction": "Shutdown Cwtch", "shutdownCwtchDialog": "Are you sure you want to shutdown Cwtch? This will close all connections, and exit the application.", - "shutdownCwtchDialogTitle": "Shutdown Cwtch?", - "shutdownCwtchTooltip": "Shutdown Cwtch", - "malformedMessage": "Malformed message", - "profileDeleteSuccess": "Successfully deleted profile", - "debugLog": "Turn on console debug logging", - "torNetworkStatus": "Tor network status", "addContactFirst": "Add or pick a contact to begin chatting.", "createProfileToBegin": "Please create or unlock a profile to begin", - "nickChangeSuccess": "Profile nickname changed successfully", "addServerFirst": "You need to add a server before you can create a group", - "deleteProfileSuccess": "Successfully deleted profile", - "sendInvite": "Send a contact or group invite", - "sendMessage": "Send Message", - "cancel": "Cancel", - "resetTor": "Reset", - "torStatus": "Tor Status", - "torVersion": "Tor Version", - "sendAnInvitation": "You sent an invitation for: ", "contactSuggestion": "This is a contact suggestion for: ", - "rejected": "Rejected!", - "accepted": "Accepted!", "chatHistoryDefault": "This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right.", - "newPassword": "New Password", - "yesLeave": "Yes, Leave This Conversation", "reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.", - "leaveGroup": "Leave This Conversation", "inviteToGroup": "You have been invited to join a group:", - "pasteAddressToAddContact": "Paste a cwtch address, invitation or key bundle here to add a new conversation", - "tooltipAddContact": "Add a new contact or conversation", - "titleManageContacts": "Conversations", - "titleManageServers": "Manage Servers", "dateNever": "Never", "dateLastYear": "Last Year", "dateYesterday": "Yesterday", @@ -130,20 +140,22 @@ "descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.", "titleManageProfiles": "Manage Cwtch Profiles", "tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.", + "titleManageContacts": "Conversations", + "tooltipAddContact": "Add a new contact or conversation", "tooltipOpenSettings": "Open the settings pane", - "invalidImportString": "Invalid import string", "contactAlreadyExists": "Contact Already Exists", + "invalidImportString": "Invalid import string", "conversationSettings": "Conversation Settings", "enterCurrentPasswordForDelete": "Please enter current password to delete this profile.", "enableGroups": "Enable Group Chat", - "experimentsEnabled": "Enable Experiments", "localeIt": "Italiana", "localeEs": "Espanol", - "addListItem": "Add a New List Item", - "addNewItem": "Add a new item to the list", "todoPlaceholder": "Todo...", + "addNewItem": "Add a new item to the list", + "addListItem": "Add a New List Item", "newConnectionPaneTitle": "New Connection", "networkStatusOnline": "Online", + "networkStatusConnecting": "Connecting to network and contacts...", "networkStatusAttemptingTor": "Attempting to connect to Tor network", "networkStatusDisconnected": "Disconnected from the internet, check your connection", "viewGroupMembershipTooltip": "View Group Membership", @@ -153,6 +165,7 @@ "builddate": "Built on: %2", "version": "Version %1", "versionTor": "Version %1 with tor %2", + "experimentsEnabled": "Enable Experiments", "themeDark": "Dark", "themeLight": "Light", "settingTheme": "Theme", @@ -163,6 +176,7 @@ "localeFr": "Frances", "localeEn": "English", "settingLanguage": "Language", + "blockUnknownLabel": "Block Unknown Contacts", "zoomLabel": "Interface zoom (mostly affects text and button sizes)", "versionBuilddate": "Version: %1 Built on: %2", "cwtchSettingsTitle": "Cwtch Settings", @@ -186,11 +200,11 @@ "password1Label": "Password", "currentPasswordLabel": "Current Password", "yourDisplayName": "Your Display Name", + "profileOnionLabel": "Send this address to contacts you want to connect with", "noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted", "radioNoPassword": "Unencrypted (No password)", "radioUsePassword": "Password", "copiedToClipboardNotification": "Copied to Clipboard", - "copyBtn": "Copy", "editProfile": "Edit Profille", "newProfile": "New Profile", "defaultProfileName": "Alice", @@ -198,6 +212,11 @@ "editProfileTitle": "Edit Profile", "addProfileTitle": "Add new profile", "deleteBtn": "Delete", + "unblockBtn": "Unblock Contact", + "dontSavePeerHistory": "Delete History", + "savePeerHistoryDescription": "Determines whether to delete any history associated with the contact.", + "savePeerHistory": "Save History", + "blockBtn": "Block Contact", "saveBtn": "Save", "displayNameLabel": "Display Name", "addressLabel": "Address", @@ -210,18 +229,23 @@ "acceptGroupInviteLabel": "Do you want to accept the invitation to", "newGroupBtn": "Create new group", "copiedClipboardNotification": "Copied to clipboard", + "copyBtn": "Copy", + "peerOfflineMessage": "Contact is offline, messages can't be delivered right now", + "peerBlockedMessage": "Contact is blocked", "pendingLabel": "Pending", "acknowledgedLabel": "Acknowledged", "couldNotSendMsgError": "Could not send this message", "dmTooltip": "Click to DM", "membershipDescription": "Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.", "addListItemBtn": "Add Item", + "peerNotOnline": "Contact is offline. Applications cannot be used right now.", "searchList": "Search List", "update": "Update", "inviteBtn": "Invite", "inviteToGroupLabel": "Invite to group", "groupNameLabel": "Group name", "viewServerInfo": "Server Info", + "serverNotSynced": "Syncing New Messages (This can take some time)...", "serverSynced": "Synced", "serverConnectivityDisconnected": "Server Disconnected", "serverConnectivityConnected": "Server Connected", @@ -236,11 +260,13 @@ "cycleCatsDesktop": "Click to cycle category.\nRight-click to reset.", "cycleCatsAndroid": "Click to cycle category.\nLong-press to reset.", "blocked": "Blocked", + "pasteAddressToAddContact": "Paste a cwtch address, invitation or key bundle here to add a new conversation", "titlePlaceholder": "title...", "postNewBulletinLabel": "Post new bulletin", "newBulletinLabel": "New Bulletin", "joinGroup": "Join group", "createGroup": "Create group", + "addPeer": "Add Contact", "groupAddr": "Address", "invitation": "Invitation", "server": "Server", @@ -249,6 +275,7 @@ "peerAddress": "Address", "joinGroupTab": "Join a group", "createGroupTab": "Create a group", + "addPeerTab": "Add a contact", "createGroupBtn": "Create", "defaultGroupName": "Awesome Group", "createGroupTitle": "Create Group" diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index 137e8a2b..a548ca3a 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,6 +1,33 @@ { "@@locale": "pt", - "@@last_modified": "2021-11-11T01:02:08+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", "newMessagesLabel": "New Messages", "localeRU": "Russian", "copyServerKeys": "Copy keys", @@ -8,8 +35,8 @@ "fileCheckingStatus": "Checking download status", "fileInterrupted": "Interrupted", "fileSavedTo": "Saved to", - "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", "encryptedServerDescription": "Encrypting a server with a password protects it from other people who may also use this device. Encrypted servers cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", + "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", "deleteServerConfirmBtn": "Really delete server", "deleteServerSuccess": "Successfully deleted server", "enterCurrentPasswordForDeleteServer": "Please enter current password to delete this server", @@ -33,7 +60,6 @@ "editServerTitle": "Edit Server", "addServerTitle": "Add Server", "titleManageProfilesShort": "Profiles", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", "settingFileSharing": "File Sharing", "tooltipSendFile": "Send File", @@ -45,22 +71,10 @@ "downloadFileButton": "Download", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", - "profileOnionLabel": "Send this address to contacts you want to connect with", - "addPeerTab": "Add a contact", - "addPeer": "Add Contact", - "peerNotOnline": "Contact is offline. Applications cannot be used right now.", - "peerBlockedMessage": "Contact is blocked", - "peerOfflineMessage": "Contact is offline, messages can't be delivered right now", - "blockBtn": "Block Contact", - "savePeerHistory": "Save History", - "savePeerHistoryDescription": "Determines whether or not to delete any history associated with the contact.", - "dontSavePeerHistory": "Delete History", - "unblockBtn": "Unblock Contact", - "blockUnknownLabel": "Block Unknown Contacts", "blockUnknownConnectionsEnabledDescription": "Connections from unknown contacts are blocked. You can change this in Settings", - "networkStatusConnecting": "Connecting to network and contacts...", "showMessageButton": "Show Message", "blockedMessageMessage": "This message is from a profile you have blocked.", "placeholderEnterMessage": "Type a message...", @@ -84,7 +98,6 @@ "notificationNewMessageFromPeer": "New message from a contact!", "tooltipHidePassword": "Hide Password", "tooltipShowPassword": "Show Password", - "serverNotSynced": "Syncing New Messages (This can take some time)...", "groupInviteSettingsWarning": "You have been invited to join a group! Please enable the Group Chat Experiment in Settings to view this Invitation.", "shutdownCwtchAction": "Shutdown Cwtch", "shutdownCwtchDialog": "Are you sure you want to shutdown Cwtch? This will close all connections, and exit the application.", @@ -115,9 +128,6 @@ "reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.", "leaveGroup": "Leave This Conversation", "inviteToGroup": "You have been invited to join a group:", - "pasteAddressToAddContact": "… cole um endereço aqui para adicionar um contato…", - "tooltipAddContact": "Add a new contact or conversation", - "titleManageContacts": "Conversations", "titleManageServers": "Manage Servers", "dateNever": "Never", "dateLastYear": "Last Year", @@ -130,20 +140,22 @@ "descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.", "titleManageProfiles": "Manage Cwtch Profiles", "tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.", + "titleManageContacts": "Conversations", + "tooltipAddContact": "Add a new contact or conversation", "tooltipOpenSettings": "Open the settings pane", - "invalidImportString": "Invalid import string", "contactAlreadyExists": "Contact Already Exists", + "invalidImportString": "Invalid import string", "conversationSettings": "Conversation Settings", "enterCurrentPasswordForDelete": "Please enter current password to delete this profile.", "enableGroups": "Enable Group Chat", - "experimentsEnabled": "Enable Experiments", "localeIt": "Italiana", "localeEs": "Espanol", - "addListItem": "Adicionar Item à Lista", - "addNewItem": "Adicionar novo item à lista", "todoPlaceholder": "Afazer…", + "addNewItem": "Adicionar novo item à lista", + "addListItem": "Adicionar Item à Lista", "newConnectionPaneTitle": "New Connection", "networkStatusOnline": "Online", + "networkStatusConnecting": "Connecting to network and contacts...", "networkStatusAttemptingTor": "Attempting to connect to Tor network", "networkStatusDisconnected": "Disconnected from the internet, check your connection", "viewGroupMembershipTooltip": "View Group Membership", @@ -153,6 +165,7 @@ "builddate": "Built on: %2", "version": "Version %1", "versionTor": "Version %1 with tor %2", + "experimentsEnabled": "Enable Experiments", "themeDark": "Dark", "themeLight": "Light", "settingTheme": "Theme", @@ -163,6 +176,7 @@ "localeFr": "Frances", "localeEn": "English", "settingLanguage": "Language", + "blockUnknownLabel": "Block Unknown Contacts", "zoomLabel": "Zoom da interface (afeta principalmente tamanho de texto e botões)", "versionBuilddate": "Version: %1 Built on: %2", "cwtchSettingsTitle": "Configurações do Cwtch", @@ -186,11 +200,11 @@ "password1Label": "Password", "currentPasswordLabel": "Current Password", "yourDisplayName": "Your Display Name", + "profileOnionLabel": "Send this address to contacts you want to connect with", "noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted", "radioNoPassword": "Unencrypted (No password)", "radioUsePassword": "Password", "copiedToClipboardNotification": "Copiado", - "copyBtn": "Copiar", "editProfile": "Edit Profille", "newProfile": "New Profile", "defaultProfileName": "Alice", @@ -198,6 +212,11 @@ "editProfileTitle": "Edit Profile", "addProfileTitle": "Add new profile", "deleteBtn": "Deletar", + "unblockBtn": "Unblock Contact", + "dontSavePeerHistory": "Delete History", + "savePeerHistoryDescription": "Determines whether to delete any history associated with the contact.", + "savePeerHistory": "Save History", + "blockBtn": "Block Contact", "saveBtn": "Salvar", "displayNameLabel": "Nome de Exibição", "addressLabel": "Endereço", @@ -210,18 +229,23 @@ "acceptGroupInviteLabel": "Você quer aceitar o convite para", "newGroupBtn": "Criar novo grupo", "copiedClipboardNotification": "Copiado", + "copyBtn": "Copiar", + "peerOfflineMessage": "Contact is offline, messages can't be delivered right now", + "peerBlockedMessage": "Contact is blocked", "pendingLabel": "Pendente", "acknowledgedLabel": "Confirmada", "couldNotSendMsgError": "Não deu para enviar esta mensagem", "dmTooltip": "Clique para DM", "membershipDescription": "A lista abaixo é de usuários que enviaram mensagens ao grupo. Essa lista pode não refletir todos os usuários que têm acesso ao grupo.", "addListItemBtn": "Add Item", + "peerNotOnline": "Contact is offline. Applications cannot be used right now.", "searchList": "Search List", "update": "Update", "inviteBtn": "Convidar", "inviteToGroupLabel": "Convidar ao grupo", "groupNameLabel": "Nome do grupo", "viewServerInfo": "Server Info", + "serverNotSynced": "Syncing New Messages (This can take some time)...", "serverSynced": "Synced", "serverConnectivityDisconnected": "Server Disconnected", "serverConnectivityConnected": "Server Connected", @@ -236,11 +260,13 @@ "cycleCatsDesktop": "Click to cycle category.\nRight-click to reset.", "cycleCatsAndroid": "Click to cycle category.\nLong-press to reset.", "blocked": "Blocked", + "pasteAddressToAddContact": "… cole um endereço aqui para adicionar um contato…", "titlePlaceholder": "título…", "postNewBulletinLabel": "Postar novo boletim", "newBulletinLabel": "Novo Boletim", "joinGroup": "Join group", "createGroup": "Create group", + "addPeer": "Add Contact", "groupAddr": "Address", "invitation": "Invitation", "server": "Server", @@ -249,6 +275,7 @@ "peerAddress": "Address", "joinGroupTab": "Join a group", "createGroupTab": "Create a group", + "addPeerTab": "Add a contact", "createGroupBtn": "Criar", "defaultGroupName": "Grupo incrível", "createGroupTitle": "Criar Grupo" diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index b637956a..8751074d 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,14 +1,52 @@ { "@@locale": "ru", - "@@last_modified": "2021-11-10T18:47:30+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "saveBtn": "Сохранить", + "profileOnionLabel": "Send this address to contacts you want to connect with", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", + "newMessagesLabel": "New Messages", + "networkStatusOnline": "В сети", + "copiedToClipboardNotification": "Скопировано в буфер обмена", + "defaultProfileName": "Алиса", + "deleteBtn": "Удалить", + "bulletinsBtn": "Бюллетень", + "groupNameLabel": "Имя группы", + "serverLabel": "Сервер", + "copyBtn": "Копировать", "localeRU": "Russian", "copyServerKeys": "Копировать ключи", "verfiyResumeButton": "Проверить\/продолжить", "fileCheckingStatus": "Проверка статуса загрузки", "fileInterrupted": "Прервано", "fileSavedTo": "Сохранить в", - "plainServerDescription": "Мы настоятельно рекомендуем защитить свой сервер Cwtch паролем. Если Вы этого не сделаете, то любой у кого окажется доступ к серверу, сможет получить доступ к информации на этом сервере включая конфиденциальные криптографические ключи.", "encryptedServerDescription": "Шифрование сервера паролем защитит его от других людей у которых может оказаться доступ к этому устройству, включая Onion адрес сервера. Зашифрованный сервер нельзя расшифровать, пока не будет введен правильный пароль разблокировки.", + "plainServerDescription": "Мы настоятельно рекомендуем защитить свой сервер Cwtch паролем. Если Вы этого не сделаете, то любой у кого окажется доступ к серверу, сможет получить доступ к информации на этом сервере включая конфиденциальные криптографические ключи.", "deleteServerConfirmBtn": "Точно удалить сервер?", "deleteServerSuccess": "Сервер успешно удален", "enterCurrentPasswordForDeleteServer": "Пожалуйста, введите пароль сервера, чтобы удалить его", @@ -32,7 +70,6 @@ "editServerTitle": "Изменить сервер", "addServerTitle": "Добавить сервер", "titleManageProfilesShort": "Профили", - "descriptionStreamerMode": "При включении этого параметра, внешний вид некоторых элементов становится более приватным, скрывая длинные Onion адреса и адреса контактов, оставляя только заданные имена", "descriptionFileSharing": "Данная функция позволяет обмениваться файлами напрямую с контактами и группами в Cwtch. Отправляемый файл будет напрямую скачиваться с вашего устройства через Cwtch.", "settingFileSharing": "Передача файлов", "tooltipSendFile": "Отправить файл", @@ -44,22 +81,10 @@ "downloadFileButton": "Загрузить", "openFolderButton": "Открыть папку", "retrievingManifestMessage": "Получение информации о файле...", + "descriptionStreamerMode": "При включении этого параметра, внешний вид некоторых элементов становится более приватным, скрывая длинные Onion адреса и адреса контактов, оставляя только заданные имена", "streamerModeLabel": "Режим презентации", "archiveConversation": "Отправить чат в архив", - "profileOnionLabel": "Send this address to contacts you want to connect with", - "addPeerTab": "Добавить контакт", - "addPeer": "Добавить контакт", - "peerNotOnline": "Контакт не в сети. Вы не можете связаться с ним пока он не появиться в сети.", - "peerBlockedMessage": "Контакт заблокирован", - "peerOfflineMessage": "Контакт не в сети, сообщения не могут быть отправлены", - "blockBtn": "Заблокировать контакт", - "savePeerHistory": "Хранить исторую", - "savePeerHistoryDescription": "Определяет политуку хранения или удаления переписки с данным контактом.", - "dontSavePeerHistory": "Удалить историю", - "unblockBtn": "Разблокировать контакт", - "blockUnknownLabel": "Блокировать неизвестные контакты", "blockUnknownConnectionsEnabledDescription": "Соединения от неизвестных контактов блокируются. Данный параметр можно изменить в настройках", - "networkStatusConnecting": "Подключение к сети и контактам...", "showMessageButton": "Показать сообщения", "blockedMessageMessage": "Это сообщение из заблокированного вами профиля.", "placeholderEnterMessage": "Написать сообщение...", @@ -83,7 +108,6 @@ "notificationNewMessageFromPeer": "Новое сообщение от контакта!", "tooltipHidePassword": "Скрыть пароль", "tooltipShowPassword": "Показать пароль", - "serverNotSynced": "Синхронизация новых сообщений (это может занять некоторое время)...", "groupInviteSettingsWarning": "Вас пригласили присоединиться к группе! Пожалуйста, включите экспериментальную функцию групповые чаты в Настройках, чтобы просмотреть это приглашение.", "shutdownCwtchAction": "Выключить Cwtch", "shutdownCwtchDialog": "Вы уверены, что хотите выключить Cwtch? Это приведет к закрытию всех подключений и выходу из приложения.", @@ -114,9 +138,6 @@ "reallyLeaveThisGroupPrompt": "Вы уверены, что хотите закончить этот разговор? Все сообщения будут удалены.", "leaveGroup": "Да, оставить этот чат", "inviteToGroup": "Вас пригласили присоединиться к группе:", - "pasteAddressToAddContact": "Вставьте адрес cwtch, приглашение или пакет ключей здесь, чтобы добавить их в контакты", - "tooltipAddContact": "Добавление нового контакта или разговора", - "titleManageContacts": "Разговоры", "titleManageServers": "Управление серверами", "dateNever": "Никогда", "dateLastYear": "Прошлый год", @@ -129,20 +150,21 @@ "descriptionExperiments": "Экспериментальные функции Cwtch это необязательные дополнительные функции, которые добавляют некоторые возможности, но не имеют такой же устойчивости к метаданным как если бы вы общались через традиционный част 1 на 1..", "titleManageProfiles": "Управление профилями Cwtch", "tooltipUnlockProfiles": "Разблокировать зашифрованные профили, введя их пароль.", + "titleManageContacts": "Разговоры", + "tooltipAddContact": "Добавление нового контакта или разговора", "tooltipOpenSettings": "Откройте панель настроек", - "invalidImportString": "Недействительная строка импорта", "contactAlreadyExists": "Контакт уже существует", + "invalidImportString": "Недействительная строка импорта", "conversationSettings": "Настройки чата", "enterCurrentPasswordForDelete": "Пожалуйста, введите текущий пароль, чтобы удалить этот профиль.", "enableGroups": "Включить Групповые чаты", - "experimentsEnabled": "Включить Экспериментальные функции", "localeIt": "Итальянский", "localeEs": "Испанский", - "addListItem": "Добавить новый элемент", - "addNewItem": "Добавить новый элемент в список", "todoPlaceholder": "Выполняю...", + "addNewItem": "Добавить новый элемент в список", + "addListItem": "Добавить новый элемент", "newConnectionPaneTitle": "Новое соединение", - "networkStatusOnline": "В сети", + "networkStatusConnecting": "Подключение к сети и контактам...", "networkStatusAttemptingTor": "Попытка подключиться к сети Tor", "networkStatusDisconnected": "Нет сети. Проверьте подключение к интернету", "viewGroupMembershipTooltip": "Просмотр членства в группе", @@ -152,6 +174,7 @@ "builddate": "Построен на: %2", "version": "Версия %1", "versionTor": "Версия %1 c tor %2", + "experimentsEnabled": "Включить Экспериментальные функции", "themeDark": "Темная", "themeLight": "Светлая", "settingTheme": "Тема", @@ -162,6 +185,7 @@ "localeFr": "Французский", "localeEn": "Английский", "settingLanguage": "Язык", + "blockUnknownLabel": "Блокировать неизвестные контакты", "zoomLabel": "Масштаб интерфейса (в основном влияет на размеры текста и кнопок)", "versionBuilddate": "Версия: %1 Сборка от: %2", "cwtchSettingsTitle": "Настройки Cwtch", @@ -188,20 +212,19 @@ "noPasswordWarning": "Отсутствие пароля в этой учетной записи означает, что все данные, хранящиеся локально, не будут зашифрованы", "radioNoPassword": "Незашифрованный (без пароля)", "radioUsePassword": "Пароль", - "copiedToClipboardNotification": "Скопировано в буфер обмена", - "copyBtn": "Копировать", "editProfile": "Изменить профиль", "newProfile": "Новый профиль", - "defaultProfileName": "Алиса", "profileName": "Отображаемое имя", "editProfileTitle": "Изменить профиль", "addProfileTitle": "Добавить новый профиль", - "deleteBtn": "Удалить", - "saveBtn": "Сохранить", + "unblockBtn": "Разблокировать контакт", + "dontSavePeerHistory": "Удалить историю", + "savePeerHistoryDescription": "Определяет политуку хранения или удаления переписки с данным контактом.", + "savePeerHistory": "Хранить исторую", + "blockBtn": "Заблокировать контакт", "displayNameLabel": "Отображаемое имя", "addressLabel": "Адрес", "puzzleGameBtn": "Puzzle Game", - "bulletinsBtn": "Бюллетень", "listsBtn": "Списки", "chatBtn": "Чат", "rejectGroupBtn": "Отклонить", @@ -209,24 +232,26 @@ "acceptGroupInviteLabel": "Хотите принять приглашение в", "newGroupBtn": "Создать новую группу", "copiedClipboardNotification": "Скопировано в буфер обмена", + "peerOfflineMessage": "Контакт не в сети, сообщения не могут быть отправлены", + "peerBlockedMessage": "Контакт заблокирован", "pendingLabel": "Ожидаемый", "acknowledgedLabel": "Отправлено", "couldNotSendMsgError": "Не удалось отправить это сообщение", "dmTooltip": "Нажмите, чтобы перейти в DM", "membershipDescription": "Ниже приведен список пользователей, отправивших сообщения группе. Этот список может не отражать всех пользователей, имеющих доступ к группе.", "addListItemBtn": "Добавить элемент", + "peerNotOnline": "Контакт не в сети. Вы не можете связаться с ним пока он не появиться в сети.", "searchList": "Список поиска", "update": "Обновить", "inviteBtn": "Пригласить", "inviteToGroupLabel": "Пригласить в группу", - "groupNameLabel": "Имя группы", "viewServerInfo": "Информация о сервере", + "serverNotSynced": "Синхронизация новых сообщений (это может занять некоторое время)...", "serverSynced": "Синхронизировано", "serverConnectivityDisconnected": "Сервер отключен", "serverConnectivityConnected": "Сервер подключен", "serverInfo": "Информация о сервере", "invitationLabel": "Приглашение", - "serverLabel": "Сервер", "search": "Поиск...", "cycleColoursDesktop": "Нажмите, чтобы переключать цвета.\nПравый клик чтобы сбросить.", "cycleColoursAndroid": "Нажмите, чтобы переключать цвета.\nНажмите и удерживайте, чтобы сбросить.", @@ -235,11 +260,13 @@ "cycleCatsDesktop": "Нажмите, чтобы просмотреть категории.\nПравый клик чтобы сбросить.", "cycleCatsAndroid": "Нажмите, чтобы просмотреть категории.\nНажмите и удерживайте, чтобы сбросить.", "blocked": "Заблокировано", + "pasteAddressToAddContact": "Вставьте адрес cwtch, приглашение или пакет ключей здесь, чтобы добавить их в контакты", "titlePlaceholder": "заговолок...", "postNewBulletinLabel": "Опубликовать новый бюллетень", "newBulletinLabel": "Новый бюллетень", "joinGroup": "Вступить в группу", "createGroup": "Создать группу", + "addPeer": "Добавить контакт", "groupAddr": "Адрес", "invitation": "Приглашение", "server": "Сервер", @@ -248,6 +275,7 @@ "peerAddress": "Адрес", "joinGroupTab": "Присоединиться к группе", "createGroupTab": "Создать группу", + "addPeerTab": "Добавить контакт", "createGroupBtn": "Создать", "defaultGroupName": "Замечательная группа", "createGroupTitle": "Создать группу" diff --git a/lib/main.dart b/lib/main.dart index 9ab2ad4b..3c3f27bd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:cwtch/config.dart'; import 'package:cwtch/notification_manager.dart'; +import 'package:cwtch/themes/cwtch.dart'; import 'package:cwtch/views/messageview.dart'; import 'package:cwtch/widgets/rightshiftfixer.dart'; import 'package:flutter/foundation.dart'; @@ -21,10 +22,10 @@ import 'models/servers.dart'; import 'views/profilemgrview.dart'; import 'views/splashView.dart'; import 'dart:io' show Platform, exit; -import 'opaque.dart'; +import 'themes/opaque.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var globalSettings = Settings(Locale("en", ''), OpaqueDark()); +var globalSettings = Settings(Locale("en", ''), CwtchDark()); var globalErrorHandler = ErrorHandler(); var globalTorStatus = TorStatus(); var globalAppState = AppState(); diff --git a/lib/main_test.dart b/lib/main_test.dart index a2551891..6ba3edd8 100644 --- a/lib/main_test.dart +++ b/lib/main_test.dart @@ -5,7 +5,7 @@ import 'package:cwtch/errorHandler.dart'; import 'package:cwtch/settings.dart'; import 'licenses.dart'; import 'main.dart'; -import 'opaque.dart'; +import 'themes/opaque.dart'; import 'dart:convert'; import 'dart:io'; @@ -14,7 +14,7 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:glob/glob.dart'; -var globalSettings = Settings(Locale("en", ''), OpaqueDark()); +var globalSettings = Settings(Locale("en", ''), CwtchDark()); var globalErrorHandler = ErrorHandler(); void main() { diff --git a/lib/model.dart b/lib/model.dart index 87ac2f36..2106895b 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -120,6 +120,7 @@ class ProfileListState extends ChangeNotifier { } class ContactListState extends ChangeNotifier { + ProfileServerListState? servers; List _contacts = []; String _filter = ""; int get num => _contacts.length; @@ -131,6 +132,10 @@ class ContactListState extends ChangeNotifier { notifyListeners(); } + void connectServers(ProfileServerListState servers) { + this.servers = servers; + } + List filteredList() { if (!isFiltered) return contacts; return _contacts.where((ContactInfoState c) => c.onion.toLowerCase().startsWith(_filter) || (c.nickname.toLowerCase().contains(_filter))).toList(); @@ -138,11 +143,20 @@ class ContactListState extends ChangeNotifier { void addAll(Iterable newContacts) { _contacts.addAll(newContacts); + servers?.clearGroups(); + _contacts.forEach((contact) { + if (contact.isGroup) { + servers?.addGroup(contact); + } + }); notifyListeners(); } void add(ContactInfoState newContact) { _contacts.add(newContact); + if (newContact.isGroup) { + servers?.addGroup(newContact); + } notifyListeners(); } @@ -213,8 +227,8 @@ class ContactListState extends ChangeNotifier { } class ProfileInfoState extends ChangeNotifier { - ContactListState _contacts = ContactListState(); ProfileServerListState _servers = ProfileServerListState(); + ContactListState _contacts = ContactListState(); final String onion; String _nickname = ""; String _imagePath = ""; @@ -242,7 +256,11 @@ class ProfileInfoState extends ChangeNotifier { this._online = online; this._encrypted = encrypted; + _contacts.connectServers(this._servers); + if (contactsJson != null && contactsJson != "" && contactsJson != "null") { + this.replaceServers(serversJson); + List contacts = jsonDecode(contactsJson); this._contacts.addAll(contacts.map((contact) { return ContactInfoState(this.onion, contact["identifier"], contact["onion"], @@ -264,8 +282,6 @@ class ProfileInfoState extends ChangeNotifier { this._contacts.updateLastMessageTime(this._contacts._contacts.first.identifier, this._contacts._contacts.first.lastMessageTime); } } - - this.replaceServers(serversJson); } // Parse out the server list json into our server info state struct... @@ -274,15 +290,22 @@ class ProfileInfoState extends ChangeNotifier { List servers = jsonDecode(serversJson); this._servers.replace(servers.map((server) { // TODO Keys... - return RemoteServerInfoState(onion: server["onion"], status: server["status"]); + return RemoteServerInfoState(onion: server["onion"], identifier: server["identifier"], description: server["description"], status: server["status"]); })); + + this._contacts.contacts.forEach((contact) { + if (contact.isGroup) { + _servers.addGroup(contact); + } + }); + notifyListeners(); } } // void updateServerStatusCache(String server, String status) { - this._servers.updateServerCache(server, status); + this._servers.updateServerState(server, status); notifyListeners(); } diff --git a/lib/models/profileservers.dart b/lib/models/profileservers.dart index cb86d392..4b868b95 100644 --- a/lib/models/profileservers.dart +++ b/lib/models/profileservers.dart @@ -1,3 +1,4 @@ +import 'package:cwtch/model.dart'; import 'package:flutter/material.dart'; class ProfileServerListState extends ChangeNotifier { @@ -6,6 +7,7 @@ class ProfileServerListState extends ChangeNotifier { void replace(Iterable newServers) { _servers.clear(); _servers.addAll(newServers); + resort(); notifyListeners(); } @@ -14,23 +16,78 @@ class ProfileServerListState extends ChangeNotifier { return idx >= 0 ? _servers[idx] : null; } - void updateServerCache(String onion, String status) { + void updateServerState(String onion, String status) { int idx = _servers.indexWhere((element) => element.onion == onion); if (idx >= 0) { - _servers[idx] = RemoteServerInfoState(onion: onion, status: status); + _servers[idx].status = status; } else { print("Tried to update server cache without a starting state...this is probably an error"); } + resort(); notifyListeners(); } + void resort() { + _servers.sort((RemoteServerInfoState a, RemoteServerInfoState b) { + // return -1 = a first in list + // return 1 = b first in list + + // online v offline + if (a.status == "Synced" && b.status != "Synced") { + return -1; + } else if (a.status != "Synced" && b.status == "Synced") { + return 1; + } + + // num of groups + if (a.groups.length > b.groups.length) { + return -1; + } else if (b.groups.length > a.groups.length) { + return 1; + } + + return 0; + }); + } + + void clearGroups() { + _servers.map((server) => server.clearGroups()); + } + + void addGroup(ContactInfoState group) { + int idx = _servers.indexWhere((element) => element.onion == group.server); + if (idx >= 0) { + _servers[idx].addGroup(group); + } + } + List get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier } class RemoteServerInfoState extends ChangeNotifier { final String onion; - final String status; + final int identifier; + String status; + String description; + List _groups = []; + + RemoteServerInfoState({required this.onion, required this.identifier, required this.description, required this.status}); + + void updateDescription(String newDescription) { + this.description = newDescription; + notifyListeners(); + } + + void clearGroups() { + _groups = []; + } + + void addGroup(ContactInfoState group) { + _groups.add(group); + notifyListeners(); + } + + List get groups => _groups.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier - RemoteServerInfoState({required this.onion, required this.status}); } diff --git a/lib/models/servers.dart b/lib/models/servers.dart index 2850668b..cd059cbf 100644 --- a/lib/models/servers.dart +++ b/lib/models/servers.dart @@ -39,11 +39,34 @@ class ServerListState extends ChangeNotifier { notifyListeners(); } + void updateServerStats(String onion, int newTotalMessages, int newConnections) { + var server = getServer(onion); + if (server != null) { + server.setStats(newTotalMessages, newConnections); + resort(); + notifyListeners(); + } + } + void delete(String onion) { _servers.removeWhere((element) => element.onion == onion); notifyListeners(); } + void resort() { + _servers.sort((ServerInfoState a, ServerInfoState b) { + // return -1 = a first in list + // return 1 = b first in list + if (a.totalMessages > b.totalMessages) { + return -1; + } else if (b.totalMessages > a.totalMessages) { + return 1; + } + + return 0; + }); + } + List get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier } @@ -55,6 +78,8 @@ class ServerInfoState extends ChangeNotifier { bool running; bool autoStart; bool isEncrypted; + int totalMessages = 0; + int connections = 0; ServerInfoState({required this.onion, required this.serverBundle, required this.running, required this.description, required this.autoStart, required this.isEncrypted}); @@ -72,4 +97,10 @@ class ServerInfoState extends ChangeNotifier { description = val; notifyListeners(); } + + void setStats(int newTotalMessages, int newConnections) { + totalMessages = newTotalMessages; + connections = newConnections; + notifyListeners(); + } } diff --git a/lib/opaque.dart b/lib/opaque.dart deleted file mode 100644 index fc984217..00000000 --- a/lib/opaque.dart +++ /dev/null @@ -1,1455 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND AS CHANGES WILL BE OVERRIDDEN. -// TO EDIT THE THEME, SEE https://git.openprivacy.ca/openprivacy/opaque/ -// FOR HOW THIS FILE IS GENERATED, SEE ../regenerate_opaque_theme.sh - -import 'dart:ui'; -import 'dart:core'; - -import 'package:flutter/material.dart'; -import 'package:cwtch/settings.dart'; - -abstract class OpaqueThemeType { - static final Color red = Color(0xFFFF0000); - - String identifier() { - return "dummy"; - } - - Color backgroundMainColor() { - return red; - } - - Color backgroundPaneColor() { - return red; - } - - Color backgroundHilightElementColor() { - return red; - } - - Color dividerColor() { - return red; - } - - Color mainTextColor() { - return red; - } - - Color altTextColor() { - return red; - } - - Color hilightElementTextColor() { - return red; - } - - Color defaultButtonColor() { - return red; - } - - Color defaultButtonActiveColor() { - return red; - } - - Color defaultButtonTextColor() { - return red; - } - - Color defaultButtonDisabledColor() { - return red; - } - - Color defaultButtonDisabledTextColor() { - return red; - } - - Color altButtonColor() { - return red; - } - - Color altButtonTextColor() { - return red; - } - - Color altButtonDisabledColor() { - return red; - } - - Color altButtonDisabledTextColor() { - return red; - } - - Color textfieldBackgroundColor() { - return red; - } - - Color textfieldBorderColor() { - return red; - } - - Color textfieldTextColor() { - return red; - } - - Color textfieldErrorColor() { - return red; - } - - Color textfieldButtonColor() { - return red; - } - - Color textfieldButtonTextColor() { - return red; - } - - Color scrollbarDefaultColor() { - return red; - } - - Color scrollbarActiveColor() { - return red; - } - - Color portraitOnlineBorderColor() { - return red; - } - - Color portraitOnlineBackgroundColor() { - return red; - } - - Color portraitOnlineTextColor() { - return red; - } - - Color portraitConnectingBorderColor() { - return red; - } - - Color portraitConnectingBackgroundColor() { - return red; - } - - Color portraitConnectingTextColor() { - return red; - } - - Color portraitOfflineBorderColor() { - return red; - } - - Color portraitOfflineBackgroundColor() { - return red; - } - - Color portraitOfflineTextColor() { - return red; - } - - Color portraitBlockedBorderColor() { - return red; - } - - Color portraitBlockedBackgroundColor() { - return red; - } - - Color portraitBlockedTextColor() { - return red; - } - - Color portraitOnlineBadgeColor() { - return red; - } - - Color portraitOfflineBadgeColor() { - return red; - } - - Color portraitContactBadgeColor() { - return red; - } - - Color portraitContactBadgeTextColor() { - return red; - } - - Color portraitProfileBadgeColor() { - return red; - } - - Color portraitProfileBadgeTextColor() { - return red; - } - - Color portraitOverlayOfflineColor() { - return red; - } - - Color dropShadowColor() { - return red; - } - - Color dropShadowPaneColor() { - return red; - } - - Color toggleColor() { - return red; - } - - Color toggleOnColor() { - return red; - } - - Color toggleOffColor() { - return red; - } - - Color sliderButtonColor() { - return red; - } - - Color sliderBarLeftColor() { - return red; - } - - Color sliderBarRightColor() { - return red; - } - - Color boxCheckedColor() { - return red; - } - - Color toolbarIconColor() { - return red; - } - - Color toolbarMainColor() { - return red; - } - - Color toolbarAltColor() { - return red; - } - - Color statusbarDisconnectedInternetColor() { - return red; - } - - Color statusbarDisconnectedInternetFontColor() { - return red; - } - - Color statusbarDisconnectedTorFontColor() { - return red; - } - - Color statusbarDisconnectedTorColor() { - return red; - } - - Color statusbarConnectingColor() { - return red; - } - - Color statusbarConnectingFontColor() { - return red; - } - - Color statusbarOnlineColor() { - return red; - } - - Color statusbarOnlineFontColor() { - return red; - } - - Color chatOverlayWarningTextColor() { - return red; - } - - Color messageFromMeBackgroundColor() { - return red; - } - - Color messageFromMeTextColor() { - return red; - } - - Color messageFromOtherBackgroundColor() { - return red; - } - - Color messageFromOtherTextColor() { - return red; - } - - Color messageStatusNormalColor() { - return red; - } - - Color messageStatusBlockedColor() { - return red; - } - - Color messageStatusBlockedTextColor() { - return red; - } - - Color messageStatusAlertColor() { - return red; - } - - Color messageStatusAlertTextColor() { - return red; - } - - // ... more to come - - // Sizes - - double contactOnionTextSize() { - return 18; - } -} - -class OpaqueDark extends OpaqueThemeType { - static final Color darkGreyPurple = Color(0xFF281831); - static final Color deepPurple = Color(0xFF422850); - static final Color mauvePurple = Color(0xFF8E64A5); - static final Color purple = Color(0xFFDFB9DE); - static final Color whitePurple = Color(0xFFE3DFE4); - static final Color softPurple = Color(0xFFFDF3FC); - static final Color pink = Color(0xFFE85DA1); - static final Color hotPink = Color(0xFFD01972); - static final Color lightGrey = Color(0xFF9E9E9E); - static final Color softGreen = Color(0xFFA0FFB0); - static final Color softRed = Color(0xFFFFA0B0); - - String identifier() { - return "dark"; - } - - Color backgroundMainColor() { - return darkGreyPurple; - } - - Color backgroundPaneColor() { - return darkGreyPurple; - } - - Color backgroundHilightElementColor() { - return deepPurple; - } - - Color dividerColor() { - return deepPurple; - } - - Color mainTextColor() { - return whitePurple; - } - - Color altTextColor() { - return mauvePurple; - } - - Color hilightElementTextColor() { - return purple; - } - - Color defaultButtonColor() { - return hotPink; - } - - Color defaultButtonActiveColor() { - return pink; - } - - Color defaultButtonTextColor() { - return whitePurple; - } - - Color defaultButtonDisabledColor() { - return lightGrey; - } - - Color defaultButtonDisabledTextColor() { - return darkGreyPurple; - } - - Color altButtonColor() { - return darkGreyPurple; - } - - Color altButtonTextColor() { - return purple; - } - - Color altButtonDisabledColor() { - return darkGreyPurple; - } - - Color altButtonDisabledTextColor() { - return purple; - } - - Color textfieldBackgroundColor() { - return deepPurple; - } - - Color textfieldBorderColor() { - return deepPurple; - } - - Color textfieldTextColor() { - return purple; - } - - Color textfieldErrorColor() { - return hotPink; - } - - Color textfieldButtonColor() { - return purple; - } - - Color textfieldButtonTextColor() { - return darkGreyPurple; - } - - Color scrollbarDefaultColor() { - return purple; - } - - Color scrollbarActiveColor() { - return hotPink; - } - - Color portraitOnlineBorderColor() { - return whitePurple; - } - - Color portraitOnlineBackgroundColor() { - return whitePurple; - } - - Color portraitOnlineTextColor() { - return whitePurple; - } - - Color portraitConnectingBorderColor() { - return purple; - } //mauvePurple - - Color portraitConnectingBackgroundColor() { - return purple; - } //darkGreyPurple - - Color portraitConnectingTextColor() { - return purple; - } - - Color portraitOfflineBorderColor() { - return purple; - } - - Color portraitOfflineBackgroundColor() { - return purple; - } - - Color portraitOfflineTextColor() { - return purple; - } - - Color portraitBlockedBorderColor() { - return lightGrey; - } - - Color portraitBlockedBackgroundColor() { - return lightGrey; - } - - Color portraitBlockedTextColor() { - return lightGrey; - } - - Color portraitOnlineBadgeColor() { - return softGreen; - } - - Color portraitOfflineBadgeColor() { - return softRed; - } - - Color portraitContactBadgeColor() { - return hotPink; - } - - Color portraitContactBadgeTextColor() { - return whitePurple; - } - - Color portraitProfileBadgeColor() { - return mauvePurple; - } - - Color portraitProfileBadgeTextColor() { - return darkGreyPurple; - } - - Color portraitOverlayOfflineColor() { - return mauvePurple; - } - - Color dropShadowColor() { - return mauvePurple; - } - - Color dropShadowPaneColor() { - return darkGreyPurple; - } - - Color toggleColor() { - return darkGreyPurple; - } - - Color toggleOnColor() { - return whitePurple; - } - - Color toggleOffColor() { - return deepPurple; - } - - Color sliderButtonColor() { - return whitePurple; - } - - Color sliderBarLeftColor() { - return mauvePurple; - } - - Color sliderBarRightColor() { - return mauvePurple; - } - - Color boxCheckedColor() { - return hotPink; - } - - Color toolbarIconColor() { - return whitePurple; - } - - Color toolbarMainColor() { - return darkGreyPurple; - } - - Color toolbarAltColor() { - return deepPurple; - } - - Color statusbarDisconnectedInternetColor() { - return whitePurple; - } - - Color statusbarDisconnectedInternetFontColor() { - return deepPurple; - } - - Color statusbarDisconnectedTorColor() { - return darkGreyPurple; - } - - Color statusbarDisconnectedTorFontColor() { - return whitePurple; - } - - Color statusbarConnectingColor() { - return deepPurple; - } - - Color statusbarConnectingFontColor() { - return whitePurple; - } - - Color statusbarOnlineColor() { - return mauvePurple; - } - - Color statusbarOnlineFontColor() { - return whitePurple; - } - - Color chatOverlayWarningTextColor() { - return purple; - } - - Color messageFromMeBackgroundColor() { - return mauvePurple; - } - - Color messageFromMeTextColor() { - return whitePurple; - } - - Color messageFromOtherBackgroundColor() { - return deepPurple; - } - - Color messageFromOtherTextColor() { - return whitePurple; - } - - Color messageStatusNormalColor() { - return deepPurple; - } - - Color messageStatusBlockedColor() { - return lightGrey; - } - - Color messageStatusBlockedTextColor() { - return whitePurple; - } - - Color messageStatusAlertColor() { - return mauvePurple; - } - - Color messageStatusAlertTextColor() { - return whitePurple; - } -} - -class OpaqueLight extends OpaqueThemeType { - static final Color whitePurple = Color(0xFFFFFDFF); - static final Color softPurple = Color(0xFFFDF3FC); - static final Color purple = Color(0xFFDFB9DE); - static final Color brightPurple = Color(0xFFD1B0E0); - static final Color darkPurple = Color(0xFF350052); - static final Color greyPurple = Color(0xFF775F84); - static final Color pink = Color(0xFFE85DA1); - static final Color hotPink = Color(0xFFD01972); - static final Color lightGrey = Color(0xFFB3B6B3); - static final Color softGreen = Color(0xFFA0FFB0); - static final Color softRed = Color(0xFFFFA0B0); - - String identifier() { - return "light"; - } - - Color backgroundMainColor() { - return whitePurple; - } - - Color backgroundPaneColor() { - return softPurple; - } - - Color backgroundHilightElementColor() { - return softPurple; - } - - Color dividerColor() { - return purple; - } - - Color mainTextColor() { - return darkPurple; - } - - Color altTextColor() { - return purple; - } - - Color hilightElementTextColor() { - return darkPurple; - } - - Color defaultButtonColor() { - return hotPink; - } - - Color defaultButtonActiveColor() { - return pink; - } - - Color defaultButtonTextColor() { - return whitePurple; - } - - Color defaultButtonDisabledColor() { - return lightGrey; - } - - Color defaultButtonDisabledTextColor() { - return whitePurple; - } - - Color altButtonColor() { - return whitePurple; - } - - Color altButtonTextColor() { - return purple; - } - - Color altButtonDisabledColor() { - return softPurple; - } - - Color altButtonDisabledTextColor() { - return purple; - } - - Color textfieldBackgroundColor() { - return purple; - } - - Color textfieldBorderColor() { - return purple; - } - - Color textfieldTextColor() { - return purple; - } - - Color textfieldErrorColor() { - return hotPink; - } - - Color textfieldButtonColor() { - return hotPink; - } - - Color textfieldButtonTextColor() { - return whitePurple; - } - - Color scrollbarDefaultColor() { - return darkPurple; - } - - Color scrollbarActiveColor() { - return hotPink; - } - - Color portraitOnlineBorderColor() { - return greyPurple; - } - - Color portraitOnlineBackgroundColor() { - return greyPurple; - } - - Color portraitOnlineTextColor() { - return darkPurple; - } - - Color portraitConnectingBorderColor() { - return greyPurple; - } - - Color portraitConnectingBackgroundColor() { - return greyPurple; - } - - Color portraitConnectingTextColor() { - return greyPurple; - } - - Color portraitOfflineBorderColor() { - return greyPurple; - } //purple - - Color portraitOfflineBackgroundColor() { - return greyPurple; - } //purple - - Color portraitOfflineTextColor() { - return greyPurple; - } //purple - - Color portraitBlockedBorderColor() { - return lightGrey; - } - - Color portraitBlockedBackgroundColor() { - return lightGrey; - } - - Color portraitBlockedTextColor() { - return lightGrey; - } - - Color portraitOnlineBadgeColor() { - return softGreen; - } - - Color portraitOfflineBadgeColor() { - return softRed; - } - - Color portraitContactBadgeColor() { - return hotPink; - } - - Color portraitContactBadgeTextColor() { - return whitePurple; - } - - Color portraitProfileBadgeColor() { - return brightPurple; - } - - Color portraitProfileBadgeTextColor() { - return whitePurple; - } - - Color portraitOverlayOfflineColor() { - return whitePurple; - } - - Color dropShadowColor() { - return purple; - } - - Color dropShadowPaneColor() { - return purple; - } - - Color toggleColor() { - return whitePurple; - } - - Color toggleOnColor() { - return hotPink; - } - - Color toggleOffColor() { - return purple; - } - - Color sliderButtonColor() { - return pink; - } - - Color sliderBarLeftColor() { - return purple; - } - - Color sliderBarRightColor() { - return purple; - } - - Color boxCheckedColor() { - return darkPurple; - } - - Color toolbarIconColor() { - return darkPurple; - } - - Color toolbarMainColor() { - return whitePurple; - } - - Color toolbarAltColor() { - return softPurple; - } - - Color statusbarDisconnectedInternetColor() { - return softPurple; - } - - Color statusbarDisconnectedInternetFontColor() { - return darkPurple; - } - - Color statusbarDisconnectedTorColor() { - return purple; - } - - Color statusbarDisconnectedTorFontColor() { - return darkPurple; - } - - Color statusbarConnectingColor() { - return greyPurple; - } - - Color statusbarConnectingFontColor() { - return whitePurple; - } - - Color statusbarOnlineColor() { - return darkPurple; - } - - Color statusbarOnlineFontColor() { - return whitePurple; - } - - Color chatOverlayWarningTextColor() { - return purple; - } - - Color messageFromMeBackgroundColor() { - return brightPurple; - } - - Color messageFromMeTextColor() { - return mainTextColor(); - } - - Color messageFromOtherBackgroundColor() { - return purple; - } - - Color messageFromOtherTextColor() { - return darkPurple; - } - - Color messageStatusNormalColor() { - return purple; - } - - Color messageStatusBlockedColor() { - return lightGrey; - } - - Color messageStatusBlockedTextColor() { - return whitePurple; - } - - Color messageStatusAlertColor() { - return hotPink; - } - - Color messageStatusAlertTextColor() { - return whitePurple; - } -} - -ThemeData mkThemeData(Settings opaque) { - return ThemeData( - visualDensity: VisualDensity.adaptivePlatformDensity, - primarySwatch: Colors.red, - primaryIconTheme: IconThemeData( - color: opaque.current().mainTextColor(), - ), - primaryColor: opaque.current().backgroundMainColor(), - canvasColor: opaque.current().backgroundPaneColor(), - backgroundColor: opaque.current().backgroundMainColor(), - highlightColor: opaque.current().hilightElementTextColor(), - iconTheme: IconThemeData( - color: opaque.current().toolbarIconColor(), - ), - cardColor: opaque.current().backgroundMainColor(), - appBarTheme: AppBarTheme( - backgroundColor: opaque.current().backgroundPaneColor(), - iconTheme: IconThemeData( - color: opaque.current().mainTextColor(), - ), - titleTextStyle: TextStyle( - color: opaque.current().mainTextColor(), - ), - actionsIconTheme: IconThemeData( - color: opaque.current().mainTextColor(), - )), - bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor()), - textButtonTheme: TextButtonThemeData( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor()), - foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor()), - overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor()), - padding: MaterialStateProperty.all(EdgeInsets.all(20))), - ), - elevatedButtonTheme: ElevatedButtonThemeData( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor() : opaque.current().defaultButtonColor()), - foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor()), - overlayColor: MaterialStateProperty.resolveWith((states) => (states.contains(MaterialState.pressed) && states.contains(MaterialState.hovered)) - ? opaque.current().defaultButtonActiveColor() - : states.contains(MaterialState.disabled) - ? opaque.current().defaultButtonDisabledColor() - : null), - enableFeedback: true, - splashFactory: InkRipple.splashFactory, - padding: MaterialStateProperty.all(EdgeInsets.all(20)), - shape: MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(18.0), - )), - ), - ), - scrollbarTheme: ScrollbarThemeData( - isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarActiveColor()), trackColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor())), - tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor()))), - dialogTheme: DialogTheme( - backgroundColor: opaque.current().backgroundPaneColor(), - titleTextStyle: TextStyle(color: opaque.current().mainTextColor()), - contentTextStyle: TextStyle(color: opaque.current().mainTextColor())), - textTheme: TextTheme( - headline1: TextStyle(color: opaque.current().mainTextColor()), - headline2: TextStyle(color: opaque.current().mainTextColor()), - headline3: TextStyle(color: opaque.current().mainTextColor()), - headline4: TextStyle(color: opaque.current().mainTextColor()), - headline5: TextStyle(color: opaque.current().mainTextColor()), - headline6: TextStyle(color: opaque.current().mainTextColor()), - bodyText1: TextStyle(color: opaque.current().mainTextColor()), - bodyText2: TextStyle(color: opaque.current().mainTextColor()), - subtitle1: TextStyle(color: opaque.current().mainTextColor()), - subtitle2: TextStyle(color: opaque.current().mainTextColor()), - caption: TextStyle(color: opaque.current().mainTextColor()), - button: TextStyle(color: opaque.current().mainTextColor()), - overline: TextStyle(color: opaque.current().mainTextColor())), - switchTheme: SwitchThemeData( - overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor()), - thumbColor: MaterialStateProperty.all(opaque.current().mainTextColor()), - trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor()), - ), - floatingActionButtonTheme: FloatingActionButtonThemeData( - backgroundColor: opaque.current().defaultButtonColor(), - hoverColor: opaque.current().defaultButtonActiveColor(), - enableFeedback: true, - splashColor: opaque.current().defaultButtonActiveColor()), - textSelectionTheme: TextSelectionThemeData( - cursorColor: opaque.current().defaultButtonActiveColor(), selectionColor: opaque.current().defaultButtonActiveColor(), selectionHandleColor: opaque.current().defaultButtonActiveColor()), - ); -} - -/* - -OpaqueThemeType _current = CwtchDark(); - -void setDark() { - _current = CwtchDark(); -} - -void setLight() { - _current = CwtchLight(); -} - -OpaqueThemeType current() { - if (_current == null) { - setDark(); - } - return _current; -} - -class Opaque extends OpaqueThemeType { - Color backgroundMainColor() { - return current().backgroundMainColor(); - } - - Color backgroundPaneColor() { - return current().backgroundPaneColor(); - } - - Color backgroundHilightElementColor() { - return current().backgroundHilightElementColor(); - } - - Color dividerColor() { - return current().dividerColor(); - } - - Color mainTextColor() { - return current().mainTextColor(); - } - - Color altTextColor() { - return current().altTextColor(); - } - - Color hilightElementTextColor() { - return current().hilightElementTextColor(); - } - - Color defaultButtonColor() { - return current().defaultButtonColor(); - } - - Color defaultButtonActiveColor() { - return current().defaultButtonActiveColor(); - } - - Color defaultButtonTextColor() { - return current().defaultButtonTextColor(); - } - - Color defaultButtonDisabledColor() { - return current().defaultButtonDisabledColor(); - } - - Color defaultButtonDisabledTextColor() { - return current().defaultButtonDisabledTextColor(); - } - - Color altButtonColor() { - return current().altButtonColor(); - } - - Color altButtonTextColor() { - return current().altButtonTextColor(); - } - - Color altButtonDisabledColor() { - return current().altButtonDisabledColor(); - } - - Color altButtonDisabledTextColor() { - return current().altButtonDisabledTextColor(); - } - - Color textfieldBackgroundColor() { - return current().textfieldBackgroundColor(); - } - - Color textfieldBorderColor() { - return current().textfieldBorderColor(); - } - - Color textfieldTextColor() { - return current().textfieldTextColor(); - } - - Color textfieldErrorColor() { - return current().textfieldErrorColor(); - } - - Color textfieldButtonColor() { - return current().textfieldButtonColor(); - } - - Color textfieldButtonTextColor() { - return current().textfieldButtonTextColor(); - } - - Color dropShadowColor() { - return current().dropShadowColor(); - } - - Color dropShadowPaneColor() { - return current().dropShadowPaneColor(); - } - - Color portraitOnlineBorderColor() { - return current().portraitOnlineBorderColor(); - } - - Color portraitOnlineBackgroundColor() { - return current().portraitOnlineBackgroundColor(); - } - - Color portraitOnlineTextColor() { - return current().portraitOnlineTextColor(); - } - - Color portraitConnectingBorderColor() { - return current().portraitConnectingBorderColor(); - } - - Color portraitConnectingBackgroundColor() { - return current().portraitConnectingBackgroundColor(); - } - - Color portraitConnectingTextColor() { - return current().portraitConnectingTextColor(); - } - - Color portraitOfflineBorderColor() { - return current().portraitOfflineBorderColor(); - } - - Color portraitOfflineBackgroundColor() { - return current().portraitOfflineBackgroundColor(); - } - - Color portraitOfflineTextColor() { - return current().portraitOfflineTextColor(); - } - - Color portraitBlockedBorderColor() { - return current().portraitBlockedBorderColor(); - } - - Color portraitBlockedBackgroundColor() { - return current().portraitBlockedBackgroundColor(); - } - - Color portraitBlockedTextColor() { - return current().portraitBlockedTextColor(); - } - - Color portraitOnlineBadgeColor() { - return current().portraitOnlineBadgeColor(); - } - - Color portraitOfflineBadgeColor() { - return current().portraitOfflineBadgeColor(); - } - - Color portraitContactBadgeColor() { - return current().portraitContactBadgeColor(); - } - - Color portraitContactBadgeTextColor() { - return current().portraitContactBadgeTextColor(); - } - - Color portraitProfileBadgeColor() { - return current().portraitProfileBadgeColor(); - } - - Color portraitProfileBadgeTextColor() { - return current().portraitProfileBadgeTextColor(); - } - - Color portraitOverlayOfflineColor() { - return current().portraitOverlayOfflineColor(); - } - - Color toggleColor() { - return current().toggleColor(); - } - - Color toggleOffColor() { - return current().toggleOffColor(); - } - - Color toggleOnColor() { - return current().toggleOnColor(); - } - - Color sliderButtonColor() { - return current().sliderButtonColor(); - } - - Color sliderBarLeftColor() { - return current().sliderBarLeftColor(); - } - - Color sliderBarRightColor() { - return current().sliderBarRightColor(); - } - - Color boxCheckedColor() { - return current().boxCheckedColor(); - } - - Color toolbarIconColor() { - return current().toolbarIconColor(); - } - - Color toolbarMainColor() { - return current().toolbarMainColor(); - } - - Color toolbarAltColor() { - return current().toolbarAltColor(); - } - - Color statusbarDisconnectedInternetColor() { - return current().statusbarDisconnectedInternetColor(); - } - - Color statusbarDisconnectedInternetFontColor() { - return current().statusbarDisconnectedInternetFontColor(); - } - - Color statusbarDisconnectedTorFontColor() { - return current().statusbarDisconnectedTorFontColor(); - } - - Color statusbarDisconnectedTorColor() { - return current().statusbarDisconnectedTorColor(); - } - - Color statusbarConnectingColor() { - return current().statusbarConnectingColor(); - } - - Color statusbarConnectingFontColor() { - return current().statusbarConnectingFontColor(); - } - - Color statusbarOnlineColor() { - return current().statusbarOnlineColor(); - } - - Color statusbarOnlineFontColor() { - return current().statusbarOnlineFontColor(); - } - - Color chatOverlayWarningTextColor() { - return current().chatOverlayWarningTextColor(); - } - - Color messageFromMeBackgroundColor() { - return current().messageFromMeBackgroundColor(); - } - - Color messageFromMeTextColor() { - return current().messageFromMeTextColor(); - } - - Color messageFromOtherBackgroundColor() { - return current().messageFromOtherBackgroundColor(); - } - - Color messageFromOtherTextColor() { - return current().messageFromOtherTextColor(); - } - - Color messageStatusNormalColor() { - return current().messageStatusNormalColor(); - } - - Color messageStatusBlockedColor() { - return current().messageStatusBlockedColor(); - } - - Color messageStatusBlockedTextColor() { - return current().messageStatusBlockedTextColor(); - } - - Color messageStatusAlertColor() { - return current().messageStatusAlertColor(); - } - - Color messageStatusAlertTextColor() { - return current().messageStatusAlertTextColor(); - } - - Color scrollbarDefaultColor() { - return current().scrollbarDefaultColor(); - } - - Color scrollbarActiveColor() { - return current().scrollbarActiveColor(); - } - - var sidePaneMinSizeBase = [200, 400, 600]; - int sidePaneMinSize() { - return sidePaneMinSizeBase[p[scale]] + 200 /*for debugging*/; - } - - var chatPaneMinSizeBase = [300, 400, 500]; - int chatPaneMinSize() { - return chatPaneMinSizeBase[p[scale]]; - } - - int doublePaneMinSize() { - return sidePaneMinSize() + chatPaneMinSize(); - } - - static late OpaqueThemeType _current; - //static final OpaqueThemeType dark = CwtchDark(); - //static final OpaqueThemeType light = CwtchLight(); - - - int scale = 2; - static final String gcdOS = "linux"; - - var p = [0, 1, 1, 1, 2]; - var t = [0, 0, 1, 2, 2]; - - var paddingMinimalBase = [1, 4, 6]; - int paddingMinimal() { - return paddingMinimalBase[p[scale]]; - } - - var paddingSmallBase = [3, 10, 15]; - int paddingSmall() { - return paddingSmallBase[p[scale]]; - } - - var paddingStandardBase = [8, 20, 30]; - int paddingStandard() { - return paddingStandardBase[p[scale]]; - } - - var paddingLargeBase = [10, 30, 40]; - int paddingLarge() { - return paddingLargeBase[p[scale]]; - } - - var paddingClickTargetBase = gcdOS == "android" ? [10, 40, 100] : [3, 10, 15]; - int paddingClickTarget() { - return paddingClickTargetBase[p[scale]]; - } - - var textSmallPtBase = [8, 12, 16]; - int textSmallPt() { - return textSmallPtBase[t[scale]]; - } - - var textMediumPtBase = [10, 16, 24]; - int textMediumPt() { - return textMediumPtBase[t[scale]]; - } - - var textLargePtBase = [16, 24, 32]; - int textLargePt() { - return textLargePtBase[t[scale]]; - } - - var textSubHeaderPtBase = [12, 18, 26]; - int textSubHeaderPt() { - return textHeaderPtBase[t[scale]]; - } - - var textHeaderPtBase = [16, 24, 32]; - int textHeaderPt() { - return textHeaderPtBase[t[scale]]; - } - - var uiIconSizeSBase = [8, 16, 24]; - int uiIconSizeS() { - return uiIconSizeSBase[p[scale]]; - } - - var uiIconSizeMBase = [24, 32, 48]; - int uiIconSizeM() { - return uiIconSizeMBase[p[scale]]; - } - - var uiIconSizeLBase = [32, 48, 60]; - int uiIconSizeL() { - return uiIconSizeLBase[p[scale]]; - } - - var uiEmojiSizeBase = [24, 32, 48]; - int uiEmojiSize() { - return uiEmojiSizeBase[p[scale]]; - } - - var contactPortraitSizeBase = [60, 72, 84]; - int contactPortraitSize() { - return contactPortraitSizeBase[p[scale]]; - } - - int badgeTextSize() { - return 12; - } - - int statusTextSize() { - return 12; - } - - int chatSize() { - return textMediumPt(); - } - - int tabSize() { - return textMediumPt(); - } -} - -*/ diff --git a/lib/settings.dart b/lib/settings.dart index 7397ce39..f961af89 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -2,10 +2,11 @@ import 'dart:collection'; import 'dart:ui'; import 'dart:core'; +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'opaque.dart'; +import 'themes/opaque.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const TapirGroupsExperiment = "tapir-groups-experiment"; @@ -36,15 +37,8 @@ class Settings extends ChangeNotifier { bool blockUnknownConnections = false; bool streamerMode = false; - /// Set the dark theme. - void setDark() { - theme = OpaqueDark(); - notifyListeners(); - } - - /// Set the Light theme. - void setLight() { - theme = OpaqueLight(); + void setTheme(String themeId, String mode) { + theme = getTheme(themeId, mode); notifyListeners(); } @@ -69,11 +63,7 @@ class Settings extends ChangeNotifier { /// be sent to the function and new settings will be instantiated based on the contents. handleUpdate(dynamic settings) { // Set Theme and notify listeners - if (settings["Theme"] == "light") { - this.setLight(); - } else { - this.setDark(); - } + this.setTheme(settings["Theme"], settings["ThemeMode"] ?? mode_dark); // Set Locale and notify listeners switchLocale(Locale(settings["Locale"])); @@ -229,11 +219,10 @@ class Settings extends ChangeNotifier { /// Convert this Settings object to a JSON representation for serialization on the /// event bus. dynamic asJson() { - var themeString = theme.identifier(); - return { "Locale": this.locale.languageCode, - "Theme": themeString, + "Theme": theme.theme, + "ThemeMode": theme.mode, "PreviousPid": -1, "BlockUnknownConnections": blockUnknownConnections, "StreamerMode": streamerMode, diff --git a/lib/themes/cwtch.dart b/lib/themes/cwtch.dart new file mode 100644 index 00000000..c5c65ae9 --- /dev/null +++ b/lib/themes/cwtch.dart @@ -0,0 +1,121 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const cwtch_theme = "cwtch"; + +final Color darkGreyPurple = Color(0xFF281831); +final Color deepPurple = Color(0xFF422850); +final Color mauvePurple = Color(0xFF8E64A5); +final Color whiteishPurple = Color(0xFFE3DFE4); +final Color lightGrey = Color(0xFF9E9E9E); +final Color softGreen = Color(0xFFA0FFB0); +final Color softRed = Color(0xFFFFA0B0); + +final Color whitePurple = Color(0xFFFFFDFF); +final Color softPurple = Color(0xFFFDF3FC); +final Color purple = Color(0xFFDFB9DE); +final Color brightPurple = Color(0xFFD1B0E0); // not in new: portrait badge color +final Color darkPurple = Color(0xFF350052); +final Color greyPurple = Color(0xFF775F84); // not in new: portrait borders +final Color pink = Color(0xFFE85DA1); // not in new: active button color +final Color hotPink = Color(0xFFD20070); // Color(0xFFD01972); +final Color softGrey = Color(0xFFB3B6B3); // not in new theme: blocked + +OpaqueThemeType GetCwtchTheme(String mode) { + if (mode == mode_dark) { + return CwtchDark(); + } else { + return CwtchLight(); + } +} + +class CwtchDark extends OpaqueThemeType { + static final Color background = darkGreyPurple; + static final Color header = darkGreyPurple; + static final Color userBubble = mauvePurple; + static final Color peerBubble = deepPurple; + static final Color font = whiteishPurple; + static final Color settings = whiteishPurple; + static final Color accent = hotPink; + + get theme => cwtch_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get backgroundHilightElementColor => deepPurple; + get mainTextColor => font; //whiteishPurple; + get sendHintTextColor => mauvePurple; + get hilightElementColor => purple; + get defaultButtonColor => accent; //hotPink; + get defaultButtonTextColor => whiteishPurple; + get defaultButtonDisabledColor => lightGrey; + get defaultButtonDisabledTextColor => darkGreyPurple; + get textfieldBackgroundColor => deepPurple; + get textfieldBorderColor => deepPurple; + get textfieldHintColor => mainTextColor; //TODO pick + get textfieldErrorColor => hotPink; + get scrollbarDefaultColor => purple; + get portraitBackgroundColor => deepPurple; + get portraitOnlineBorderColor => whiteishPurple; + get portraitOfflineBorderColor => purple; + get portraitBlockedBorderColor => lightGrey; + get portraitBlockedTextColor => lightGrey; + get portraitContactBadgeColor => hotPink; + get portraitContactBadgeTextColor => whiteishPurple; + get portraitProfileBadgeColor => mauvePurple; + get portraitProfileBadgeTextColor => darkGreyPurple; + get dropShadowColor => mauvePurple; + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class CwtchLight extends OpaqueThemeType { + static final Color background = whitePurple; + static final Color header = softPurple; + static final Color userBubble = purple; + static final Color peerBubble = softPurple; + static final Color font = darkPurple; + static final Color settings = darkPurple; + static final Color accent = hotPink; + + get theme => cwtch_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get backgroundHilightElementColor => softPurple; + get mainTextColor => settings; + get sendHintTextColor => purple; + get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable + get defaultButtonColor => accent; // hotPink; + get defaultButtonTextColor => whitePurple; // ? + get defaultButtonDisabledColor => softGrey; + get textfieldBackgroundColor => purple; + get textfieldBorderColor => purple; + get textfieldHintColor => font; //TODO pick + get textfieldErrorColor => hotPink; + get scrollbarDefaultColor => accent; + get portraitBackgroundColor => softPurple; + get portraitOnlineBorderColor => greyPurple; + get portraitOfflineBorderColor => greyPurple; + get portraitBlockedBorderColor => softGrey; + get portraitBlockedTextColor => softGrey; + get portraitContactBadgeColor => accent; + get portraitContactBadgeTextColor => whitePurple; + get portraitProfileBadgeColor => brightPurple; + get portraitProfileBadgeTextColor => whitePurple; + get dropShadowColor => purple; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/themes/ghost.dart b/lib/themes/ghost.dart new file mode 100644 index 00000000..de2d3f2d --- /dev/null +++ b/lib/themes/ghost.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const ghost_theme = "ghost"; + +OpaqueThemeType GetGhostTheme(String mode) { + if (mode == mode_dark) { + return GhostDark(); + } else { + return GhostLight(); + } +} + +class GhostDark extends CwtchDark { + static final Color background = Color(0xFF0D0D1F); + static final Color header = Color(0xFF0D0D1F); + static final Color userBubble = Color(0xFF1A237E); + static final Color peerBubble = Color(0xFF000051); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFDFFFD); + static final Color accent = Color(0xFFD20070); + + get theme => ghost_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class GhostLight extends CwtchLight { + static final Color background = Color(0xFFFDFDFF); + static final Color header = Color(0xFFAAB6FE); + static final Color userBubble = Color(0xFFAAB6FE); + static final Color peerBubble = Color(0xFFE8EAF6); + static final Color font = Color(0xFF0D0D1F); + static final Color settings = Color(0xFF0D0D1F); + static final Color accent = Color(0xFFD20070); + + get theme => ghost_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/themes/mermaid.dart b/lib/themes/mermaid.dart new file mode 100644 index 00000000..c6e21122 --- /dev/null +++ b/lib/themes/mermaid.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const mermaid_theme = "mermaid"; + +OpaqueThemeType GetMermaidTheme(String mode) { + if (mode == mode_dark) { + return MermaidDark(); + } else { + return MermaidLight(); + } +} + +class MermaidDark extends CwtchDark { + static final Color background = Color(0xFF102426); + static final Color header = Color(0xFF102426); + static final Color userBubble = Color(0xFF00838F); + static final Color peerBubble = Color(0xFF00363A); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFF7FCFD); + static final Color accent = Color(0xFF8E64A5); + + get theme => mermaid_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class MermaidLight extends CwtchLight { + static final Color background = Color(0xFFF7FCFD); + static final Color header = Color(0xFF56C8D8); + static final Color userBubble = Color(0xFF56C8D8); + static final Color peerBubble = Color(0xFFB2EBF2); + static final Color font = Color(0xFF102426); + static final Color settings = Color(0xFF102426); + static final Color accent = Color(0xFF8E64A5); + + get theme => mermaid_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/themes/midnight.dart b/lib/themes/midnight.dart new file mode 100644 index 00000000..da1f1bfd --- /dev/null +++ b/lib/themes/midnight.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const midnight_theme = "midnight"; + +OpaqueThemeType GetMidnightTheme(String mode) { + if (mode == mode_dark) { + return MidnightDark(); + } else { + return MidnightLight(); + } +} + +class MidnightDark extends CwtchDark { + static final Color background = Color(0xFF1B1B1B); + static final Color header = Color(0xFF1B1B1B); + static final Color userBubble = Color(0xFF373737); + static final Color peerBubble = Color(0xFF212121); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFFFDFF); + static final Color accent = Color(0xFFD20070); + + get theme => midnight_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class MidnightLight extends CwtchLight { + static final Color background = Color(0xFFFFFDFF); + static final Color header = Color(0xFFE0E0E0); + static final Color userBubble = Color(0xFFE0E0E0); + static final Color peerBubble = Color(0xFFF3F3F3); + static final Color font = Color(0xFF1B1B1B); + static final Color settings = Color(0xFF1B1B1B); + static final Color accent = Color(0xFFD20070); + + get theme => midnight_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/themes/neon1.dart b/lib/themes/neon1.dart new file mode 100644 index 00000000..fcb4f614 --- /dev/null +++ b/lib/themes/neon1.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const neon1_theme = "neon1"; + +OpaqueThemeType GetNeon1Theme(String mode) { + if (mode == mode_dark) { + return Neon1Dark(); + } else { + return Neon1Light(); + } +} + +class Neon1Dark extends CwtchDark { + static final Color background = Color(0xFF290826); + static final Color header = Color(0xFF290826); + static final Color userBubble = Color(0xFFD20070); + static final Color peerBubble = Color(0xFF26A9A4); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFFFDFF); + static final Color accent = Color(0xFFA604FE); + + get theme => neon1_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class Neon1Light extends CwtchLight { + static final Color background = Color(0xFFFFFDFF); + static final Color header = Color(0xFFFF94C2); + static final Color userBubble = Color(0xFFFF94C2); + static final Color peerBubble = Color(0xFFE7F6F6); + static final Color font = Color(0xFF290826); + static final Color settings = Color(0xFF290826); + static final Color accent = Color(0xFFA604FE); + + get theme => neon1_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/themes/neon2.dart b/lib/themes/neon2.dart new file mode 100644 index 00000000..bdfeaf73 --- /dev/null +++ b/lib/themes/neon2.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const neon2_theme = "neon2"; + +OpaqueThemeType GetNeon2Theme(String mode) { + if (mode == mode_dark) { + return Neon2Dark(); + } else { + return Neon2Light(); + } +} + +class Neon2Dark extends CwtchDark { + static final Color background = Color(0xFF290826); + static final Color header = Color(0xFF290826); + static final Color userBubble = Color(0xFFA604FE); + static final Color peerBubble = Color(0xFF03AD00); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFFFDFF); + static final Color accent = Color(0xFFA604FE); + + get theme => neon2_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class Neon2Light extends CwtchLight { + static final Color background = Color(0xFFFFFDFF); + static final Color header = Color(0xFFD8C7E1); + static final Color userBubble = Color(0xFFD8C7E1); + static final Color peerBubble = Color(0xFF80E27E); + static final Color font = Color(0xFF290826); + static final Color settings = Color(0xFF290826); + static final Color accent = Color(0xFFA604FE); + + get theme => neon2_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart new file mode 100644 index 00000000..9e601d32 --- /dev/null +++ b/lib/themes/opaque.dart @@ -0,0 +1,201 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:cwtch/themes/mermaid.dart'; +import 'package:cwtch/themes/neon1.dart'; +import 'package:cwtch/themes/pumpkin.dart'; +import 'package:cwtch/themes/vampire.dart'; +import 'package:cwtch/themes/witch.dart'; +import 'package:flutter/material.dart'; +import 'package:cwtch/settings.dart'; + +import 'ghost.dart'; +import 'midnight.dart'; +import 'neon2.dart'; + +const mode_light = "light"; +const mode_dark = "dark"; + +final themes = { + cwtch_theme: {mode_light: CwtchLight(), mode_dark: CwtchDark()}, + ghost_theme: {mode_light: GhostLight(), mode_dark: GhostDark()}, + mermaid_theme: {mode_light: MermaidLight(), mode_dark: MermaidDark()}, + midnight_theme: {mode_light: MidnightLight(), mode_dark: MidnightDark()}, + neon1_theme: {mode_light: Neon1Light(), mode_dark: Neon1Dark()}, + neon2_theme: {mode_light: Neon2Light(), mode_dark: Neon2Dark()}, + pumpkin_theme: {mode_light: PumpkinLight(), mode_dark: PumpkinDark()}, + witch_theme: {mode_light: WitchLight(), mode_dark: WitchDark()}, + vampire_theme: {mode_light: VampireLight(), mode_dark: VampireDark()}, +}; + +OpaqueThemeType getTheme(String themeId, String mode) { + if (themeId == "") { + themeId = cwtch_theme; + } + if (themeId == mode_light) { + themeId = cwtch_theme; + mode = mode_light; + } + if (themeId == mode_dark) { + themeId = cwtch_theme; + mode = mode_dark; + } + + var theme = themes[themeId]?[mode]; + return theme ?? CwtchDark(); +} + +Color lighten(Color color, [double amount = 0.15]) { + final hsl = HSLColor.fromColor(color); + final hslLight = hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); + + return hslLight.toColor(); +} + +Color darken(Color color, [double amount = 0.15]) { + final hsl = HSLColor.fromColor(color); + final hslDarken = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); + + return hslDarken.toColor(); +} + +abstract class OpaqueThemeType { + static final Color red = Color(0xFFFF0000); + + get theme => "dummy"; + get mode => mode_light; + + // Main screen background color (message pane, item rows) + get backgroundMainColor => red; + + // Top pane ane pane colors (settings) + get backgroundPaneColor => red; + + get mainTextColor => red; + + // pressed row, offline heart + get hilightElementColor => red; + // Selected Row + get backgroundHilightElementColor => red; + // Faded text color for suggestions in textfields + // Todo: implement way more places + get sendHintTextColor => red; + + get defaultButtonColor => red; + get defaultButtonActiveColor => /*mode == mode_light ? darken(defaultButtonColor) :*/ lighten(defaultButtonColor); + get defaultButtonTextColor => red; + get defaultButtonDisabledColor => red; + get textfieldBackgroundColor => red; + get textfieldBorderColor => red; + get textfieldHintColor => red; + get textfieldErrorColor => red; + get scrollbarDefaultColor => red; + get portraitBackgroundColor => red; + get portraitOnlineBorderColor => red; + get portraitOfflineBorderColor => red; + get portraitBlockedBorderColor => red; + get portraitBlockedTextColor => red; + get portraitContactBadgeColor => red; + get portraitContactBadgeTextColor => red; + get portraitProfileBadgeColor => red; + get portraitProfileBadgeTextColor => red; + + // dropshaddpow + // todo: probably should not be reply icon color in messagerow + get dropShadowColor => red; + + get toolbarIconColor => red; + get messageFromMeBackgroundColor => red; + get messageFromMeTextColor => red; + get messageFromOtherBackgroundColor => red; + get messageFromOtherTextColor => red; + + // Sizes + + double contactOnionTextSize() { + return 18; + } +} + +ThemeData mkThemeData(Settings opaque) { + return ThemeData( + visualDensity: VisualDensity.adaptivePlatformDensity, + primarySwatch: Colors.red, + primaryIconTheme: IconThemeData( + color: opaque.current().mainTextColor, + ), + primaryColor: opaque.current().backgroundMainColor, + canvasColor: opaque.current().backgroundPaneColor, + backgroundColor: opaque.current().backgroundMainColor, + highlightColor: opaque.current().hilightElementColor, + iconTheme: IconThemeData( + color: opaque.current().toolbarIconColor, + ), + cardColor: opaque.current().backgroundMainColor, + appBarTheme: AppBarTheme( + backgroundColor: opaque.current().backgroundPaneColor, + iconTheme: IconThemeData( + color: opaque.current().mainTextColor, + ), + titleTextStyle: TextStyle( + color: opaque.current().mainTextColor, + ), + actionsIconTheme: IconThemeData( + color: opaque.current().mainTextColor, + )), + //bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor), // Can't determine current use + textButtonTheme: TextButtonThemeData( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor), + foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor), + overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor), + padding: MaterialStateProperty.all(EdgeInsets.all(20))), + ), + hintColor: opaque.current().textfieldHintColor, + elevatedButtonTheme: ElevatedButtonThemeData( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor : opaque.current().defaultButtonColor), + foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor), + overlayColor: MaterialStateProperty.resolveWith((states) => (states.contains(MaterialState.pressed) && states.contains(MaterialState.hovered)) + ? opaque.current().defaultButtonActiveColor + : states.contains(MaterialState.disabled) + ? opaque.current().defaultButtonDisabledColor + : null), + enableFeedback: true, + splashFactory: InkRipple.splashFactory, + padding: MaterialStateProperty.all(EdgeInsets.all(20)), + shape: MaterialStateProperty.all(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + )), + ), + ), + scrollbarTheme: ScrollbarThemeData(isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor)), + tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor))), + dialogTheme: DialogTheme( + backgroundColor: opaque.current().backgroundPaneColor, titleTextStyle: TextStyle(color: opaque.current().mainTextColor), contentTextStyle: TextStyle(color: opaque.current().mainTextColor)), + textTheme: TextTheme( + headline1: TextStyle(color: opaque.current().mainTextColor), + headline2: TextStyle(color: opaque.current().mainTextColor), + headline3: TextStyle(color: opaque.current().mainTextColor), + headline4: TextStyle(color: opaque.current().mainTextColor), + headline5: TextStyle(color: opaque.current().mainTextColor), + headline6: TextStyle(color: opaque.current().mainTextColor), + bodyText1: TextStyle(color: opaque.current().mainTextColor), + bodyText2: TextStyle(color: opaque.current().mainTextColor), + subtitle1: TextStyle(color: opaque.current().mainTextColor), + subtitle2: TextStyle(color: opaque.current().mainTextColor), + caption: TextStyle(color: opaque.current().mainTextColor), + button: TextStyle(color: opaque.current().mainTextColor), + overline: TextStyle(color: opaque.current().mainTextColor)), + switchTheme: SwitchThemeData( + overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor), + thumbColor: MaterialStateProperty.all(opaque.current().mainTextColor), + trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor), + ), + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: opaque.current().defaultButtonColor, hoverColor: opaque.current().defaultButtonActiveColor, enableFeedback: true, splashColor: opaque.current().defaultButtonActiveColor), + textSelectionTheme: TextSelectionThemeData( + cursorColor: opaque.current().defaultButtonActiveColor, selectionColor: opaque.current().defaultButtonActiveColor, selectionHandleColor: opaque.current().defaultButtonActiveColor), + ); +} diff --git a/lib/themes/pumpkin.dart b/lib/themes/pumpkin.dart new file mode 100644 index 00000000..f1c2faef --- /dev/null +++ b/lib/themes/pumpkin.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const pumpkin_theme = "pumpkin"; + +OpaqueThemeType GetPumpkinTheme(String mode) { + if (mode == mode_dark) { + return PumpkinDark(); + } else { + return PumpkinLight(); + } +} + +class PumpkinDark extends CwtchDark { + static final Color background = Color(0xFF281831); + static final Color header = Color(0xFF281831); + static final Color userBubble = Color(0xFFB53D00); + static final Color peerBubble = Color(0xFF422850); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFFFBF6); + static final Color accent = Color(0xFF8E64A5); + + get theme => pumpkin_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class PumpkinLight extends CwtchLight { + static final Color background = Color(0xFFFFFBF6); + static final Color header = Color(0xFFFF9800); + static final Color userBubble = Color(0xFFFF9800); + static final Color peerBubble = Color(0xFFD8C7E1); + static final Color font = Color(0xFF281831); + static final Color settings = Color(0xFF281831); + static final Color accent = Color(0xFF8E64A5); + + get theme => pumpkin_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/themes/vampire.dart b/lib/themes/vampire.dart new file mode 100644 index 00000000..13bba5b2 --- /dev/null +++ b/lib/themes/vampire.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const vampire_theme = "vampire"; + +OpaqueThemeType GetVampireTheme(String mode) { + if (mode == mode_dark) { + return VampireDark(); + } else { + return VampireLight(); + } +} + +class VampireDark extends CwtchDark { + static final Color background = Color(0xFF281831); + static final Color header = Color(0xFF281831); + static final Color userBubble = Color(0xFF9A1218); + static final Color peerBubble = Color(0xFF422850); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFDFFFD); + static final Color accent = Color(0xFF8E64A5); + + get theme => vampire_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class VampireLight extends CwtchLight { + static final Color background = Color(0xFFFFFDFD); + static final Color header = Color(0xFFD8C7E1); + static final Color userBubble = Color(0xFFD8C7E1); + static final Color peerBubble = Color(0xFFFFEBEE); + static final Color font = Color(0xFF281831); + static final Color settings = Color(0xFF281831); + static final Color accent = Color(0xFF8E64A5); + + get theme => vampire_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/themes/witch.dart b/lib/themes/witch.dart new file mode 100644 index 00000000..38ad6c8e --- /dev/null +++ b/lib/themes/witch.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +const witch_theme = "witch"; + +OpaqueThemeType GetWitchTheme(String mode) { + if (mode == mode_dark) { + return WitchDark(); + } else { + return WitchLight(); + } +} + +class WitchDark extends CwtchDark { + static final Color background = Color(0xFF0E1E0E); + static final Color header = Color(0xFF0E1E0E); + static final Color userBubble = Color(0xFF1B5E20); + static final Color peerBubble = Color(0xFF003300); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFDFFFD); + static final Color accent = Color(0xFFD20070); + + get theme => witch_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class WitchLight extends CwtchLight { + static final Color background = Color(0xFFFDFFFD); + static final Color header = Color(0xFF80E27E); + static final Color userBubble = Color(0xFF80E27E); + static final Color peerBubble = Color(0xFFE8F5E9); + static final Color font = Color(0xFF0E1E0E); + static final Color settings = Color(0xFF0E1E0E); + static final Color accent = Color(0xFFD20070); + + get theme => witch_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} diff --git a/lib/views/addcontactview.dart b/lib/views/addcontactview.dart index 8485058f..c073f0f5 100644 --- a/lib/views/addcontactview.dart +++ b/lib/views/addcontactview.dart @@ -163,7 +163,7 @@ class _AddContactViewState extends State { } }); }, - labelText: '', + hintText: '', ) ]))); } @@ -215,7 +215,7 @@ class _AddContactViewState extends State { ), CwtchTextField( controller: ctrlrGroupName, - labelText: AppLocalizations.of(context)!.groupNameLabel, + hintText: AppLocalizations.of(context)!.groupNameLabel, onChanged: (newValue) {}, validator: (value) {}, ), diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index 2355fd57..95706b92 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -16,7 +16,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../cwtch_icons_icons.dart'; import '../errorHandler.dart'; import '../main.dart'; -import '../opaque.dart'; +import '../themes/opaque.dart'; import '../settings.dart'; class AddEditProfileView extends StatefulWidget { @@ -91,7 +91,7 @@ class _AddEditProfileViewState extends State { imagePath: Provider.of(context).imagePath, diameter: 120, maskOut: false, - border: theme.theme.portraitOnlineBorderColor(), + border: theme.theme.portraitOnlineBorderColor, badgeTextColor: Colors.red, badgeColor: Colors.red, ) @@ -104,11 +104,10 @@ class _AddEditProfileViewState extends State { CwtchTextField( controller: ctrlrNick, autofocus: false, - labelText: AppLocalizations.of(context)!.yourDisplayName, + hintText: AppLocalizations.of(context)!.yourDisplayName, validator: (value) { if (value.isEmpty) { - // TODO l10n ize - return "Please enter a display name"; + return AppLocalizations.of(context)!.displayNameTooltip; } return null; }, @@ -146,13 +145,13 @@ class _AddEditProfileViewState extends State { child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Checkbox( value: usePassword, - fillColor: MaterialStateProperty.all(theme.current().defaultButtonColor()), - activeColor: theme.current().defaultButtonActiveColor(), + fillColor: MaterialStateProperty.all(theme.current().defaultButtonColor), + activeColor: theme.current().defaultButtonActiveColor, onChanged: _handleSwitchPassword, ), Text( AppLocalizations.of(context)!.radioUsePassword, - style: TextStyle(color: theme.current().mainTextColor()), + style: TextStyle(color: theme.current().mainTextColor), ), SizedBox( height: 20, diff --git a/lib/views/addeditservers.dart b/lib/views/addeditservers.dart index 2a1c8f46..ede9911a 100644 --- a/lib/views/addeditservers.dart +++ b/lib/views/addeditservers.dart @@ -33,7 +33,6 @@ class _AddEditServerViewState extends State { final ctrlrOnion = TextEditingController(text: ""); late bool usePassword; - //late bool deleted; @override void initState() { @@ -81,22 +80,16 @@ class _AddEditServerViewState extends State { child: Form( key: _formKey, child: Container( - margin: EdgeInsets.fromLTRB(30, 0, 30, 10), - padding: EdgeInsets.fromLTRB(20, 0, 20, 10), + margin: EdgeInsets.fromLTRB(30, 5, 30, 10), + padding: EdgeInsets.fromLTRB(20, 5, 20, 10), child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Onion Visibility( visible: serverInfoState.onion.isNotEmpty, - child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - height: 20, - ), - CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), - SizedBox( - height: 20, - ), - SelectableText(serverInfoState.onion) - ])), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), SelectableText(serverInfoState.onion)])), // Description Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -110,7 +103,7 @@ class _AddEditServerViewState extends State { ), CwtchTextField( controller: ctrlrDesc, - labelText: "Description", + hintText: AppLocalizations.of(context)!.fieldDescriptionLabel, autofocus: false, ) ]), @@ -123,7 +116,7 @@ class _AddEditServerViewState extends State { Visibility( visible: serverInfoState.onion.isNotEmpty, child: SwitchListTile( - title: Text(AppLocalizations.of(context)!.serverEnabled, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.serverEnabled, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.serverEnabledDescription), value: serverInfoState.running, onChanged: (bool value) { @@ -134,14 +127,14 @@ class _AddEditServerViewState extends State { Provider.of(context, listen: false).cwtch.StopServer(serverInfoState.onion); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.negative_heart_24px, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.negative_heart_24px, color: settings.current().mainTextColor), )), // Auto start SwitchListTile( - title: Text(AppLocalizations.of(context)!.serverAutostartLabel, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.serverAutostartLabel, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.serverAutostartDescription), value: serverInfoState.autoStart, onChanged: (bool value) { @@ -151,11 +144,33 @@ class _AddEditServerViewState extends State { Provider.of(context, listen: false).cwtch.SetServerAttribute(serverInfoState.onion, "autostart", value ? "true" : "false"); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.favorite_24dp, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.favorite_24dp, color: settings.current().mainTextColor), ), + // metrics + Visibility( + visible: serverInfoState.onion.isNotEmpty, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox( + height: 20, + ), + Text(AppLocalizations.of(context)!.serverMetricsLabel, style: Provider.of(context).biggerFont), + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(AppLocalizations.of(context)!.serverTotalMessagesLabel), + ]), + Text(serverInfoState.totalMessages.toString()) + ]), + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(AppLocalizations.of(context)!.serverConnectionsLabel), + ]), + Text(serverInfoState.connections.toString()) + ]), + ])), + // ***** Password ***** // use password toggle @@ -167,13 +182,13 @@ class _AddEditServerViewState extends State { ), Checkbox( value: usePassword, - fillColor: MaterialStateProperty.all(settings.current().defaultButtonColor()), - activeColor: settings.current().defaultButtonActiveColor(), + fillColor: MaterialStateProperty.all(settings.current().defaultButtonColor), + activeColor: settings.current().defaultButtonActiveColor, onChanged: _handleSwitchPassword, ), Text( AppLocalizations.of(context)!.radioUsePassword, - style: TextStyle(color: settings.current().mainTextColor()), + style: TextStyle(color: settings.current().mainTextColor), ), SizedBox( height: 20, diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 990899f3..cfb29b01 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -1,4 +1,5 @@ import 'package:cwtch/cwtch_icons_icons.dart'; +import 'package:cwtch/views/profileserversview.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/views/torstatusview.dart'; import 'package:cwtch/widgets/contactrow.dart'; @@ -77,7 +78,7 @@ class _ContactsViewState extends State { ProfileImage( imagePath: Provider.of(context).imagePath, diameter: 42, - border: Provider.of(context).current().portraitOnlineBorderColor(), + border: Provider.of(context).current().portraitOnlineBorderColor, badgeTextColor: Colors.red, badgeColor: Colors.red, ), @@ -86,7 +87,7 @@ class _ContactsViewState extends State { ), Expanded( child: Text("%1 » %2".replaceAll("%1", Provider.of(context).nickname).replaceAll("%2", AppLocalizations.of(context)!.titleManageContacts), - overflow: TextOverflow.ellipsis, style: TextStyle(color: Provider.of(context).current().mainTextColor()))), + overflow: TextOverflow.ellipsis, style: TextStyle(color: Provider.of(context).current().mainTextColor))), ])), actions: getActions(context), ), @@ -112,7 +113,15 @@ class _ContactsViewState extends State { Clipboard.setData(new ClipboardData(text: Provider.of(context, listen: false).onion)); })); - // TODO servers + // Manage known Servers + if (Provider.of(context, listen: false).isExperimentEnabled(TapirGroupsExperiment) || Provider.of(context, listen: false).isExperimentEnabled(ServerManagementExperiment)) { + actions.add(IconButton( + icon: Icon(CwtchIcons.dns_24px), + tooltip: AppLocalizations.of(context)!.manageKnownServersButton, + onPressed: () { + _pushServers(); + })); + } // Search contacts actions.add(IconButton( @@ -130,7 +139,7 @@ class _ContactsViewState extends State { Widget _buildFilterable() { Widget txtfield = CwtchTextField( controller: ctrlrFilter, - labelText: AppLocalizations.of(context)!.search, + hintText: AppLocalizations.of(context)!.search, onChanged: (newVal) { Provider.of(context, listen: false).filter = newVal; }, @@ -162,12 +171,13 @@ class _ContactsViewState extends State { )); } - void _pushTorStatus() { + void _pushServers() { + var profile = Provider.of(context); Navigator.of(context).push(MaterialPageRoute( builder: (BuildContext context) { return MultiProvider( - providers: [Provider.value(value: Provider.of(context))], - child: TorStatusView(), + providers: [ChangeNotifierProvider(create: (context) => profile), Provider.value(value: Provider.of(context))], + child: ProfileServersView(), ); }, )); diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 6668ed52..e6887350 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -2,6 +2,16 @@ import 'dart:convert'; import 'dart:io'; import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/servers.dart'; +import 'package:cwtch/themes/cwtch.dart'; +import 'package:cwtch/themes/ghost.dart'; +import 'package:cwtch/themes/mermaid.dart'; +import 'package:cwtch/themes/midnight.dart'; +import 'package:cwtch/themes/neon1.dart'; +import 'package:cwtch/themes/neon2.dart'; +import 'package:cwtch/themes/opaque.dart'; +import 'package:cwtch/themes/pumpkin.dart'; +import 'package:cwtch/themes/vampire.dart'; +import 'package:cwtch/themes/witch.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/settings.dart'; @@ -36,7 +46,7 @@ class _GlobalSettingsViewState extends State { Widget _buildSettingsList() { return Consumer(builder: (context, settings, child) { return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) { - var appIcon = Icon(Icons.info, color: settings.current().mainTextColor()); + var appIcon = Icon(Icons.info, color: settings.current().mainTextColor); return Scrollbar( isAlwaysShown: true, child: SingleChildScrollView( @@ -47,8 +57,8 @@ class _GlobalSettingsViewState extends State { ), child: Column(children: [ ListTile( - title: Text(AppLocalizations.of(context)!.settingLanguage, style: TextStyle(color: settings.current().mainTextColor())), - leading: Icon(CwtchIcons.change_language, color: settings.current().mainTextColor()), + title: Text(AppLocalizations.of(context)!.settingLanguage, style: TextStyle(color: settings.current().mainTextColor)), + leading: Icon(CwtchIcons.change_language, color: settings.current().mainTextColor), trailing: DropdownButton( value: Provider.of(context).locale.languageCode, onChanged: (String? newValue) { @@ -64,25 +74,43 @@ class _GlobalSettingsViewState extends State { ); }).toList())), SwitchListTile( - title: Text(AppLocalizations.of(context)!.settingTheme, style: TextStyle(color: settings.current().mainTextColor())), - value: settings.current().identifier() == "light", + title: Text(AppLocalizations.of(context)!.settingTheme, style: TextStyle(color: settings.current().mainTextColor)), + value: settings.current().mode == mode_light, onChanged: (bool value) { if (value) { - settings.setLight(); + settings.setTheme(settings.theme.theme, mode_light); } else { - settings.setDark(); + settings.setTheme(settings.theme.theme, mode_dark); } // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), ), ListTile( - title: Text(AppLocalizations.of(context)!.settingUIColumnPortrait, style: TextStyle(color: settings.current().mainTextColor())), - leading: Icon(Icons.table_chart, color: settings.current().mainTextColor()), + title: Text(AppLocalizations.of(context)!.themeColorLabel), + trailing: DropdownButton( + value: Provider.of(context).theme.theme, + onChanged: (String? newValue) { + setState(() { + settings.setTheme(newValue!, settings.theme.mode); + saveSettings(context); + }); + }, + items: themes.keys.map>((String themeId) { + return DropdownMenuItem( + value: themeId, + child: Text(getThemeName(context, themeId)), + ); + }).toList()), + leading: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), + ), + ListTile( + title: Text(AppLocalizations.of(context)!.settingUIColumnPortrait, style: TextStyle(color: settings.current().mainTextColor)), + leading: Icon(Icons.table_chart, color: settings.current().mainTextColor), trailing: DropdownButton( value: settings.uiColumnModePortrait.toString(), onChanged: (String? newValue) { @@ -100,9 +128,9 @@ class _GlobalSettingsViewState extends State { AppLocalizations.of(context)!.settingUIColumnLandscape, textWidthBasis: TextWidthBasis.longestLine, softWrap: true, - style: TextStyle(color: settings.current().mainTextColor()), + style: TextStyle(color: settings.current().mainTextColor), ), - leading: Icon(Icons.table_chart, color: settings.current().mainTextColor()), + leading: Icon(Icons.table_chart, color: settings.current().mainTextColor), trailing: Container( width: 200.0, child: DropdownButton( @@ -122,7 +150,7 @@ class _GlobalSettingsViewState extends State { ); }).toList()))), SwitchListTile( - title: Text(AppLocalizations.of(context)!.blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionBlockUnknownConnections), value: settings.blockUnknownConnections, onChanged: (bool value) { @@ -135,12 +163,12 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.block_unknown, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.block_unknown, color: settings.current().mainTextColor), ), SwitchListTile( - title: Text(AppLocalizations.of(context)!.streamerModeLabel, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.streamerModeLabel, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionStreamerMode), value: settings.streamerMode, onChanged: (bool value) { @@ -148,12 +176,12 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.streamer_bunnymask, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.streamer_bunnymask, color: settings.current().mainTextColor), ), SwitchListTile( - title: Text(AppLocalizations.of(context)!.experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionExperiments), value: settings.experimentsEnabled, onChanged: (bool value) { @@ -165,16 +193,16 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.enable_experiments, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.enable_experiments, color: settings.current().mainTextColor), ), Visibility( visible: settings.experimentsEnabled, child: Column( children: [ SwitchListTile( - title: Text(AppLocalizations.of(context)!.enableGroups, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.enableGroups, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionExperimentsGroups), value: settings.isExperimentEnabled(TapirGroupsExperiment), onChanged: (bool value) { @@ -186,14 +214,14 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.enable_groups, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.enable_groups, color: settings.current().mainTextColor), ), Visibility( visible: !Platform.isAndroid && !Platform.isIOS, child: SwitchListTile( - title: Text(AppLocalizations.of(context)!.settingServers, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.settingServers, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.settingServersDescription), value: settings.isExperimentEnabled(ServerManagementExperiment), onChanged: (bool value) { @@ -206,12 +234,12 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.dns_24px, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.dns_24px, color: settings.current().mainTextColor), )), SwitchListTile( - title: Text(AppLocalizations.of(context)!.settingFileSharing, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.settingFileSharing, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionFileSharing), value: settings.isExperimentEnabled(FileSharingExperiment), onChanged: (bool value) { @@ -222,13 +250,13 @@ class _GlobalSettingsViewState extends State { } saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(Icons.attach_file, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(Icons.attach_file, color: settings.current().mainTextColor), ), SwitchListTile( - title: Text("Enable Clickable Links", style: TextStyle(color: settings.current().mainTextColor())), - subtitle: Text("The clickable links experiment allows you to click on URLs shared in messages."), + title: Text(AppLocalizations.of(context)!.enableExperimentClickableLinks, style: TextStyle(color: settings.current().mainTextColor)), + subtitle: Text(AppLocalizations.of(context)!.experimentClickableLinksDescription), value: settings.isExperimentEnabled(ClickableLinksExperiment), onChanged: (bool value) { if (value) { @@ -238,9 +266,9 @@ class _GlobalSettingsViewState extends State { } saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(Icons.link, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(Icons.link, color: settings.current().mainTextColor), ), ], )), @@ -251,8 +279,8 @@ class _GlobalSettingsViewState extends State { applicationLegalese: '\u{a9} 2021 Open Privacy Research Society', aboutBoxChildren: [ Padding( - padding: EdgeInsets.fromLTRB( - 24.0 + 10.0 + (appIcon.size ?? 24.0), 16.0, 0.0, 0.0), // About has 24 padding (ln 389) and there appears to be another 10 of padding in the widget + padding: EdgeInsets.fromLTRB(24.0 + 10.0 + (appIcon.size ?? 24.0), 16.0, 0.0, 0.0), + // About has 24 padding (ln 389) and there appears to be another 10 of padding in the widget child: SelectableText(AppLocalizations.of(context)!.versionBuilddate.replaceAll("%1", EnvironmentConfig.BUILD_VER).replaceAll("%2", EnvironmentConfig.BUILD_DATE)), ) ]), @@ -300,6 +328,31 @@ String getLanguageFull(context, String languageCode) { return languageCode; } +/// Since we don't seem to able to dynamically pull translations, this function maps themes to their names +String getThemeName(context, String theme) { + switch (theme) { + case cwtch_theme: + return AppLocalizations.of(context)!.themeNameCwtch; + case ghost_theme: + return AppLocalizations.of(context)!.themeNameGhost; + case mermaid_theme: + return AppLocalizations.of(context)!.themeNameMermaid; + case midnight_theme: + return AppLocalizations.of(context)!.themeNameMidnight; + case neon1_theme: + return AppLocalizations.of(context)!.themeNameNeon1; + case neon2_theme: + return AppLocalizations.of(context)!.themeNameNeon2; + case pumpkin_theme: + return AppLocalizations.of(context)!.themeNamePumpkin; + case vampire_theme: + return AppLocalizations.of(context)!.themeNameVampire; + case witch_theme: + return AppLocalizations.of(context)!.themeNameWitch; + } + return theme; +} + /// Send an UpdateGlobalSettings to the Event Bus saveSettings(context) { var settings = Provider.of(context, listen: false); diff --git a/lib/views/groupsettingsview.dart b/lib/views/groupsettingsview.dart index 463a99b2..6407c4ef 100644 --- a/lib/views/groupsettingsview.dart +++ b/lib/views/groupsettingsview.dart @@ -101,7 +101,7 @@ class _GroupSettingsViewState extends State { ), CwtchTextField( controller: ctrlrGroupAddr, - labelText: '', + hintText: '', validator: (value) {}, ) ]), @@ -116,7 +116,7 @@ class _GroupSettingsViewState extends State { CwtchTextField( controller: TextEditingController(text: Provider.of(context, listen: false).server), validator: (value) {}, - labelText: '', + hintText: '', ) ]), diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index 539bebfb..8b803daf 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -104,6 +104,7 @@ class _MessageViewState extends State { return WillPopScope( onWillPop: _onWillPop, child: Scaffold( + backgroundColor: Provider.of(context).theme.backgroundMainColor, floatingActionButton: appState.unreadMessagesBelow ? FloatingActionButton( child: Icon(Icons.arrow_downward), @@ -120,7 +121,7 @@ class _MessageViewState extends State { ProfileImage( imagePath: Provider.of(context).imagePath, diameter: 42, - border: Provider.of(context).current().portraitOnlineBorderColor(), + border: Provider.of(context).current().portraitOnlineBorderColor, badgeTextColor: Colors.red, badgeColor: Colors.red, ), @@ -225,7 +226,7 @@ class _MessageViewState extends State { bool isOffline = Provider.of(context).isOnline() == false; var composeBox = Container( - color: Provider.of(context).theme.backgroundMainColor(), + color: Provider.of(context).theme.backgroundMainColor, padding: EdgeInsets.all(2), margin: EdgeInsets.all(2), height: 100, @@ -233,7 +234,7 @@ class _MessageViewState extends State { children: [ Expanded( child: Container( - decoration: BoxDecoration(border: Border(top: BorderSide(color: Provider.of(context).theme.defaultButtonActiveColor()))), + decoration: BoxDecoration(border: Border(top: BorderSide(color: Provider.of(context).theme.defaultButtonActiveColor))), child: RawKeyboardListener( focusNode: FocusNode(), onKey: handleKeyPress, @@ -253,12 +254,12 @@ class _MessageViewState extends State { enabled: !isOffline, decoration: InputDecoration( hintText: isOffline ? "" : AppLocalizations.of(context)!.placeholderEnterMessage, - hintStyle: TextStyle(color: Provider.of(context).theme.altTextColor()), + hintStyle: TextStyle(color: Provider.of(context).theme.sendHintTextColor), enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, enabled: true, suffixIcon: ElevatedButton( - child: Icon(CwtchIcons.send_24px, size: 24, color: Provider.of(context).theme.defaultButtonTextColor()), + child: Icon(CwtchIcons.send_24px, size: 24, color: Provider.of(context).theme.defaultButtonTextColor), onPressed: isOffline ? null : _sendMessage, ))), )))), @@ -278,8 +279,8 @@ class _MessageViewState extends State { margin: EdgeInsets.all(5), padding: EdgeInsets.all(5), color: message.getMetadata().senderHandle != Provider.of(context).selectedProfile - ? Provider.of(context).theme.messageFromOtherBackgroundColor() - : Provider.of(context).theme.messageFromMeBackgroundColor(), + ? Provider.of(context).theme.messageFromOtherBackgroundColor + : Provider.of(context).theme.messageFromMeBackgroundColor, child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Stack(children: [ Align( @@ -313,7 +314,7 @@ class _MessageViewState extends State { children = [composeBox]; } - return Column(mainAxisSize: MainAxisSize.min, children: children); + return Container(color: Provider.of(context).theme.backgroundMainColor, child: Column(mainAxisSize: MainAxisSize.min, children: children)); } // Send the message if enter is pressed without the shift key... diff --git a/lib/views/peersettingsview.dart b/lib/views/peersettingsview.dart index 506c1706..57f42b40 100644 --- a/lib/views/peersettingsview.dart +++ b/lib/views/peersettingsview.dart @@ -105,7 +105,7 @@ class _PeerSettingsViewState extends State { height: 20, ), SwitchListTile( - title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor)), value: Provider.of(context).isBlocked, onChanged: (bool blocked) { // Save local blocked status @@ -137,14 +137,14 @@ class _PeerSettingsViewState extends State { Provider.of(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.block_peer, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.block_peer, color: settings.current().mainTextColor), ), ListTile( - title: Text(AppLocalizations.of(context)!.savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.savePeerHistory, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.savePeerHistoryDescription), - leading: Icon(CwtchIcons.peer_history, color: settings.current().mainTextColor()), + leading: Icon(CwtchIcons.peer_history, color: settings.current().mainTextColor), trailing: DropdownButton( value: Provider.of(context).savePeerHistory == "DefaultDeleteHistory" ? AppLocalizations.of(context)!.dontSavePeerHistory diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index e4a6eba0..da72472c 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -46,20 +46,20 @@ class _ProfileMgrViewState extends State { return Provider.of(context, listen: false).cwtchIsClosing; }, child: Scaffold( - backgroundColor: settings.theme.backgroundMainColor(), + backgroundColor: settings.theme.backgroundMainColor, appBar: AppBar( title: Row(children: [ Icon( CwtchIcons.cwtch_knott, size: 36, - color: settings.theme.mainTextColor(), + color: settings.theme.mainTextColor, ), SizedBox( width: 10, ), Expanded( child: Text(MediaQuery.of(context).size.width > 600 ? AppLocalizations.of(context)!.titleManageProfiles : AppLocalizations.of(context)!.titleManageProfilesShort, - style: TextStyle(color: settings.current().mainTextColor()))) + style: TextStyle(color: settings.current().mainTextColor))) ]), actions: getActions(), ), @@ -93,7 +93,7 @@ class _ProfileMgrViewState extends State { // Unlock Profiles actions.add(IconButton( icon: Icon(CwtchIcons.lock_open_24px), - color: Provider.of(context).profiles.isEmpty ? Provider.of(context).theme.defaultButtonColor() : Provider.of(context).theme.mainTextColor(), + color: Provider.of(context).profiles.isEmpty ? Provider.of(context).theme.defaultButtonColor : Provider.of(context).theme.mainTextColor, tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles, onPressed: _modalUnlockProfiles, )); diff --git a/lib/views/profileserversview.dart b/lib/views/profileserversview.dart new file mode 100644 index 00000000..1fd029b4 --- /dev/null +++ b/lib/views/profileserversview.dart @@ -0,0 +1,136 @@ +import 'package:cwtch/models/profileservers.dart'; +import 'package:cwtch/models/servers.dart'; +import 'package:cwtch/widgets/remoteserverrow.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:provider/provider.dart'; + +import '../cwtch_icons_icons.dart'; +import '../main.dart'; +import '../model.dart'; +import '../settings.dart'; + +class ProfileServersView extends StatefulWidget { + @override + _ProfileServersView createState() => _ProfileServersView(); +} + +class _ProfileServersView extends State { + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + var knownServers = Provider.of(context).serverList.servers.map((RemoteServerInfoState remoteServer) { + return remoteServer.onion + ".onion"; + }).toSet(); + var importServerList = Provider.of(context).servers.where((server) => !knownServers.contains(server.onion)).map>((ServerInfoState serverInfo) { + return DropdownMenuItem( + value: serverInfo.onion, + child: Text( + serverInfo.description.isNotEmpty ? serverInfo.description : serverInfo.onion, + overflow: TextOverflow.ellipsis, + ), + ); + }).toList(); + + importServerList.insert(0, DropdownMenuItem(value: "", child: Text(AppLocalizations.of(context)!.importLocalServerSelectText))); + + return Scaffold( + appBar: AppBar( + title: Text(MediaQuery.of(context).size.width > 600 ? AppLocalizations.of(context)!.manageKnownServersLong : AppLocalizations.of(context)!.manageKnownServersShort), + ), + body: Consumer( + builder: (context, profile, child) { + ProfileServerListState servers = profile.serverList; + final tiles = servers.servers.map( + (RemoteServerInfoState server) { + return ChangeNotifierProvider.value( + value: server, + builder: (context, child) => RepaintBoundary(child: RemoteServerRow()), + ); + }, + ); + + final divided = ListTile.divideTiles( + context: context, + tiles: tiles, + ).toList(); + + final importCard = Card( + child: ListTile( + title: Text(AppLocalizations.of(context)!.importLocalServerLabel), + leading: Icon(CwtchIcons.add_circle_24px, color: Provider.of(context).current().mainTextColor), + trailing: DropdownButton( + onChanged: (String? importServer) { + if (importServer!.isNotEmpty) { + var server = Provider.of(context).getServer(importServer)!; + showImportConfirm(context, profile.onion, server.onion, server.description, server.serverBundle); + } + }, + value: "", + items: importServerList, + ))); + + return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) { + return Scrollbar( + isAlwaysShown: true, + child: SingleChildScrollView( + clipBehavior: Clip.antiAlias, + child: Container( + margin: EdgeInsets.fromLTRB(5, 0, 5, 10), + padding: EdgeInsets.fromLTRB(5, 0, 5, 10), + child: Column(children: [if (importServerList.length > 1) importCard, Column(children: divided)])))); + }); + + return ListView(children: divided); + }, + )); + } + + showImportConfirm(BuildContext context, String profileHandle, String serverHandle, String serverDesc, String bundle) { + var serverLabel = serverDesc.isNotEmpty ? serverDesc : serverHandle; + serverHandle = serverHandle.substring(0, serverHandle.length - 6); // remove '.onion' + // set up the buttons + Widget cancelButton = ElevatedButton( + child: Text(AppLocalizations.of(context)!.cancel), + onPressed: () { + Navigator.of(context).pop(); // dismiss dialog + }, + ); + Widget continueButton = ElevatedButton( + child: Text(AppLocalizations.of(context)!.importLocalServerButton.replaceAll("%1", serverLabel)), + onPressed: () { + Provider.of(context, listen: false).cwtch.ImportBundle(profileHandle, bundle); + // Wait 500ms and hope the server is imported and add it's description in the UI and as an attribute + Future.delayed(const Duration(milliseconds: 500), () { + var profile = Provider.of(context); + if (profile.serverList.getServer(serverHandle) != null) { + profile.serverList.getServer(serverHandle)?.updateDescription(serverDesc); + + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profile.onion, profile.serverList.getServer(serverHandle)!.identifier, "server.description", serverDesc); + } + }); + Navigator.of(context).pop(); + }); + + // set up the AlertDialog + AlertDialog alert = AlertDialog( + title: Text(AppLocalizations.of(context)!.importLocalServerButton.replaceAll("%1", serverLabel)), + actions: [ + cancelButton, + continueButton, + ], + ); + + // show the dialog + showDialog( + context: context, + builder: (BuildContext context) { + return alert; + }, + ); + } +} diff --git a/lib/views/remoteserverview.dart b/lib/views/remoteserverview.dart new file mode 100644 index 00000000..18bcdd04 --- /dev/null +++ b/lib/views/remoteserverview.dart @@ -0,0 +1,146 @@ +import 'dart:convert'; +import 'package:cwtch/cwtch/cwtch.dart'; +import 'package:cwtch/cwtch_icons_icons.dart'; +import 'package:cwtch/models/profileservers.dart'; +import 'package:cwtch/models/servers.dart'; +import 'package:cwtch/widgets/buttontextfield.dart'; +import 'package:cwtch/widgets/contactrow.dart'; +import 'package:cwtch/widgets/cwtchlabel.dart'; +import 'package:cwtch/widgets/passwordfield.dart'; +import 'package:cwtch/widgets/textfield.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:flutter/material.dart'; +import 'package:cwtch/settings.dart'; +import 'package:provider/provider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import '../errorHandler.dart'; +import '../main.dart'; +import '../config.dart'; +import '../model.dart'; + +/// Pane to add or edit a server +class RemoteServerView extends StatefulWidget { + const RemoteServerView(); + + @override + _RemoteServerViewState createState() => _RemoteServerViewState(); +} + +class _RemoteServerViewState extends State { + final _formKey = GlobalKey(); + + final ctrlrDesc = TextEditingController(text: ""); + + @override + void initState() { + super.initState(); + var serverInfoState = Provider.of(context, listen: false); + if (serverInfoState.description.isNotEmpty) { + ctrlrDesc.text = serverInfoState.description; + } + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Consumer3(builder: (context, profile, serverInfoState, settings, child) { + return Scaffold( + appBar: AppBar(title: Text(ctrlrDesc.text.isNotEmpty ? ctrlrDesc.text : serverInfoState.onion)), + body: Container( + margin: EdgeInsets.fromLTRB(30, 0, 30, 10), + padding: EdgeInsets.fromLTRB(20, 0, 20, 10), + child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox( + height: 20, + ), + CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), + SizedBox( + height: 20, + ), + SelectableText(serverInfoState.onion), + + // Description + SizedBox( + height: 20, + ), + CwtchLabel(label: AppLocalizations.of(context)!.serverDescriptionLabel), + Text(AppLocalizations.of(context)!.serverDescriptionDescription), + SizedBox( + height: 20, + ), + CwtchButtonTextField( + controller: ctrlrDesc, + readonly: false, + tooltip: AppLocalizations.of(context)!.saveBtn, + labelText: AppLocalizations.of(context)!.fieldDescriptionLabel, + icon: Icon(Icons.save), + onPressed: () { + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profile.onion, serverInfoState.identifier, "server.description", ctrlrDesc.text); + serverInfoState.updateDescription(ctrlrDesc.text); + }, + ), + + SizedBox( + height: 20, + ), + + Padding( + padding: EdgeInsets.all(8), + child: Text(AppLocalizations.of(context)!.groupsOnThisServerLabel), + ), + Expanded(child: _buildGroupsList(serverInfoState)) + ]))); + }); + } + + Widget _buildGroupsList(RemoteServerInfoState serverInfoState) { + final tiles = serverInfoState.groups.map( + (ContactInfoState group) { + return ChangeNotifierProvider.value( + value: group, + builder: (context, child) => RepaintBoundary(child: _buildGroupRow(group)), // ServerRow()), + ); + }, + ); + + final divided = ListTile.divideTiles( + context: context, + tiles: tiles, + ).toList(); + + var size = MediaQuery.of(context).size; + + int cols = ((size.width - 50) / 500).ceil(); + final double itemHeight = 60; // magic arbitary + final double itemWidth = (size.width - 50 /* magic padding guess */) / cols; + + return GridView.count(crossAxisCount: cols, childAspectRatio: (itemWidth / itemHeight), children: divided); + } + + Widget _buildGroupRow(ContactInfoState group) { + return Padding( + padding: const EdgeInsets.all(6.0), //border size + child: Column(children: [ + Text( + group.nickname, + style: Provider.of(context).biggerFont.apply(color: Provider.of(context).theme.portraitOnlineBorderColor), + softWrap: true, + overflow: TextOverflow.ellipsis, + ), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + group.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Provider.of(context).theme.portraitOnlineBorderColor), + ))) + ])); + } +} diff --git a/lib/views/serversview.dart b/lib/views/serversview.dart index 148d1daf..5e943b43 100644 --- a/lib/views/serversview.dart +++ b/lib/views/serversview.dart @@ -77,7 +77,7 @@ class _ServersView extends State { // Unlock Profiles actions.add(IconButton( icon: Icon(CwtchIcons.lock_open_24px), - color: Provider.of(context).servers.isEmpty ? Provider.of(context).theme.defaultButtonColor() : Provider.of(context).theme.mainTextColor(), + color: Provider.of(context).servers.isEmpty ? Provider.of(context).theme.defaultButtonColor : Provider.of(context).theme.mainTextColor, tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles, onPressed: _modalUnlockServers, )); diff --git a/lib/views/splashView.dart b/lib/views/splashView.dart index a5642f2d..33eb9097 100644 --- a/lib/views/splashView.dart +++ b/lib/views/splashView.dart @@ -27,8 +27,7 @@ class SplashView extends StatelessWidget { Padding( padding: const EdgeInsets.all(20.0), child: Text(appState.appError == "" ? "Loading Cwtch..." : appState.appError, - style: TextStyle( - fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor() : Provider.of(context).theme.textfieldErrorColor())), + style: TextStyle(fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor : Provider.of(context).theme.textfieldErrorColor)), ), Image(image: AssetImage("assets/Open_Privacy_Logo_lightoutline.png")), ])), diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index 46e88796..dddb7840 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -5,12 +5,13 @@ import 'package:provider/provider.dart'; // Provides a styled Text Field for use in Form Widgets. // Callers must provide a text controller, label helper text and a validator. class CwtchButtonTextField extends StatefulWidget { - CwtchButtonTextField({required this.controller, required this.onPressed, required this.icon, required this.tooltip, this.readonly = true}); + CwtchButtonTextField({required this.controller, required this.onPressed, required this.icon, required this.tooltip, this.readonly = true, this.labelText}); final TextEditingController controller; final Function()? onPressed; final Icon icon; final String tooltip; final bool readonly; + String? labelText; @override _CwtchButtonTextFieldState createState() => _CwtchButtonTextFieldState(); @@ -39,29 +40,31 @@ class _CwtchButtonTextFieldState extends State { focusNode: _focusNode, enableIMEPersonalizedLearning: false, decoration: InputDecoration( + labelText: widget.labelText, + labelStyle: TextStyle(color: theme.current().mainTextColor, backgroundColor: theme.current().textfieldBackgroundColor), suffixIcon: IconButton( onPressed: widget.onPressed, icon: widget.icon, padding: EdgeInsets.fromLTRB(0.0, 4.0, 2.0, 2.0), tooltip: widget.tooltip, enableFeedback: true, - color: theme.current().mainTextColor(), - highlightColor: theme.current().defaultButtonColor(), - focusColor: theme.current().defaultButtonActiveColor(), - splashColor: theme.current().defaultButtonActiveColor(), + color: theme.current().mainTextColor, + highlightColor: theme.current().defaultButtonColor, + focusColor: theme.current().defaultButtonActiveColor, + splashColor: theme.current().defaultButtonActiveColor, ), floatingLabelBehavior: FloatingLabelBehavior.never, filled: true, - fillColor: theme.current().textfieldBackgroundColor(), - focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), - focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), - errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), + fillColor: theme.current().textfieldBackgroundColor, + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), + focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), errorStyle: TextStyle( - color: theme.current().textfieldErrorColor(), + color: theme.current().textfieldErrorColor, fontWeight: FontWeight.bold, ), contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0))), + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0))), ); }); } diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index 93bbb655..5872dddb 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -23,7 +23,7 @@ class _ContactRowState extends State { var contact = Provider.of(context); return Card( clipBehavior: Clip.antiAlias, - color: Provider.of(context).selectedConversation == contact.onion ? Provider.of(context).theme.backgroundHilightElementColor() : null, + color: Provider.of(context).selectedConversation == contact.identifier ? Provider.of(context).theme.backgroundHilightElementColor : null, borderOnForeground: false, margin: EdgeInsets.all(0.0), child: InkWell( @@ -32,16 +32,16 @@ class _ContactRowState extends State { padding: const EdgeInsets.all(6.0), //border size child: ProfileImage( badgeCount: contact.unreadMessages, - badgeColor: Provider.of(context).theme.portraitContactBadgeColor(), - badgeTextColor: Provider.of(context).theme.portraitContactBadgeTextColor(), + badgeColor: Provider.of(context).theme.portraitContactBadgeColor, + badgeTextColor: Provider.of(context).theme.portraitContactBadgeTextColor, diameter: 64.0, imagePath: contact.imagePath, maskOut: !contact.isOnline(), border: contact.isOnline() - ? Provider.of(context).theme.portraitOnlineBorderColor() + ? Provider.of(context).theme.portraitOnlineBorderColor : contact.isBlocked - ? Provider.of(context).theme.portraitBlockedBorderColor() - : Provider.of(context).theme.portraitOfflineBorderColor()), + ? Provider.of(context).theme.portraitBlockedBorderColor + : Provider.of(context).theme.portraitOfflineBorderColor), ), Expanded( child: Padding( @@ -55,20 +55,20 @@ class _ContactRowState extends State { style: TextStyle( fontSize: Provider.of(context).theme.contactOnionTextSize(), color: contact.isBlocked - ? Provider.of(context).theme.portraitBlockedTextColor() - : Provider.of(context).theme.mainTextColor()), //Provider.of(context).biggerFont, + ? Provider.of(context).theme.portraitBlockedTextColor + : Provider.of(context).theme.mainTextColor), //Provider.of(context).biggerFont, softWrap: true, overflow: TextOverflow.visible, ), Visibility( visible: contact.isGroup && contact.status == "Authenticated", child: LinearProgressIndicator( - color: Provider.of(context).theme.defaultButtonActiveColor(), + color: Provider.of(context).theme.defaultButtonActiveColor, )), Visibility( visible: !Provider.of(context).streamerMode, child: Text(contact.onion, - style: TextStyle(color: contact.isBlocked ? Provider.of(context).theme.portraitBlockedTextColor() : Provider.of(context).theme.mainTextColor())), + style: TextStyle(color: contact.isBlocked ? Provider.of(context).theme.portraitBlockedTextColor : Provider.of(context).theme.mainTextColor)), ) ], ))), @@ -81,7 +81,7 @@ class _ContactRowState extends State { iconSize: 16, icon: Icon( Icons.favorite, - color: Provider.of(context).theme.mainTextColor(), + color: Provider.of(context).theme.mainTextColor, ), tooltip: AppLocalizations.of(context)!.tooltipAcceptContactRequest, onPressed: _btnApprove, @@ -89,7 +89,7 @@ class _ContactRowState extends State { IconButton( padding: EdgeInsets.zero, iconSize: 16, - icon: Icon(Icons.delete, color: Provider.of(context).theme.mainTextColor()), + icon: Icon(Icons.delete, color: Provider.of(context).theme.mainTextColor), tooltip: AppLocalizations.of(context)!.tooltipRejectContactRequest, onPressed: _btnReject, ) @@ -98,7 +98,7 @@ class _ContactRowState extends State { ? IconButton( padding: EdgeInsets.zero, iconSize: 16, - icon: Icon(Icons.block, color: Provider.of(context).theme.mainTextColor()), + icon: Icon(Icons.block, color: Provider.of(context).theme.mainTextColor), onPressed: () {}, ) : Text(dateToNiceString(contact.lastMessageTime))), diff --git a/lib/widgets/cwtchlabel.dart b/lib/widgets/cwtchlabel.dart index b354c778..07ac3874 100644 --- a/lib/widgets/cwtchlabel.dart +++ b/lib/widgets/cwtchlabel.dart @@ -18,7 +18,7 @@ class _CwtchLabelState extends State { return Consumer(builder: (context, theme, child) { return Text( widget.label, - style: TextStyle(fontSize: 20, color: theme.current().mainTextColor()), + style: TextStyle(fontSize: 20, color: theme.current().mainTextColor), ); }); } diff --git a/lib/widgets/filebubble.dart b/lib/widgets/filebubble.dart index ea26052a..fd49e9fe 100644 --- a/lib/widgets/filebubble.dart +++ b/lib/widgets/filebubble.dart @@ -61,7 +61,7 @@ class FileBubbleState extends State { var wdgSender = Center( widthFactor: 1, child: SelectableText(senderDisplayStr + '\u202F', - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()))); + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor))); var wdgMessage = !showFileSharing ? Text(AppLocalizations.of(context)!.messageEnableFileSharing) @@ -84,7 +84,7 @@ class FileBubbleState extends State { } else { wdgDecorations = LinearProgressIndicator( value: Provider.of(context).downloadProgress(widget.fileKey()), - color: Provider.of(context).theme.defaultButtonActiveColor(), + color: Provider.of(context).theme.defaultButtonActiveColor, ); } } else if (flagStarted) { @@ -114,9 +114,8 @@ class FileBubbleState extends State { widthFactor: 1.0, child: Container( decoration: BoxDecoration( - color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), - border: - Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), width: 1), + color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, + border: Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), topRight: Radius.circular(borderRadiousEh), @@ -196,7 +195,7 @@ class FileBubbleState extends State { SelectableText( chrome + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -205,7 +204,7 @@ class FileBubbleState extends State { SelectableText( fileName + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, fontWeight: FontWeight.bold, overflow: TextOverflow.ellipsis, ), @@ -216,7 +215,7 @@ class FileBubbleState extends State { SelectableText( prettyBytes(fileSize) + '\u202F' + '\n', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -225,7 +224,7 @@ class FileBubbleState extends State { subtitle: SelectableText( 'sha512: ' + rootHash + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, fontSize: 10, fontFamily: "monospace", ), @@ -233,7 +232,7 @@ class FileBubbleState extends State { maxLines: 4, textWidthBasis: TextWidthBasis.parent, ), - leading: Icon(Icons.attach_file, size: 32, color: Provider.of(context).theme.messageFromMeTextColor())); + leading: Icon(Icons.attach_file, size: 32, color: Provider.of(context).theme.messageFromMeTextColor)); } // Construct an file chrome @@ -244,7 +243,7 @@ class FileBubbleState extends State { SelectableText( chrome + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -253,7 +252,7 @@ class FileBubbleState extends State { SelectableText( fileName + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, fontWeight: FontWeight.bold, overflow: TextOverflow.ellipsis, ), @@ -264,7 +263,7 @@ class FileBubbleState extends State { SelectableText( AppLocalizations.of(context)!.labelFilesize + ': ' + prettyBytes(fileSize) + '\u202F' + '\n', style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -273,7 +272,7 @@ class FileBubbleState extends State { subtitle: SelectableText( 'sha512: ' + rootHash + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, fontSize: 10, fontFamily: "monospace", ), @@ -281,13 +280,13 @@ class FileBubbleState extends State { maxLines: 4, textWidthBasis: TextWidthBasis.parent, ), - leading: Icon(Icons.attach_file, size: 32, color: Provider.of(context).theme.messageFromOtherTextColor()), + leading: Icon(Icons.attach_file, size: 32, color: Provider.of(context).theme.messageFromOtherTextColor), trailing: Visibility( visible: speed != "0 B/s", child: SelectableText( speed + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 1, diff --git a/lib/widgets/invitationbubble.dart b/lib/widgets/invitationbubble.dart index 483ed833..2839b550 100644 --- a/lib/widgets/invitationbubble.dart +++ b/lib/widgets/invitationbubble.dart @@ -56,7 +56,7 @@ class InvitationBubbleState extends State { var wdgSender = Center( widthFactor: 1, child: SelectableText(senderDisplayStr + '\u202F', - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()))); + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor))); // If we receive an invite for ourselves, treat it as a bug. The UI no longer allows this so it could have only come from // some kind of malfeasance. @@ -96,9 +96,8 @@ class InvitationBubbleState extends State { widthFactor: 1.0, child: Container( decoration: BoxDecoration( - color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), - border: - Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), width: 1), + color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, + border: Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), topRight: Radius.circular(borderRadiousEh), @@ -149,7 +148,7 @@ class InvitationBubbleState extends State { SelectableText( chrome + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -158,7 +157,7 @@ class InvitationBubbleState extends State { SelectableText( targetName + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -173,7 +172,7 @@ class InvitationBubbleState extends State { SelectableText( chrome + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, @@ -181,7 +180,7 @@ class InvitationBubbleState extends State { ), SelectableText( targetName + '\u202F', - style: TextStyle(color: Provider.of(context).theme.messageFromOtherTextColor()), + style: TextStyle(color: Provider.of(context).theme.messageFromOtherTextColor), textAlign: TextAlign.left, maxLines: 2, textWidthBasis: TextWidthBasis.longestLine, diff --git a/lib/widgets/messagebubble.dart b/lib/widgets/messagebubble.dart index ae68962b..469a1b5a 100644 --- a/lib/widgets/messagebubble.dart +++ b/lib/widgets/messagebubble.dart @@ -48,7 +48,7 @@ class MessageBubbleState extends State { } } var wdgSender = SelectableText(senderDisplayStr, - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor())); + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor)); var wdgMessage; @@ -58,7 +58,7 @@ class MessageBubbleState extends State { //key: Key(myKey), focusNode: _focus, style: TextStyle( - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, @@ -67,7 +67,7 @@ class MessageBubbleState extends State { wdgMessage = SelectableLinkify( text: widget.content + '\u202F', // TODO: onOpen breaks the "selectable" functionality. Maybe something to do with gesture handler? - options: LinkifyOptions(humanize: false), + options: LinkifyOptions(humanize: false, removeWww: false, looseUrl: true, defaultToHttps: true), linkifiers: [UrlLinkifier()], onOpen: (link) { _modalOpenLink(context, link); @@ -75,10 +75,10 @@ class MessageBubbleState extends State { //key: Key(myKey), focusNode: _focus, style: TextStyle( - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, ), linkStyle: TextStyle( - color: Provider.of(context).current().mainTextColor(), + color: Provider.of(context).current().mainTextColor, ), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, @@ -95,13 +95,11 @@ class MessageBubbleState extends State { child: Container( child: Container( decoration: BoxDecoration( - color: error - ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor()), + color: error ? malformedColor : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), border: Border.all( color: error ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor()), + : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), @@ -159,6 +157,7 @@ class MessageBubbleState extends State { onPressed: () async { if (await canLaunch(link.url)) { await launch(link.url); + Navigator.pop(bcontext); } else { throw 'Could not launch $link'; } diff --git a/lib/widgets/messagebubbledecorations.dart b/lib/widgets/messagebubbledecorations.dart index 22ba1e91..6b740ea9 100644 --- a/lib/widgets/messagebubbledecorations.dart +++ b/lib/widgets/messagebubbledecorations.dart @@ -25,8 +25,7 @@ class _MessageBubbleDecoration extends State { mainAxisSize: MainAxisSize.min, children: [ Text(widget.prettyDate, - style: - TextStyle(fontSize: 9.0, color: widget.fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()), + style: TextStyle(fontSize: 9.0, color: widget.fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor), textAlign: widget.fromMe ? TextAlign.right : TextAlign.left), !widget.fromMe ? SizedBox(width: 1, height: 1) @@ -35,14 +34,14 @@ class _MessageBubbleDecoration extends State { child: widget.ackd == true ? Tooltip( message: AppLocalizations.of(context)!.acknowledgedLabel, - child: Icon(Icons.check_circle_outline, color: Provider.of(context).theme.messageFromMeTextColor(), size: 16)) + child: Icon(Icons.check_circle_outline, color: Provider.of(context).theme.messageFromMeTextColor, size: 16)) : (widget.errored == true ? Tooltip( message: AppLocalizations.of(context)!.couldNotSendMsgError, - child: Icon(Icons.error_outline, color: Provider.of(context).theme.messageFromMeTextColor(), size: 16)) + child: Icon(Icons.error_outline, color: Provider.of(context).theme.messageFromMeTextColor, size: 16)) : Tooltip( message: AppLocalizations.of(context)!.pendingLabel, - child: Icon(Icons.hourglass_bottom_outlined, color: Provider.of(context).theme.messageFromMeTextColor(), size: 16)))) + child: Icon(Icons.hourglass_bottom_outlined, color: Provider.of(context).theme.messageFromMeTextColor, size: 16)))) ], )); } diff --git a/lib/widgets/messagelist.dart b/lib/widgets/messagelist.dart index 365a75fc..57009768 100644 --- a/lib/widgets/messagelist.dart +++ b/lib/widgets/messagelist.dart @@ -35,65 +35,66 @@ class _MessageListState extends State { return RepaintBoundary( child: Container( + color: Provider.of(context).theme.backgroundMainColor, child: Column(children: [ - Visibility( - visible: showMessageWarning, - child: Container( - padding: EdgeInsets.all(5.0), - color: Provider.of(context).theme.defaultButtonActiveColor(), - child: DefaultTextStyle( - style: TextStyle(color: Provider.of(context).theme.defaultButtonTextColor()), - child: showSyncing - ? Text(AppLocalizations.of(context)!.serverNotSynced, textAlign: TextAlign.center) - : showOfflineWarning - ? Text(Provider.of(context).isGroup ? AppLocalizations.of(context)!.serverConnectivityDisconnected : AppLocalizations.of(context)!.peerOfflineMessage, - textAlign: TextAlign.center) - // Only show the ephemeral status for peer conversations, not for groups... - : (showEphemeralWarning - ? Text(AppLocalizations.of(context)!.chatHistoryDefault, textAlign: TextAlign.center) - : - // We are not allowed to put null here, so put an empty text widget - Text("")), - ))), - Expanded( - child: Container( - // Only show broken heart is the contact is offline... - decoration: BoxDecoration( - image: Provider.of(outerContext).isOnline() - ? null - : DecorationImage( - fit: BoxFit.scaleDown, - alignment: Alignment.center, - image: AssetImage("assets/core/negative_heart_512px.png"), - colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementTextColor(), BlendMode.srcIn))), - // Don't load messages for syncing server... - child: loadMessages - ? ScrollablePositionedList.builder( - itemPositionsListener: widget.scrollListener, - itemScrollController: widget.scrollController, - initialScrollIndex: initi > 4 ? initi - 4 : 0, - itemCount: Provider.of(outerContext).totalMessages, - reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction... - itemBuilder: (itemBuilderContext, index) { - var profileOnion = Provider.of(outerContext, listen: false).onion; - var contactHandle = Provider.of(outerContext, listen: false).identifier; - var messageIndex = index; + Visibility( + visible: showMessageWarning, + child: Container( + padding: EdgeInsets.all(5.0), + color: Provider.of(context).theme.defaultButtonActiveColor, + child: DefaultTextStyle( + style: TextStyle(color: Provider.of(context).theme.defaultButtonTextColor), + child: showSyncing + ? Text(AppLocalizations.of(context)!.serverNotSynced, textAlign: TextAlign.center) + : showOfflineWarning + ? Text(Provider.of(context).isGroup ? AppLocalizations.of(context)!.serverConnectivityDisconnected : AppLocalizations.of(context)!.peerOfflineMessage, + textAlign: TextAlign.center) + // Only show the ephemeral status for peer conversations, not for groups... + : (showEphemeralWarning + ? Text(AppLocalizations.of(context)!.chatHistoryDefault, textAlign: TextAlign.center) + : + // We are not allowed to put null here, so put an empty text widget + Text("")), + ))), + Expanded( + child: Container( + // Only show broken heart is the contact is offline... + decoration: BoxDecoration( + image: Provider.of(outerContext).isOnline() + ? null + : DecorationImage( + fit: BoxFit.scaleDown, + alignment: Alignment.center, + image: AssetImage("assets/core/negative_heart_512px.png"), + colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementColor, BlendMode.srcIn))), + // Don't load messages for syncing server... + child: loadMessages + ? ScrollablePositionedList.builder( + itemPositionsListener: widget.scrollListener, + itemScrollController: widget.scrollController, + initialScrollIndex: initi > 4 ? initi - 4 : 0, + itemCount: Provider.of(outerContext).totalMessages, + reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction... + itemBuilder: (itemBuilderContext, index) { + var profileOnion = Provider.of(outerContext, listen: false).onion; + var contactHandle = Provider.of(outerContext, listen: false).identifier; + var messageIndex = index; - return FutureBuilder( - future: messageHandler(outerContext, profileOnion, contactHandle, messageIndex), - builder: (context, snapshot) { - if (snapshot.hasData) { - var message = snapshot.data as Message; - var key = Provider.of(outerContext, listen: false).getMessageKey(contactHandle, message.getMetadata().messageID); - return message.getWidget(context, key); - } else { - return MessageLoadingBubble(); - } - }, - ); - }, - ) - : null)) - ]))); + return FutureBuilder( + future: messageHandler(outerContext, profileOnion, contactHandle, messageIndex), + builder: (context, snapshot) { + if (snapshot.hasData) { + var message = snapshot.data as Message; + var key = Provider.of(outerContext, listen: false).getMessageKey(contactHandle, message.getMetadata().messageID); + return message.getWidget(context, key); + } else { + return MessageLoadingBubble(); + } + }, + ); + }, + ) + : null)) + ]))); } } diff --git a/lib/widgets/messagerow.dart b/lib/widgets/messagerow.dart index 9941fb52..98f353c2 100644 --- a/lib/widgets/messagerow.dart +++ b/lib/widgets/messagerow.dart @@ -85,7 +85,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi onPressed: () { Provider.of(context, listen: false).selectedIndex = Provider.of(context, listen: false).messageID; }, - icon: Icon(Icons.reply, color: Provider.of(context).theme.dropShadowColor()))); + icon: Icon(Icons.reply, color: Provider.of(context).theme.dropShadowColor))); Widget wdgSpacer = Flexible(child: SizedBox(width: 60, height: 10)); var widgetRow = []; @@ -96,7 +96,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi actualMessage, ]; } else if (isBlocked && !showBlockedMessage) { - Color blockedMessageBackground = Provider.of(context).theme.messageFromOtherBackgroundColor(); + Color blockedMessageBackground = Provider.of(context).theme.messageFromOtherBackgroundColor; Widget wdgPortrait = Padding(padding: EdgeInsets.all(4.0), child: Icon(CwtchIcons.account_blocked)); widgetRow = [ wdgPortrait, @@ -118,7 +118,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi AppLocalizations.of(context)!.blockedMessageMessage, //key: Key(myKey), style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.center, textWidthBasis: TextWidthBasis.longestLine, @@ -152,8 +152,9 @@ class MessageRowState extends State with SingleTickerProviderStateMi diameter: 48.0, imagePath: Provider.of(context).senderImage ?? contact.imagePath, //maskOut: contact.status != "Authenticated", - border: contact.status == "Authenticated" ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), - badgeTextColor: Colors.red, badgeColor: Colors.red, + border: contact.status == "Authenticated" ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, + badgeTextColor: Colors.red, + badgeColor: Colors.red, tooltip: isContact ? AppLocalizations.of(context)!.contactGoto.replaceFirst("%1", senderDisplayStr) : AppLocalizations.of(context)!.addContact, ))); @@ -216,8 +217,8 @@ class MessageRowState extends State with SingleTickerProviderStateMi Widget _bubbleNew() { return Container( decoration: BoxDecoration( - color: Provider.of(context).theme.messageFromMeBackgroundColor(), - border: Border.all(color: Provider.of(context).theme.messageFromMeBackgroundColor(), width: 1), + color: Provider.of(context).theme.messageFromMeBackgroundColor, + border: Border.all(color: Provider.of(context).theme.messageFromMeBackgroundColor, width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(8), diff --git a/lib/widgets/passwordfield.dart b/lib/widgets/passwordfield.dart index acd79787..e8cedd9d 100644 --- a/lib/widgets/passwordfield.dart +++ b/lib/widgets/passwordfield.dart @@ -53,21 +53,21 @@ class _CwtchTextFieldState extends State { }, icon: Icon((obscureText ? CwtchIcons.eye_closed : CwtchIcons.eye_open), semanticLabel: label), tooltip: label, - color: theme.current().mainTextColor(), - highlightColor: theme.current().defaultButtonColor(), - focusColor: theme.current().defaultButtonActiveColor(), - splashColor: theme.current().defaultButtonActiveColor(), + color: theme.current().mainTextColor, + highlightColor: theme.current().defaultButtonColor, + focusColor: theme.current().defaultButtonActiveColor, + splashColor: theme.current().defaultButtonActiveColor, ), errorStyle: TextStyle( - color: theme.current().textfieldErrorColor(), + color: theme.current().textfieldErrorColor, fontWeight: FontWeight.bold, ), - focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), - focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), - errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), + focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), filled: true, - fillColor: theme.current().textfieldBackgroundColor(), - enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), + fillColor: theme.current().textfieldBackgroundColor, + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), ), ); }); diff --git a/lib/widgets/profileimage.dart b/lib/widgets/profileimage.dart index 1516f3e0..f790a520 100644 --- a/lib/widgets/profileimage.dart +++ b/lib/widgets/profileimage.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:provider/provider.dart'; import '../settings.dart'; @@ -28,11 +28,11 @@ class _ProfileImageState extends State { filterQuality: FilterQuality.medium, // We need some theme specific blending here...we might want to consider making this a theme level attribute colorBlendMode: !widget.maskOut - ? Provider.of(context).theme.identifier() == "dark" + ? Provider.of(context).theme.mode == mode_dark ? BlendMode.softLight : BlendMode.darken : BlendMode.srcOut, - color: Provider.of(context).theme.backgroundHilightElementColor(), + color: Provider.of(context).theme.portraitBackgroundColor, isAntiAlias: true, width: widget.diameter, height: widget.diameter, diff --git a/lib/widgets/profilerow.dart b/lib/widgets/profilerow.dart index 39bce219..a5d9e418 100644 --- a/lib/widgets/profilerow.dart +++ b/lib/widgets/profilerow.dart @@ -32,11 +32,11 @@ class _ProfileRowState extends State { padding: const EdgeInsets.all(6.0), //border size child: ProfileImage( badgeCount: 0, - badgeColor: Provider.of(context).theme.portraitProfileBadgeColor(), - badgeTextColor: Provider.of(context).theme.portraitProfileBadgeTextColor(), + badgeColor: Provider.of(context).theme.portraitProfileBadgeColor, + badgeTextColor: Provider.of(context).theme.portraitProfileBadgeTextColor, diameter: 64.0, imagePath: profile.imagePath, - border: profile.isOnline ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor())), + border: profile.isOnline ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor)), Expanded( child: Column( children: [ @@ -60,7 +60,7 @@ class _ProfileRowState extends State { IconButton( enableFeedback: true, tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname, - icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor()), + icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor), onPressed: () { _pushEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath, encrypted: profile.isEncrypted); }, diff --git a/lib/widgets/quotedmessage.dart b/lib/widgets/quotedmessage.dart index 6d1854bc..e2af135e 100644 --- a/lib/widgets/quotedmessage.dart +++ b/lib/widgets/quotedmessage.dart @@ -42,13 +42,13 @@ class QuotedMessageBubbleState extends State { } } var wdgSender = SelectableText(senderDisplayStr, - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor())); + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor)); var wdgMessage = SelectableText( widget.body + '\u202F', focusNode: _focus, style: TextStyle( - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, @@ -61,11 +61,11 @@ class QuotedMessageBubbleState extends State { try { var qMessage = (snapshot.data! as Message); // Swap the background color for quoted tweets.. - var qTextColor = fromMe ? Provider.of(context).theme.messageFromOtherTextColor() : Provider.of(context).theme.messageFromMeTextColor(); + var qTextColor = fromMe ? Provider.of(context).theme.messageFromOtherTextColor : Provider.of(context).theme.messageFromMeTextColor; return Container( margin: EdgeInsets.all(5), padding: EdgeInsets.all(5), - color: fromMe ? Provider.of(context).theme.messageFromOtherBackgroundColor() : Provider.of(context).theme.messageFromMeBackgroundColor(), + color: fromMe ? Provider.of(context).theme.messageFromOtherBackgroundColor : Provider.of(context).theme.messageFromMeBackgroundColor, child: Wrap(runAlignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly, runSpacing: 1.0, crossAxisAlignment: WrapCrossAlignment.center, children: [ Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(Icons.reply, size: 32, color: qTextColor))), Center(widthFactor: 1.0, child: DefaultTextStyle(child: qMessage.getPreviewWidget(context), style: TextStyle(color: qTextColor))) @@ -90,13 +90,11 @@ class QuotedMessageBubbleState extends State { child: Container( child: Container( decoration: BoxDecoration( - color: error - ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor()), + color: error ? malformedColor : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), border: Border.all( color: error ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor()), + : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), diff --git a/lib/widgets/remoteserverrow.dart b/lib/widgets/remoteserverrow.dart new file mode 100644 index 00000000..e7b2417a --- /dev/null +++ b/lib/widgets/remoteserverrow.dart @@ -0,0 +1,74 @@ +import 'package:cwtch/main.dart'; +import 'package:cwtch/models/profileservers.dart'; +import 'package:cwtch/models/servers.dart'; +import 'package:cwtch/views/addeditservers.dart'; +import 'package:cwtch/views/remoteserverview.dart'; +import 'package:cwtch/widgets/profileimage.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import '../cwtch_icons_icons.dart'; +import '../errorHandler.dart'; +import '../model.dart'; +import '../settings.dart'; + +class RemoteServerRow extends StatefulWidget { + @override + _RemoteServerRowState createState() => _RemoteServerRowState(); +} + +class _RemoteServerRowState extends State { + @override + Widget build(BuildContext context) { + var server = Provider.of(context); + var description = server.description.isNotEmpty ? server.description : server.onion; + var running = server.status == "Synced"; + return Consumer(builder: (context, profile, child) { + return Card( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.all(0.0), + child: InkWell( + child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Padding( + padding: const EdgeInsets.all(6.0), //border size + child: Icon(CwtchIcons.dns_24px, + color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, size: 64)), + Expanded( + child: Column( + children: [ + Text( + description, + semanticsLabel: description, + style: Provider.of(context) + .biggerFont + .apply(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), + softWrap: true, + overflow: TextOverflow.ellipsis, + ), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + server.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), + ))) + ], + )), + ]), + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + settings: RouteSettings(name: "remoteserverview"), + builder: (BuildContext context) { + return MultiProvider( + providers: [Provider.value(value: profile), ChangeNotifierProvider(create: (context) => server), Provider.value(value: Provider.of(context))], + child: RemoteServerView(), + ); + })); + })); + }); + } +} diff --git a/lib/widgets/serverrow.dart b/lib/widgets/serverrow.dart index 9c12f477..2c245b51 100644 --- a/lib/widgets/serverrow.dart +++ b/lib/widgets/serverrow.dart @@ -26,54 +26,57 @@ class _ServerRowState extends State { margin: EdgeInsets.all(0.0), child: InkWell( child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: const EdgeInsets.all(6.0), //border size - child: Icon(CwtchIcons.dns_24px, - color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), size: 64)), - Expanded( - child: Column( - children: [ - Text( - server.description, - semanticsLabel: server.description, - style: Provider.of(context) - .biggerFont - .apply(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - Visibility( - visible: !Provider.of(context).streamerMode, - child: ExcludeSemantics( - child: Text( - server.onion, + Padding( + padding: const EdgeInsets.all(6.0), //border size + child: Icon(CwtchIcons.dns_24px, + color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, size: 64)), + Expanded( + child: Column( + children: [ + Text( + server.description, + semanticsLabel: server.description, + style: Provider.of(context) + .biggerFont + .apply(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), softWrap: true, overflow: TextOverflow.ellipsis, - style: TextStyle(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), - ))) - ], - )), + ), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + server.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), + ))) + ], + )), - // Copy server button - IconButton( - enableFeedback: true, - tooltip: AppLocalizations.of(context)!.copyServerKeys, - icon: Icon(CwtchIcons.address_copy_2, color: Provider.of(context).current().mainTextColor()), - onPressed: () { - Clipboard.setData(new ClipboardData(text: server.serverBundle)); - }, - ), + // Copy server button + IconButton( + enableFeedback: true, + tooltip: AppLocalizations.of(context)!.copyServerKeys, + icon: Icon(CwtchIcons.address_copy_2, color: Provider.of(context).current().mainTextColor), + onPressed: () { + Clipboard.setData(new ClipboardData(text: server.serverBundle)); + }, + ), - // Edit button - IconButton( - enableFeedback: true, - tooltip: AppLocalizations.of(context)!.editServerTitle, - icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor()), - onPressed: () { + // Edit button + IconButton( + enableFeedback: true, + tooltip: AppLocalizations.of(context)!.editServerTitle, + icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor), + onPressed: () { + _pushEditServer(server); + }, + ) + ]), + onTap: () { _pushEditServer(server); - }, - ) - ]))); + })); } void _pushEditServer(ServerInfoState server) { diff --git a/lib/widgets/textfield.dart b/lib/widgets/textfield.dart index 64b4f020..436bea19 100644 --- a/lib/widgets/textfield.dart +++ b/lib/widgets/textfield.dart @@ -7,9 +7,9 @@ doNothing(String x) {} // Provides a styled Text Field for use in Form Widgets. // Callers must provide a text controller, label helper text and a validator. class CwtchTextField extends StatefulWidget { - CwtchTextField({required this.controller, required this.labelText, this.validator, this.autofocus = false, this.onChanged = doNothing}); + CwtchTextField({required this.controller, required this.hintText, this.validator, this.autofocus = false, this.onChanged = doNothing}); final TextEditingController controller; - final String labelText; + final String hintText; final FormFieldValidator? validator; final Function(String) onChanged; final bool autofocus; @@ -42,20 +42,19 @@ class _CwtchTextFieldState extends State { enableIMEPersonalizedLearning: false, focusNode: _focusNode, decoration: InputDecoration( - labelText: widget.labelText, - labelStyle: TextStyle(color: theme.current().mainTextColor(), backgroundColor: theme.current().textfieldBackgroundColor()), + hintText: widget.hintText, floatingLabelBehavior: FloatingLabelBehavior.never, filled: true, - focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), - focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), - errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), + focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), errorStyle: TextStyle( - color: theme.current().textfieldErrorColor(), + color: theme.current().textfieldErrorColor, fontWeight: FontWeight.bold, ), - fillColor: theme.current().textfieldBackgroundColor(), + fillColor: theme.current().textfieldBackgroundColor, contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0))), + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0))), ); }); } diff --git a/lib/widgets/tor_icon.dart b/lib/widgets/tor_icon.dart index 796e2a5f..5bdebfa8 100644 --- a/lib/widgets/tor_icon.dart +++ b/lib/widgets/tor_icon.dart @@ -19,7 +19,7 @@ class _TorIconState extends State { return RepaintBoundary( child: Icon( Provider.of(context).progress == 0 ? CwtchIcons.onion_off : (Provider.of(context).progress == 100 ? CwtchIcons.onion_on : CwtchIcons.onion_waiting), - color: Provider.of(context).theme.mainTextColor(), + color: Provider.of(context).theme.mainTextColor, semanticLabel: Provider.of(context).progress == 100 ? AppLocalizations.of(context)!.networkStatusOnline : (Provider.of(context).progress == 0 ? AppLocalizations.of(context)!.networkStatusDisconnected : AppLocalizations.of(context)!.networkStatusAttemptingTor), diff --git a/regenerate_opaque_theme.sh b/regenerate_opaque_theme.sh deleted file mode 100755 index e4ff06d7..00000000 --- a/regenerate_opaque_theme.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -themes="/home/erinn/go/src/git.openprivacy.ca/openprivacy/opaque/theme" -outfile="./lib/opaque.dart" - -if [ -e "$outfile" ]; then - mv "$outfile" "${outfile}.bak" -fi - -echo "// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND AS CHANGES WILL BE OVERRIDDEN." > "$outfile" -echo "// TO EDIT THE THEME, SEE https://git.openprivacy.ca/openprivacy/opaque/" >> "$outfile" -echo "// FOR HOW THIS FILE IS GENERATED, SEE ../regenerate_opaque_theme.sh" >> "$outfile" - -sed 's/import QtQuick 2\.0//g' "${themes}/ThemeType.qml" | \ - sed "s/QtObject ./import 'dart:ui\';\nimport 'dart:core';\nabstract class OpaqueThemeType {\n static final Color red = Color(0xFFFF0000);/g" | \ - sed 's/\(property color\|var\)/Color/g' | \ - sed 's/\(:\| =\) ".*"/(){return red;}/g' >> "$outfile" - -echo -e "\n\n" >> "$outfile" - -sed 's/ThemeType/class CwtchDark extends OpaqueThemeType/g' "${themes}/CwtchDark.qml" | \ - sed 's/readonly property color \(.*\): "#\(\w*\)"/static final Color \1 = Color(0xFF\2);/g' | \ - sed 's/\(\w*\): \(\w*\)/Color \1() { return \2; }/g' >> "$outfile" - -echo -e "\n\n" >> "$outfile" - -sed 's/ThemeType/class CwtchLight extends OpaqueThemeType/g' "${themes}/CwtchLight.qml" | \ - sed 's/readonly property color \(.*\): "#\(\w*\)"/static final Color \1 = Color(0xFF\2);/g' | \ - sed 's/\(\w*\): \(\w*\)/Color \1() { return \2; }/g' >> "$outfile" - -echo -e "\n\n" >> "$outfile" - -sed 's/\(pragma Singleton\|import QtQuick 2\.0\)//g' "${themes}/Theme.qml" | \ - sed 's|//.*$||g' | \ - sed 's/theme\./current./g' | \ - sed 's/property color/property Color/g' | \ - sed 's/readonly property Color \(.*\): \([a-zA-Z0-9._]*\)/Color \1() { return \2(); }/g' | \ - #to preserve int values: #static int \1() { return \2; }/g' | \ - sed 's/readonly property int \(.*\): \(.*\)/int \1() { return \2; }/g' | \ - sed 's/readonly property variant \([a-zA-Z0-9._]*\): \(.*\)$/var \1 = \2;/g' | \ - sed 's/color/Color/g' | \ - sed 's/: \(.+\)/ = \1;/g' | \ - sed 's/property ThemeType \(\w*\): \(.*\)../static final OpaqueThemeType \1 = \2();/g' | \ - sed 's/final OpaqueThemeType theme = .*$/Opaque current() { return dark; }/' | \ - sed 's/^.*themeScaleNew.*$/int scale = 2;\n static final String gcdOS = "linux";/g' | \ - sed 's/gcd.os/gcdOS/g' | \ - sed 's/return \([a-zA-Z]\+\) ;/return \1();/g' | \ - sed 's/return \([a-zA-Z]\+\) + \([a-zA-Z]\+\);/return \1() + \2();/g' | \ - sed 's/Item/class Opaque extends OpaqueThemeType/' | \ - sed 's/current\./current()./g' >> "$outfile" diff --git a/test/buttontextfield_test.dart b/test/buttontextfield_test.dart index 2f750035..95c2d65a 100644 --- a/test/buttontextfield_test.dart +++ b/test/buttontextfield_test.dart @@ -5,8 +5,9 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/buttontextfield.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -14,8 +15,8 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var settingsEnglishDark = Settings(Locale("en", ''), OpaqueDark()); -var settingsEnglishLight = Settings(Locale("en", ''), OpaqueLight()); +var settingsEnglishDark = Settings(Locale("en", ''), CwtchDark()); +var settingsEnglishLight = Settings(Locale("en", ''), CwtchLight()); ChangeNotifierProvider getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark); void main() { diff --git a/test/cwtchlabel_test.dart b/test/cwtchlabel_test.dart index d0d077a1..63ad75b7 100644 --- a/test/cwtchlabel_test.dart +++ b/test/cwtchlabel_test.dart @@ -5,8 +5,9 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/cwtchlabel.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -14,8 +15,8 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var settingsEnglishDark = Settings(Locale("en", ''), OpaqueDark()); -var settingsEnglishLight = Settings(Locale("en", ''), OpaqueLight()); +var settingsEnglishDark = Settings(Locale("en", ''), CwtchDark()); +var settingsEnglishLight = Settings(Locale("en", ''), CwtchLight()); ChangeNotifierProvider getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark); void main() { diff --git a/test/profileimage_test.dart b/test/profileimage_test.dart index 9a841f9b..239aa5aa 100644 --- a/test/profileimage_test.dart +++ b/test/profileimage_test.dart @@ -5,8 +5,9 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/profileimage.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -14,8 +15,8 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var settingsEnglishDark = Settings(Locale("en", ''), OpaqueDark()); -var settingsEnglishLight = Settings(Locale("en", ''), OpaqueLight()); +var settingsEnglishDark = Settings(Locale("en", ''), CwtchDark()); +var settingsEnglishLight = Settings(Locale("en", ''), CwtchLight()); ChangeNotifierProvider getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark); String file(String slug) { @@ -33,10 +34,10 @@ void main() { Widget testWidget = ProfileImage( imagePath: "profiles/001-centaur.png", - badgeTextColor: settingsEnglishDark.theme.portraitProfileBadgeTextColor(), - badgeColor: settingsEnglishDark.theme.portraitProfileBadgeColor(), + badgeTextColor: settingsEnglishDark.theme.portraitProfileBadgeTextColor, + badgeColor: settingsEnglishDark.theme.portraitProfileBadgeColor, maskOut: false, - border: settingsEnglishDark.theme.portraitOfflineBorderColor(), + border: settingsEnglishDark.theme.portraitOfflineBorderColor, diameter: 64.0, badgeCount: 10, ); diff --git a/test/textfield_basic.png b/test/textfield_basic.png index 693afb1c..b17efd07 100644 Binary files a/test/textfield_basic.png and b/test/textfield_basic.png differ diff --git a/test/textfield_form_42.png b/test/textfield_form_42.png index 3d925698..abb2c137 100644 Binary files a/test/textfield_form_42.png and b/test/textfield_form_42.png differ diff --git a/test/textfield_form_alpha.png b/test/textfield_form_alpha.png index ef0f1d8c..531bb36a 100644 Binary files a/test/textfield_form_alpha.png and b/test/textfield_form_alpha.png differ diff --git a/test/textfield_form_final.png b/test/textfield_form_final.png index 2ad30d6e..d9087d17 100644 Binary files a/test/textfield_form_final.png and b/test/textfield_form_final.png differ diff --git a/test/textfield_form_init.png b/test/textfield_form_init.png index ed39bf8b..5c23672c 100644 Binary files a/test/textfield_form_init.png and b/test/textfield_form_init.png differ diff --git a/test/textfield_test.dart b/test/textfield_test.dart index 9a0f0525..27ea0f3e 100644 --- a/test/textfield_test.dart +++ b/test/textfield_test.dart @@ -6,7 +6,8 @@ // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; +import 'package:cwtch/themes/cwtch.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/textfield.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -14,8 +15,8 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var settingsEnglishDark = Settings(Locale("en", ''), OpaqueDark()); -var settingsEnglishLight = Settings(Locale("en", ''), OpaqueLight()); +var settingsEnglishDark = Settings(Locale("en", ''), CwtchDark()); +var settingsEnglishLight = Settings(Locale("en", ''), CwtchLight()); ChangeNotifierProvider getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark); String file(String slug) { @@ -27,7 +28,7 @@ void main() { tester.binding.window.physicalSizeTestValue = Size(800, 300); final TextEditingController ctrlr1 = TextEditingController(); - Widget testWidget = CwtchTextField(controller: ctrlr1, validator: (value) { }, labelText: '',); + Widget testWidget = CwtchTextField(controller: ctrlr1, validator: (value) { }, hintText: '',); Widget testHarness = MultiProvider( providers:[getSettingsEnglishDark()], @@ -69,7 +70,7 @@ void main() { Widget testWidget = CwtchTextField( controller: ctrlr1, - labelText: strLabel1, + hintText: strLabel1, validator: (value) { if (value == null || value == "") return strFail1; final number = num.tryParse(value);