Merge pull request 'contact wiring for newpeer' (#10) from erinnplods into newPeer

Reviewed-on: #10
This commit is contained in:
Sarah Jamie Lewis 2021-03-01 14:25:50 -08:00
commit 3e8a838aa7
26 changed files with 1193 additions and 165 deletions

View File

@ -1,16 +1,46 @@
# flutter_app
# flwtch
A new Flutter application.
## Getting Started
This project is a starting point for a Flutter application.
click the play button in android studio
A few resources to get you started if this is your first Flutter project:
## l10n
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
### Adding a new string
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
Strings are managed directly from our Lokalise(url?) project.
Keys should be valid Dart variable names in lowerCamelCase.
After adding a new key and providing/obtaining translations for it, follow the next step to update your local copy.
### Updating translations
Only Open Privacy staff members can update translations automatically:
```
flutter pub run flutter_lokalise download -v --api-token "<X>" --project-id "<Y>"
```
This will download a bundle of translations from Lokalise and convert it to resource files in `lib/l10n/intl_*.arb`.
The next time Flwtch is built, Flutter will notice the changes and update `app_localizations.dart` accordingly (thanks to `generate:true` in `pubspec.yaml`).
### Using a string
Any widget underneath the main MaterialApp should be able to:
```
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
```
and then use:
```
Text(AppLocalizations.of(context).stringIdentifer),
```
### Configuration
API tokens are only available to Open Privacy staff at this time, who will perform the translation updates for you as part of merging your PRs.
With `generate: true` in `pubspec.yaml`, the Flutter build process checks `l10n.yaml` for input/output filenames.

Binary file not shown.

3
l10n.yaml Normal file
View File

@ -0,0 +1,3 @@
arb-dir: lib/l10n
template-arb-file: intl_en.arb
output-localization-file: app_localizations.dart

View File

@ -6,7 +6,6 @@ import 'package:flutter_app/model.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:async';
import 'package:path/path.dart' as path;
import 'package:provider/provider.dart';
import 'cwtch.dart';
import 'cwtchNotifier.dart';

134
lib/l10n/intl_de.arb Normal file
View File

@ -0,0 +1,134 @@
{
"@@locale": "de",
"acceptGroupBtn": "Annehmen",
"acceptGroupInviteLabel": "Möchtest Du die Einladung annehmen",
"acknowledgedLabel": "bestätigt",
"addListItem": "Liste hinzufügen",
"addListItemBtn": "Element hinzufügen",
"addNewItem": "Ein neues Element zur Liste hinzufügen",
"addNewProfileBtn": "Neues Profil hinzufügen",
"addPeer": "Peer hinzufügen",
"addPeerTab": "Einen Peer hinzufügen",
"addProfileTitle": "Neues Profil hinzufügen",
"addressLabel": "Adresse",
"blockBtn": "Peer blockieren",
"blocked": "Blockiert",
"blockUnknownLabel": "Unbekannte Peers blockieren",
"builddate": "Aufgebaut auf: %2",
"bulletinsBtn": "Meldungen",
"chatBtn": "Chat",
"copiedClipboardNotification": "in die Zwischenablage kopiert",
"copiedToClipboardNotification": "in die Zwischenablage kopiert",
"copyBtn": "Kopieren",
"couldNotSendMsgError": "Nachricht konnte nicht gesendet werden",
"createGroup": "Gruppe erstellen",
"createGroupBtn": "Anlegen",
"createGroupTab": "Eine Gruppe erstellen",
"createGroupTitle": "Gruppe Anlegen",
"createProfileBtn": "Profil speichern",
"currentPasswordLabel": "derzeitiges Passwort",
"cwtchSettingsTitle": "Cwtch Einstellungen",
"cycleCatsAndroid": "",
"cycleCatsDesktop": "",
"cycleColoursAndroid": "",
"cycleColoursDesktop": "",
"cycleMorphsAndroid": "",
"cycleMorphsDesktop": "",
"defaultGroupName": "Tolle Gruppe",
"defaultProfileName": "Alice",
"defaultScalingText": "defaultmäßige Textgröße (Skalierungsfaktor:",
"deleteBtn": "Löschen",
"deleteConfirmLabel": "Geben Sie LÖSCHEN zur Bestätigung ein",
"deleteConfirmText": "LÖSCHEN",
"deleteProfileBtn": "Profil löschen",
"deleteProfileConfirmBtn": "Profil wirklich löschen",
"displayNameLabel": "Angezeigter Name",
"dmTooltip": "Klicken, um DM zu senden",
"dontSavePeerHistory": "Peer-Verlauf löschen",
"editProfile": "Profil bearbeiten",
"editProfileTitle": "Profil bearbeiten",
"enterProfilePassword": "Geben Sie ein Passwort ein, um Ihre Profile anzuzeigen",
"error0ProfilesLoadedForPassword": "0 Profile mit diesem Passwort geladen",
"experimentsEnabled": "Experimente aktiviert",
"groupAddr": "Adresse",
"groupName": "Gruppenname",
"groupNameLabel": "Gruppenname",
"invitation": "Einladung",
"invitationLabel": "Einladung",
"inviteBtn": "Einladen",
"inviteToGroupLabel": "In die Gruppe einladen",
"joinGroup": "Gruppe beitreten",
"joinGroupTab": "Einer Gruppe beitreten",
"largeTextLabel": "Groß",
"listsBtn": "Listen",
"loadingTor": "Tor wird geladen...",
"localeDe": "Deutsche",
"localeEn": "",
"localeEs": "",
"localeFr": "",
"localeIt": "",
"localePt": "",
"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.",
"networkStatusAttemptingTor": "Versuche, eine Verbindung mit dem Tor-Netzwerk herzustellen",
"networkStatusConnecting": "Verbinde zu Netzwerk und Peers ...",
"networkStatusDisconnected": "Vom Internet getrennt, überprüfen Sie Ihre Verbindung",
"networkStatusOnline": "Online",
"newBulletinLabel": "Neue Meldung",
"newConnectionPaneTitle": "Neue Verbindung",
"newGroupBtn": "Neue Gruppe anlegen",
"newProfile": "Neues Profil",
"noPasswordWarning": "Wenn für dieses Konto kein Passwort verwendet wird, bedeutet dies, dass alle lokal gespeicherten Daten nicht verschlüsselt werden.",
"password": "Passwort",
"password1Label": "Passwort",
"password2Label": "Passwort erneut eingeben",
"passwordChangeError": "Fehler beim Ändern des Passworts: Das Passwort wurde abgelehnt",
"passwordErrorEmpty": "Passwort kann nicht leer sein",
"passwordErrorMatch": "Passwörter stimmen nicht überein",
"pasteAddressToAddContact": "Adresse hier hinzufügen, um einen Kontakt aufzunehmen",
"peerAddress": "Adresse",
"peerBlockedMessage": "Peer ist blockiert",
"peerName": "Namen",
"peerNotOnline": "",
"peerOfflineMessage": "Peer ist offline, Nachrichten können derzeit nicht zugestellt werden",
"pendingLabel": "Bestätigung ausstehend",
"postNewBulletinLabel": "Neue Meldung veröffentlichen",
"profileName": "Anzeigename",
"profileOnionLabel": "Senden Sie diese Adresse an Peers, mit denen Sie sich verbinden möchten",
"puzzleGameBtn": "Puzzlespiel",
"radioNoPassword": "Unverschlüsselt (kein Passwort)",
"radioUsePassword": "Passwort",
"rejectGroupBtn": "Ablehnen",
"saveBtn": "Speichern",
"savePeerHistory": "Peer-Verlauf speichern",
"savePeerHistoryDescription": "Legt fest, ob ein mit dem Peer verknüpfter Verlauf gelöscht werden soll oder nicht.",
"saveProfileBtn": "Profil speichern",
"search": "Suche...",
"searchList": "",
"server": "Server",
"serverConnectivityConnected": "Server verbunden",
"serverConnectivityDisconnected": "Server getrennt",
"serverInfo": "Server-Informationen",
"serverLabel": "Server",
"serverNotSynced": "",
"serverSynced": "",
"settingInterfaceZoom": "Zoomstufe",
"settingLanguage": "Sprache",
"settingTheme": "Thema",
"smallTextLabel": "Klein",
"themeDark": "Dunkel",
"themeLight": "Licht",
"titlePlaceholder": "Titel...",
"todoPlaceholder": "noch zu erledigen",
"unblockBtn": "Peer entblockieren",
"unlock": "Entsperren",
"update": "",
"version": "Version %1",
"versionBuilddate": "Version: %1 Aufgebaut auf: %2",
"versionTor": "Version %1 mit tor %2",
"viewGroupMembershipTooltip": "Gruppenmitgliedschaft anzeigen",
"viewServerInfo": "",
"yourDisplayName": "Ihr Anzeigename",
"yourProfiles": "Ihre Profile",
"yourServers": "Ihre Server",
"zoomLabel": "Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)"
}

134
lib/l10n/intl_en.arb Normal file
View File

@ -0,0 +1,134 @@
{
"@@locale": "en",
"acceptGroupBtn": "Accept",
"acceptGroupInviteLabel": "Do you want to accept the invitation to",
"acknowledgedLabel": "Acknowledged",
"addListItem": "Add a New List Item",
"addListItemBtn": "Add Item",
"addNewItem": "Add a new item to the list",
"addNewProfileBtn": "Add new profile",
"addPeer": "Add Peer",
"addPeerTab": "Add a peer",
"addProfileTitle": "Add new profile",
"addressLabel": "Address",
"blockBtn": "Block Peer",
"blocked": "Blocked",
"blockUnknownLabel": "Block Unknown Peers",
"builddate": "Built on: %2",
"bulletinsBtn": "Bulletins",
"chatBtn": "Chat",
"copiedClipboardNotification": "Copied to clipboard",
"copiedToClipboardNotification": "Copied to Clipboard",
"copyBtn": "Copy",
"couldNotSendMsgError": "Could not send this message",
"createGroup": "Create group",
"createGroupBtn": "Create",
"createGroupTab": "Create a group",
"createGroupTitle": "Create Group",
"createProfileBtn": "Create Profile",
"currentPasswordLabel": "Current Password",
"cwtchSettingsTitle": "Cwtch Settings",
"cycleCatsAndroid": "Click to cycle category.\nLong-press to reset.",
"cycleCatsDesktop": "Click to cycle category.\nRight-click to reset.",
"cycleColoursAndroid": "Click to cycle colours.\nLong-press to reset.",
"cycleColoursDesktop": "Click to cycle colours.\nRight-click to reset.",
"cycleMorphsAndroid": "Click to cycle morphs.\nLong-press to reset.",
"cycleMorphsDesktop": "Click to cycle morphs.\nRight-click to reset.",
"defaultGroupName": "Awesome Group",
"defaultProfileName": "Alice",
"defaultScalingText": "Default size text (scale factor:",
"deleteBtn": "Delete",
"deleteConfirmLabel": "Type DELETE to confirm",
"deleteConfirmText": "DELETE",
"deleteProfileBtn": "Delete Profile",
"deleteProfileConfirmBtn": "Really Delete Profile",
"displayNameLabel": "Display Name",
"dmTooltip": "Click to DM",
"dontSavePeerHistory": "Delete Peer History",
"editProfile": "Edit Profille",
"editProfileTitle": "Edit Profile",
"enterProfilePassword": "Enter a password to view your profiles",
"error0ProfilesLoadedForPassword": "0 profiles loaded with that password",
"experimentsEnabled": "Experiments enabled",
"groupAddr": "Address",
"groupName": "Group name",
"groupNameLabel": "Group Name",
"invitation": "Invitation",
"invitationLabel": "Invitation",
"inviteBtn": "Invite",
"inviteToGroupLabel": "Invite to group",
"joinGroup": "Join group",
"joinGroupTab": "Join a group",
"largeTextLabel": "Large",
"listsBtn": "Lists",
"loadingTor": "Loading tor...",
"localeDe": "Deutsche",
"localeEn": "English",
"localeEs": "Espanol",
"localeFr": "Frances",
"localeIt": "Italiana",
"localePt": "Portuguesa",
"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.",
"networkStatusAttemptingTor": "Attempting to connect to Tor network",
"networkStatusConnecting": "Connecting to network and peers...",
"networkStatusDisconnected": "Disconnected from the internet, check your connection",
"networkStatusOnline": "Online",
"newBulletinLabel": "New Bulletin",
"newConnectionPaneTitle": "New Connection",
"newGroupBtn": "Create new group",
"newProfile": "New Profile",
"noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted",
"password": "Password",
"password1Label": "Password",
"password2Label": "Reenter password",
"passwordChangeError": "Error changing password: Supplied password rejected",
"passwordErrorEmpty": "Password cannot be empty",
"passwordErrorMatch": "Passwords do not match",
"pasteAddressToAddContact": "... paste an address here to add a contact...",
"peerAddress": "Address",
"peerBlockedMessage": "Peer is blocked",
"peerName": "Name",
"peerNotOnline": "Peer is Offline. Applications cannot be used right now.",
"peerOfflineMessage": "Peer is offline, messages can't be delivered right now",
"pendingLabel": "Pending",
"postNewBulletinLabel": "Post new bulletin",
"profileName": "Display name",
"profileOnionLabel": "Send this address to peers you want to connect with",
"puzzleGameBtn": "Puzzle Game",
"radioNoPassword": "Unencrypted (No password)",
"radioUsePassword": "Password",
"rejectGroupBtn": "Reject",
"saveBtn": "Save",
"savePeerHistory": "Save Peer History",
"savePeerHistoryDescription": "Determines whether or not to delete any history associated with the peer.",
"saveProfileBtn": "Save Profile",
"search": "Search...",
"searchList": "Search List",
"server": "Server",
"serverConnectivityConnected": "Server Connected",
"serverConnectivityDisconnected": "Server Disconnected",
"serverInfo": "Server Information",
"serverLabel": "Server",
"serverNotSynced": "Out of Sync",
"serverSynced": "Synced",
"settingInterfaceZoom": "Zoom level",
"settingLanguage": "Language",
"settingTheme": "Theme",
"smallTextLabel": "Small",
"themeDark": "Dark",
"themeLight": "Light",
"titlePlaceholder": "title...",
"todoPlaceholder": "Todo...",
"unblockBtn": "Unblock Peer",
"unlock": "Unlock",
"update": "Update",
"version": "Version %1",
"versionBuilddate": "Version: %1 Built on: %2",
"versionTor": "Version %1 with tor %2",
"viewGroupMembershipTooltip": "View Group Membership",
"viewServerInfo": "Server Info",
"yourDisplayName": "Your Display Name",
"yourProfiles": "Your Profiles",
"yourServers": "Your Servers",
"zoomLabel": "Interface zoom (mostly affects text and button sizes)"
}

134
lib/l10n/intl_es.arb Normal file
View File

@ -0,0 +1,134 @@
{
"@@locale": "es",
"acceptGroupBtn": "Aceptar",
"acceptGroupInviteLabel": "¿Quieres aceptar la invitación a ",
"acknowledgedLabel": "Reconocido",
"addListItem": "Añadir un nuevo elemento a la lista",
"addListItemBtn": "Agregar artículo",
"addNewItem": "Añadir un nuevo elemento a la lista",
"addNewProfileBtn": "Agregar nuevo perfil",
"addPeer": "Agregar Contacto",
"addPeerTab": "Agregar Contacto",
"addProfileTitle": "Agregar nuevo perfil",
"addressLabel": "Dirección",
"blockBtn": "Bloquear contacto",
"blocked": "Bloqueado",
"blockUnknownLabel": "Bloquear conexiones desconocidas",
"builddate": "Basado en: %2",
"bulletinsBtn": "Boletines",
"chatBtn": "Chat",
"copiedClipboardNotification": "Copiado al portapapeles",
"copiedToClipboardNotification": "Copiado al portapapeles",
"copyBtn": "Copiar",
"couldNotSendMsgError": "No se pudo enviar este mensaje",
"createGroup": "Crear perfil",
"createGroupBtn": "Crear",
"createGroupTab": "Crear un grupo",
"createGroupTitle": "Crear un grupo",
"createProfileBtn": "Crear perfil",
"currentPasswordLabel": "Contraseña actual",
"cwtchSettingsTitle": "Configuración de Cwtch",
"cycleCatsAndroid": "Click para cambiar categoría. Mantenga pulsado para reiniciar.",
"cycleCatsDesktop": "Click para cambiar categoría. Click derecho para reiniciar.",
"cycleColoursAndroid": "Click para cambiar colores. Mantenga pulsado para reiniciar.",
"cycleColoursDesktop": "Click para cambiar colores. Click derecho para reiniciar.",
"cycleMorphsAndroid": "Click para cambiar transformaciones. Mantenga pulsado para reiniciar.",
"cycleMorphsDesktop": "Click para cambiar transformaciones. Click derecho para reiniciar.",
"defaultGroupName": "El Grupo Asombroso",
"defaultProfileName": "Alicia",
"defaultScalingText": "Tamaño predeterminado de texto (factor de escala:",
"deleteBtn": "Eliminar",
"deleteConfirmLabel": "Escribe ELIMINAR para confirmar",
"deleteConfirmText": "ELIMINAR",
"deleteProfileBtn": "Eliminar Perfil",
"deleteProfileConfirmBtn": "Confirmar eliminar perfil",
"displayNameLabel": "Nombre de Usuario",
"dmTooltip": "Haz clic para enviar mensaje directo",
"dontSavePeerHistory": "Eliminar historial de contacto",
"editProfile": "Editar perfil",
"editProfileTitle": "Editar perfil",
"enterProfilePassword": "Ingresa tu contraseña para ver tus perfiles",
"error0ProfilesLoadedForPassword": "0 perfiles cargados con esa contraseña",
"experimentsEnabled": "Experimentos habilitados",
"groupAddr": "Dirección",
"groupName": "Nombre del grupo",
"groupNameLabel": "Nombre del grupo",
"invitation": "Invitación",
"invitationLabel": "Invitación",
"inviteBtn": "Invitar",
"inviteToGroupLabel": "Invitar al grupo",
"joinGroup": "Únete al grupo",
"joinGroupTab": "Únete a un grupo",
"largeTextLabel": "Grande",
"listsBtn": "Listas",
"loadingTor": "Cargando tor...",
"localeDe": "Alemán",
"localeEn": "Inglés",
"localeEs": "Español",
"localeFr": "Francés",
"localeIt": "Italiano",
"localePt": "Portugués",
"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",
"networkStatusAttemptingTor": "Intentando conectarse a la red Tor",
"networkStatusConnecting": "Conectando a la red y a los contactos...",
"networkStatusDisconnected": "Sin conexión, comprueba tu conexión",
"networkStatusOnline": "En línea",
"newBulletinLabel": "Nuevo Boletín",
"newConnectionPaneTitle": "Nueva conexión",
"newGroupBtn": "Crear un nuevo grupo de chat",
"newProfile": "Nuevo perfil",
"noPasswordWarning": "No usar una contraseña para esta cuenta significa que los datos almacenados localmente no serán encriptados",
"password": "Contraseña",
"password1Label": "Contraseña",
"password2Label": "Vuelve a ingresar tu contraseña",
"passwordChangeError": "Hubo un error cambiando tu contraseña: la contraseña ingresada fue rechazada",
"passwordErrorEmpty": "El campo de contraseña no puede estar vacío",
"passwordErrorMatch": "Las contraseñas no coinciden",
"pasteAddressToAddContact": "...pegar una dirección aquí para añadir un contacto...",
"peerAddress": "Dirección",
"peerBlockedMessage": "Contacto bloqueado",
"peerName": "Nombre",
"peerNotOnline": "Este contacto no está en línea, la aplicación no puede ser usada en este momento",
"peerOfflineMessage": "Este contacto no está en línea, los mensajes no pueden ser entregados en este momento",
"pendingLabel": "Pendiente",
"postNewBulletinLabel": "Publicar nuevo boletín",
"profileName": "Nombre de Usuario",
"profileOnionLabel": "Envía esta dirección a los contactos con los que quieras conectarte",
"puzzleGameBtn": "Juego de rompecabezas",
"radioNoPassword": "Sin cifrado (sin contraseña)",
"radioUsePassword": "Contraseña",
"rejectGroupBtn": "Rechazar",
"saveBtn": "Guardar",
"savePeerHistory": "Guardar el historial con contacto",
"savePeerHistoryDescription": "Determina si eliminar o no el historial asociado con el contacto.",
"saveProfileBtn": "Guardar perfil",
"search": "Búsqueda...",
"searchList": "Buscar en la lista",
"server": "Servidor",
"serverConnectivityConnected": "Servidor conectado",
"serverConnectivityDisconnected": "Servidor desconectado",
"serverInfo": "Información del servidor",
"serverLabel": "Servidor",
"serverNotSynced": "Fuera de sincronización con el servidor",
"serverSynced": "Sincronizado",
"settingInterfaceZoom": "Nivel de zoom",
"settingLanguage": "Idioma",
"settingTheme": "Tema",
"smallTextLabel": "Pequeño",
"themeDark": "Oscuro",
"themeLight": "Claro",
"titlePlaceholder": "título...",
"todoPlaceholder": "Por hacer...",
"unblockBtn": "Desbloquear contacto",
"unlock": "Desbloquear",
"update": "Actualizar",
"version": "Versión %1",
"versionBuilddate": "Versión: %1 Basado en %2",
"versionTor": "Versión %1 con tor %2",
"viewGroupMembershipTooltip": "Ver membresía del grupo",
"viewServerInfo": "Información del servidor",
"yourDisplayName": "Tu nombre de usuario",
"yourProfiles": "Tus perfiles",
"yourServers": "Tus servidores",
"zoomLabel": "Zoom de la interfaz (afecta principalmente el tamaño del texto y de los botones)"
}

134
lib/l10n/intl_fr.arb Normal file
View File

@ -0,0 +1,134 @@
{
"@@locale": "fr",
"acceptGroupBtn": "Accepter",
"acceptGroupInviteLabel": "Voulez-vous accepter l'invitation au groupe",
"acknowledgedLabel": "Confirmé",
"addListItem": "Ajouter un nouvel élément",
"addListItemBtn": "",
"addNewItem": "Ajouter un nouvel élément à la liste",
"addNewProfileBtn": "",
"addPeer": "",
"addPeerTab": "",
"addProfileTitle": "",
"addressLabel": "Adresse",
"blockBtn": "",
"blocked": "",
"blockUnknownLabel": "",
"builddate": "",
"bulletinsBtn": "Bulletins",
"chatBtn": "Discuter",
"copiedClipboardNotification": "Copié dans le presse-papier",
"copiedToClipboardNotification": "Copié dans le presse-papier",
"copyBtn": "Copier",
"couldNotSendMsgError": "Impossible d'envoyer ce message",
"createGroup": "",
"createGroupBtn": "Créer",
"createGroupTab": "",
"createGroupTitle": "Créer un groupe",
"createProfileBtn": "",
"currentPasswordLabel": "",
"cwtchSettingsTitle": "Préférences Cwtch",
"cycleCatsAndroid": "",
"cycleCatsDesktop": "",
"cycleColoursAndroid": "",
"cycleColoursDesktop": "",
"cycleMorphsAndroid": "",
"cycleMorphsDesktop": "",
"defaultGroupName": "Un super groupe",
"defaultProfileName": "",
"defaultScalingText": "Taille par défaut du texte (échelle:",
"deleteBtn": "Effacer",
"deleteConfirmLabel": "",
"deleteConfirmText": "",
"deleteProfileBtn": "",
"deleteProfileConfirmBtn": "",
"displayNameLabel": "Pseudo",
"dmTooltip": "Envoyer un message privé",
"dontSavePeerHistory": "",
"editProfile": "",
"editProfileTitle": "",
"enterProfilePassword": "",
"error0ProfilesLoadedForPassword": "",
"experimentsEnabled": "",
"groupAddr": "",
"groupName": "",
"groupNameLabel": "Nom du groupe",
"invitation": "",
"invitationLabel": "Invitation",
"inviteBtn": "Invitation",
"inviteToGroupLabel": "Inviter quelqu'un",
"joinGroup": "",
"joinGroupTab": "",
"largeTextLabel": "Large",
"listsBtn": "Listes",
"loadingTor": "",
"localeDe": "",
"localeEn": "",
"localeEs": "",
"localeFr": "",
"localeIt": "",
"localePt": "",
"membershipDescription": "Liste des utilisateurs ayant envoyés un ou plusieurs messages au groupe. Cette liste peut ne pas être representatives de l'ensemble des membres du groupe.",
"networkStatusAttemptingTor": "",
"networkStatusConnecting": "",
"networkStatusDisconnected": "",
"networkStatusOnline": "",
"newBulletinLabel": "Nouveau bulletin",
"newConnectionPaneTitle": "",
"newGroupBtn": "Créer un nouveau groupe",
"newProfile": "",
"noPasswordWarning": "",
"password": "",
"password1Label": "",
"password2Label": "",
"passwordChangeError": "",
"passwordErrorEmpty": "",
"passwordErrorMatch": "",
"pasteAddressToAddContact": "... coller une adresse ici pour ajouter un contact...",
"peerAddress": "",
"peerBlockedMessage": "",
"peerName": "",
"peerNotOnline": "",
"peerOfflineMessage": "",
"pendingLabel": "En attente",
"postNewBulletinLabel": "Envoyer un nouveau bulletin",
"profileName": "",
"profileOnionLabel": "",
"puzzleGameBtn": "Puzzle",
"radioNoPassword": "",
"radioUsePassword": "",
"rejectGroupBtn": "Refuser",
"saveBtn": "Sauvegarder",
"savePeerHistory": "",
"savePeerHistoryDescription": "",
"saveProfileBtn": "",
"search": "",
"searchList": "",
"server": "",
"serverConnectivityConnected": "",
"serverConnectivityDisconnected": "",
"serverInfo": "",
"serverLabel": "Serveur",
"serverNotSynced": "",
"serverSynced": "",
"settingInterfaceZoom": "",
"settingLanguage": "",
"settingTheme": "",
"smallTextLabel": "Petit",
"themeDark": "",
"themeLight": "",
"titlePlaceholder": "titre...",
"todoPlaceholder": "A faire...",
"unblockBtn": "",
"unlock": "",
"update": "",
"version": "",
"versionBuilddate": "",
"versionTor": "",
"viewGroupMembershipTooltip": "",
"viewServerInfo": "",
"yourDisplayName": "",
"yourProfiles": "",
"yourServers": "",
"zoomLabel": "Interface zoom (essentiellement la taille du texte et des composants de l'interface)"
}

134
lib/l10n/intl_it.arb Normal file
View File

@ -0,0 +1,134 @@
{
"@@locale": "it",
"acceptGroupBtn": "Accetta",
"acceptGroupInviteLabel": "Vuoi accettare l'invito a",
"acknowledgedLabel": "Riconosciuto",
"addListItem": "Aggiungi un nuovo elemento alla lista",
"addListItemBtn": "Aggiungi elemento",
"addNewItem": "Aggiungi un nuovo elemento alla lista",
"addNewProfileBtn": "Aggiungi nuovo profilo",
"addPeer": "Aggiungi peer",
"addPeerTab": "Aggiungi un peer",
"addProfileTitle": "Aggiungi nuovo profilo",
"addressLabel": "Indirizzo",
"blockBtn": "Blocca il peer",
"blocked": "Bloccato",
"blockUnknownLabel": "Blocca peer sconosciuti",
"builddate": "Costruito il: %2",
"bulletinsBtn": "Bollettini",
"chatBtn": "Chat",
"copiedClipboardNotification": "Copiato negli Appunti",
"copiedToClipboardNotification": "Copiato negli Appunti",
"copyBtn": "Copia",
"couldNotSendMsgError": "Impossibile inviare questo messaggio",
"createGroup": "Crea un gruppo",
"createGroupBtn": "Crea",
"createGroupTab": "Crea un gruppo",
"createGroupTitle": "Crea un gruppo",
"createProfileBtn": "Crea un profilo",
"currentPasswordLabel": "Password corrente",
"cwtchSettingsTitle": "Impostazioni di Cwtch",
"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.",
"cycleColoursAndroid": "Fare clic per scorrere i colori.\nPressione lunga per resettare.",
"cycleColoursDesktop": "Fare clic per scorrere i colori.\nCliccare con il tasto destro per resettare.",
"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.",
"defaultGroupName": "Gruppo fantastico",
"defaultProfileName": "Alice",
"defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:",
"deleteBtn": "Elimina",
"deleteConfirmLabel": "Digita ELIMINA per confermare",
"deleteConfirmText": "ELIMINA",
"deleteProfileBtn": "Elimina profilo",
"deleteProfileConfirmBtn": "Elimina realmente il profilo",
"displayNameLabel": "Nome visualizzato",
"dmTooltip": "Clicca per inviare un Messagio Diretto",
"dontSavePeerHistory": "Elimina cronologia dei peer",
"editProfile": "Modifica profilo",
"editProfileTitle": "Modifica profilo",
"enterProfilePassword": "Inserisci una password per visualizzare i tuoi profili",
"error0ProfilesLoadedForPassword": "0 profili caricati con quella password",
"experimentsEnabled": "Esperimenti abilitati",
"groupAddr": "Indirizzo",
"groupName": "Nome del gruppo",
"groupNameLabel": "Nome del gruppo",
"invitation": "Invito",
"invitationLabel": "Invito",
"inviteBtn": "Invitare",
"inviteToGroupLabel": "Invitare nel gruppo",
"joinGroup": "Unisciti al gruppo",
"joinGroupTab": "Unisciti a un gruppo",
"largeTextLabel": "Grande",
"listsBtn": "Liste",
"loadingTor": "Caricamento di tor...",
"localeDe": "Tedesco",
"localeEn": "Inglese",
"localeEs": "Spagnolo",
"localeFr": "Francese",
"localeIt": "Italiano",
"localePt": "Portoghese",
"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.",
"networkStatusAttemptingTor": "Tentativo di connessione alla rete Tor",
"networkStatusConnecting": "Connessione alla rete e ai peer ...",
"networkStatusDisconnected": "Disconnesso da Internet, controlla la tua connessione",
"networkStatusOnline": "Online",
"newBulletinLabel": "Nuovo bollettino",
"newConnectionPaneTitle": "Nuova connessione",
"newGroupBtn": "Crea un nuovo gruppo",
"newProfile": "Nuovo profilo",
"noPasswordWarning": "Non utilizzare una password su questo account significa che tutti i dati archiviati localmente non verranno criptati",
"password": "Password",
"password1Label": "Password",
"password2Label": "Reinserire la password",
"passwordChangeError": "Errore durante la modifica della password: password fornita rifiutata",
"passwordErrorEmpty": "La password non può essere vuota",
"passwordErrorMatch": "Le password non corrispondono",
"pasteAddressToAddContact": "... incolla qui un indirizzo per aggiungere un contatto ...",
"peerAddress": "Indirizzo",
"peerBlockedMessage": "Il peer è bloccato",
"peerName": "Nome",
"peerNotOnline": "Il peer è offline. Le applicazioni non possono essere utilizzate in questo momento.",
"peerOfflineMessage": "Il peer è offline, i messaggi non possono essere recapitati in questo momento",
"pendingLabel": "In corso",
"postNewBulletinLabel": "Pubblica un nuovo bollettino",
"profileName": "Nome visualizzato",
"profileOnionLabel": "Inviare questo indirizzo ai peer con cui si desidera connettersi",
"puzzleGameBtn": "Gioco di puzzle",
"radioNoPassword": "Non criptato (senza password)",
"radioUsePassword": "Password",
"rejectGroupBtn": "Rifiuta",
"saveBtn": "Salva",
"savePeerHistory": "Salva cronologia peer",
"savePeerHistoryDescription": "Determina se eliminare o meno ogni cronologia eventualmente associata al peer.",
"saveProfileBtn": "Salva il profilo",
"search": "Ricerca...",
"searchList": "Cerca nella lista",
"server": "Server",
"serverConnectivityConnected": "Server connesso",
"serverConnectivityDisconnected": "Server disconnesso",
"serverInfo": "Informazioni sul server",
"serverLabel": "Server",
"serverNotSynced": "Non sincronizzato",
"serverSynced": "Sincronizzato",
"settingInterfaceZoom": "Livello di zoom",
"settingLanguage": "Lingua",
"settingTheme": "Tema",
"smallTextLabel": "Piccolo",
"themeDark": "Scuro",
"themeLight": "Chiaro",
"titlePlaceholder": "titolo...",
"todoPlaceholder": "Da fare...",
"unblockBtn": "Sblocca il peer",
"unlock": "Sblocca",
"update": "Aggiornamento",
"version": "Versione %1",
"versionBuilddate": "Versione: %1 Costruito il: %2",
"versionTor": "Versione %1 con tor %2",
"viewGroupMembershipTooltip": "Visualizza i membri del gruppo",
"viewServerInfo": "Informazioni sul server",
"yourDisplayName": "Il tuo nome visualizzato",
"yourProfiles": "I tuoi profili",
"yourServers": "I tuoi server",
"zoomLabel": "Zoom dell'interfaccia (influisce principalmente sulle dimensioni del testo e dei pulsanti)"
}

134
lib/l10n/intl_pt.arb Normal file
View File

@ -0,0 +1,134 @@
{
"@@locale": "pt",
"acceptGroupBtn": "Aceitar",
"acceptGroupInviteLabel": "Você quer aceitar o convite para",
"acknowledgedLabel": "Confirmada",
"addListItem": "Adicionar Item à Lista",
"addListItemBtn": "",
"addNewItem": "Adicionar novo item à lista",
"addNewProfileBtn": "",
"addPeer": "",
"addPeerTab": "",
"addProfileTitle": "",
"addressLabel": "Endereço",
"blockBtn": "",
"blocked": "",
"blockUnknownLabel": "",
"builddate": "",
"bulletinsBtn": "Boletins",
"chatBtn": "Chat",
"copiedClipboardNotification": "Copiado",
"copiedToClipboardNotification": "Copiado",
"copyBtn": "Copiar",
"couldNotSendMsgError": "Não deu para enviar esta mensagem",
"createGroup": "",
"createGroupBtn": "Criar",
"createGroupTab": "",
"createGroupTitle": "Criar Grupo",
"createProfileBtn": "",
"currentPasswordLabel": "",
"cwtchSettingsTitle": "Configurações do Cwtch",
"cycleCatsAndroid": "",
"cycleCatsDesktop": "",
"cycleColoursAndroid": "",
"cycleColoursDesktop": "",
"cycleMorphsAndroid": "",
"cycleMorphsDesktop": "",
"defaultGroupName": "Grupo incrível",
"defaultProfileName": "",
"defaultScalingText": "Texto tamanho padrão (fator de escala: ",
"deleteBtn": "Deletar",
"deleteConfirmLabel": "",
"deleteConfirmText": "",
"deleteProfileBtn": "",
"deleteProfileConfirmBtn": "",
"displayNameLabel": "Nome de Exibição",
"dmTooltip": "Clique para DM",
"dontSavePeerHistory": "",
"editProfile": "",
"editProfileTitle": "",
"enterProfilePassword": "",
"error0ProfilesLoadedForPassword": "",
"experimentsEnabled": "",
"groupAddr": "",
"groupName": "",
"groupNameLabel": "Nome do Grupo",
"invitation": "",
"invitationLabel": "Convite",
"inviteBtn": "Convidar",
"inviteToGroupLabel": "Convidar ao grupo",
"joinGroup": "",
"joinGroupTab": "",
"largeTextLabel": "Grande",
"listsBtn": "Listas",
"loadingTor": "",
"localeDe": "",
"localeEn": "",
"localeEs": "",
"localeFr": "",
"localeIt": "",
"localePt": "",
"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.",
"networkStatusAttemptingTor": "",
"networkStatusConnecting": "",
"networkStatusDisconnected": "",
"networkStatusOnline": "",
"newBulletinLabel": "Novo Boletim",
"newConnectionPaneTitle": "",
"newGroupBtn": "Criar novo grupo",
"newProfile": "",
"noPasswordWarning": "",
"password": "",
"password1Label": "",
"password2Label": "",
"passwordChangeError": "",
"passwordErrorEmpty": "",
"passwordErrorMatch": "",
"pasteAddressToAddContact": "… cole um endereço aqui para adicionar um contato…",
"peerAddress": "",
"peerBlockedMessage": "",
"peerName": "",
"peerNotOnline": "",
"peerOfflineMessage": "",
"pendingLabel": "Pendente",
"postNewBulletinLabel": "Postar novo boletim",
"profileName": "",
"profileOnionLabel": "",
"puzzleGameBtn": "Jogo de Adivinhação",
"radioNoPassword": "",
"radioUsePassword": "",
"rejectGroupBtn": "Recusar",
"saveBtn": "Salvar",
"savePeerHistory": "",
"savePeerHistoryDescription": "",
"saveProfileBtn": "",
"search": "",
"searchList": "",
"server": "",
"serverConnectivityConnected": "",
"serverConnectivityDisconnected": "",
"serverInfo": "",
"serverLabel": "Servidor",
"serverNotSynced": "",
"serverSynced": "",
"settingInterfaceZoom": "",
"settingLanguage": "",
"settingTheme": "",
"smallTextLabel": "Pequeno",
"themeDark": "",
"themeLight": "",
"titlePlaceholder": "título…",
"todoPlaceholder": "Afazer…",
"unblockBtn": "",
"unlock": "",
"update": "",
"version": "",
"versionBuilddate": "",
"versionTor": "",
"viewGroupMembershipTooltip": "",
"viewServerInfo": "",
"yourDisplayName": "",
"yourProfiles": "",
"yourServers": "",
"zoomLabel": "Zoom da interface (afeta principalmente tamanho de texto e botões)"
}

View File

@ -1,4 +1,3 @@
import 'dart:collection';
import 'package:flutter_app/cwtch/ffi.dart';
import 'package:flutter_app/cwtch/gomobile.dart';
import 'package:flutter/material.dart';
@ -11,6 +10,7 @@ import 'views/profilemgrview.dart';
import 'views/splashView.dart';
import 'dart:io' show Platform;
import 'opaque.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() => runApp(Flwtch());
@ -72,6 +72,9 @@ class FlwtchState extends State<Flwtch> {
builder: (context, widget) {
return Consumer<OpaqueTheme>(
builder: (context, opaque, child) => MaterialApp(
locale: Locale("es",''),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
title: 'Cwtch',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,

View File

@ -1,17 +1,16 @@
import 'dart:convert';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter/cupertino.dart';
import 'dart:async';
import 'dart:collection';
import 'cwtch/cwtch.dart';
import 'main.dart';
////////////////////
/// UI State ///
////////////////////
//todo: delete
class ProfileModel {
String onion;
String nickname;
@ -20,6 +19,7 @@ class ProfileModel {
HashMap<String, ContactModel> contacts;
}
//todo: delete
class ContactModel {
String onion;
String nickname;
@ -32,9 +32,13 @@ class ContactModel {
ContactModel({this.onion, this.nickname, this.status, this.isInvitation, this.isBlocked, this.imagePath});
}
//todo: delete
class DanMessageModel {
// ignore: non_constant_identifier_names
String Timestamp;
// ignore: non_constant_identifier_names
bool Acknowledged;
// ignore: non_constant_identifier_names
String Message;
}
@ -81,6 +85,27 @@ class ContactListState extends ChangeNotifier {
List<ContactInfoState> _onions = [];
int get num => _onions.length;
ContactListState(Cwtch cwtch, String profileOnion) {
cwtch.GetContacts(profileOnion).then((jsonStr) {
if (jsonStr == null) return;
print("contacts: " + jsonStr);
List<dynamic> contacts = jsonDecode(jsonStr);
contacts.forEach((c) {
add(ContactInfoState(
profileOnion: profileOnion,
onion: c["onion"],
nickname: c["name"],
isGroup: false,
isInvitation: false,
isBlocked: false,
status: c["status"],
imagePath: "",
));
});
});
}
void addAll(Iterable<ContactInfoState> newOnions) {
_onions.addAll(newOnions);
notifyListeners();
@ -115,7 +140,7 @@ class ProfileInfoState extends ChangeNotifier {
String get nickname => this._nickname;
set nickname(String newValue) {
this.nickname = newValue;
this._nickname = newValue;
notifyListeners();
}
@ -130,6 +155,12 @@ class ProfileInfoState extends ChangeNotifier {
this._unreadMessages = newVal;
notifyListeners();
}
@override
void dispose() {
super.dispose();
print("profileinfostate.dispose()");
}
}
class ContactInfoState extends ChangeNotifier {
@ -158,6 +189,18 @@ class ContactInfoState extends ChangeNotifier {
notifyListeners();
}
get isInvitation => this._isInvitation;
set isInvitation(bool newVal) {
this._isInvitation = newVal;
notifyListeners();
}
get status => this._status;
set status(String newVal) {
this._status = newVal;
notifyListeners();
}
get unreadMessages => this._unreadMessages;
set unreadMessages(int newVal) {
this._unreadMessages = newVal;

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class AddContactView extends StatefulWidget {
@override
@ -10,7 +11,7 @@ class _AddContactViewState extends State<AddContactView> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add Contact'),
title: Text(AppLocalizations.of(context).newConnectionPaneTitle),
),
body: _buildForm(),
);
@ -22,9 +23,9 @@ class _AddContactViewState extends State<AddContactView> {
spacing: 20.0,
runSpacing: 20.0,
children: <Widget>[
Text("display name"),
Text("peer handle or group invite or server bundle"),
Text("Create/save"),
Text(AppLocalizations.of(context).profileName),
Text("peer handle or group invite or server bundle"),//todo
Text(AppLocalizations.of(context).createGroupBtn),
],
));
}

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../main.dart';
@ -26,7 +27,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text((widget.profileOnion == "" ? 'Add' : 'Edit') + ' Profile'),
title: Text(widget.profileOnion == "" ? AppLocalizations.of(context).addProfileTitle : AppLocalizations.of(context).editProfileTitle),
),
body: _buildForm(),
);
@ -38,15 +39,16 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
spacing: 20.0,
runSpacing: 20.0,
children: <Widget>[
Text("Display name"),
Text(AppLocalizations.of(context).displayNameLabel),
SizedBox(width:200, height: 60, child: TextField(controller: ctrlrNick,)),
widget.profileOnion == "" ? SizedBox(width:1,height:1,) : Text("Cwtch Address"),
widget.profileOnion == "" ? SizedBox(width:1,height:1,) : Text(AppLocalizations.of(context).addressLabel),
widget.profileOnion == "" ? SizedBox(width:1,height:1,) : SizedBox(width:200,height:60,child:TextField(controller: ctrlrOnion)),
Text("Password/unencrypted"),
Text("Password"),
Text(AppLocalizations.of(context).radioUsePassword),
Text(AppLocalizations.of(context).radioNoPassword),
Text(AppLocalizations.of(context).password1Label),
SizedBox(width:200, height: 60, child: TextField(controller: ctrlrPass,)),
Text("Confirm"),
ElevatedButton(onPressed: _createPressed, child: Text("do the thing"),),
Text(AppLocalizations.of(context).password2Label),
ElevatedButton(onPressed: _createPressed, child: Text(widget.profileOnion == "" ? AppLocalizations.of(context).addNewProfileBtn : AppLocalizations.of(context).saveProfileBtn),),
],
));
}

View File

@ -1,16 +1,13 @@
import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_app/widgets/contactrow.dart';
import 'package:provider/provider.dart';
import '../main.dart';
import '../opaque.dart';
import 'addcontactview.dart';
import 'messageview.dart';
import '../model.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class ContactsView extends StatefulWidget {
const ContactsView({Key key, this.profile}) : super(key: key);
final ProfileInfoState profile;
const ContactsView({Key key}) : super(key: key);
@override
_ContactsViewState createState() => _ContactsViewState();
@ -18,35 +15,38 @@ class ContactsView extends StatefulWidget {
class _ContactsViewState extends State<ContactsView> {
_ContactsViewState();
Map<String, ContactModel> _contacts = new HashMap<String, ContactModel>();
// Map<String, ContactModel> _contacts = new HashMap<String, ContactModel>();
@override
void didChangeDependencies() {
super.didChangeDependencies();
Provider.of<FlwtchState>(context).cwtch.GetContacts(widget.profile.onion).then((jsonContacts) {
print("got contact: $jsonContacts");
setState(() {
List<dynamic> contacts = jsonDecode(jsonContacts);
contacts.forEach((onion) {
_contacts.putIfAbsent(onion['onion'], () => ContactModel(onion: onion['onion'], nickname: onion['name'], status: onion['status']));
});
});
});
}
// @override
// void didChangeDependencies() {
// super.didChangeDependencies();
//
// Provider.of<ContactListState>(context).onions.forEach((contact) {
// _contacts.putIfAbsent(contact.onion, () => ContactModel(contact);
// });
// .cwtch.GetContacts(widget.profile.onion).then((jsonContacts) {
// print("got contact: $jsonContacts");
// setState(() {
// List<dynamic> contacts = jsonDecode(jsonContacts);
// contacts.forEach((onion) {
// _contacts.putIfAbsent(onion['onion'], () => ContactModel(onion: onion['onion'], nickname: onion['name'], status: onion['status']));
// });
// });
// });
// }
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.profile.nickname + '\'s contacts'),
title: Text("%1's contacts".replaceAll("%1", Provider.of<ProfileInfoState>(context).nickname ?? Provider.of<ProfileInfoState>(context).onion ?? '')),//todo
actions: [
IconButton(icon: Icon(Icons.copy), onPressed: _copyOnion,),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _pushAddContact,
tooltip: 'New Contact',
tooltip: AppLocalizations.of(context).newConnectionPaneTitle,
child: const Icon(Icons.person_add_sharp),
),
body: _buildContactList(),
@ -57,32 +57,11 @@ class _ContactsViewState extends State<ContactsView> {
return StreamBuilder<String>(
stream: Provider.of<FlwtchState>(context).appStatus.contactEvents(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
final tiles = _contacts.values.map(
(ContactModel contact) {
return ListTile(
leading: SizedBox(
width: 60,
height: 60,
child: ClipOval(
child: SizedBox(width:60, height:60, child:Container(color:Colors.white, width: 60, height: 60, child: Image(image: AssetImage("assets/profiles/001-centaur.png"), width:50,height:50,))),
//child: SizedBox(width:60, height:60, child:Container(color:Colors.white, width: 60, height: 60, child: Image(image: AssetImage(contact.imagePath), width:50,height:50,))),
),
),
trailing: contact.isInvitation != null && contact.isInvitation ? Column(children:<Widget>[Icon(Icons.favorite, color: Opaque.current().mainTextColor()),Icon(Icons.delete, color: Opaque.current().mainTextColor())]) : Text("99+"),//(nb: Icons.create is a pencil and we use it for "edit", not create)
title: Text(
contact.nickname,
style: Provider.of<FlwtchState>(context).biggerFont,
),
subtitle: Text(contact.status),
onTap: () {
setState(() {
var flwtch = Provider.of<FlwtchState>(context, listen:false);
flwtch.setState(() => flwtch.selectedConversation = contact.onion);
// case 2/3 handled by Double/TripleColumnView respectively
if (flwtch.columns.length == 1) _pushMessageView(contact.onion);
});
},
final tiles = Provider.of<ContactListState>(context).onions.map(
(ContactInfoState contact) {
return ChangeNotifierProvider<ContactInfoState>(
create: (context) => contact,
builder: (context, child) => ContactRow(),
);
},
);
@ -97,19 +76,6 @@ class _ContactsViewState extends State<ContactsView> {
);
}
void _pushMessageView(String handle) {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return Provider(
create: (_) => Provider.of<FlwtchState>(context),
child: MessageView(profile: widget.profile, conversationHandle: handle),
);
},
),
);
}
void _pushAddContact() {
Navigator.of(context).push(
MaterialPageRoute<void>(
@ -124,7 +90,7 @@ class _ContactsViewState extends State<ContactsView> {
}
void _copyOnion() {
final snackBar = SnackBar(content: Text('NYI:( Copied profile address to clipboard'));//todo
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification));//todo
// Find the Scaffold in the widget tree and use it to show a SnackBar.
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}

View File

@ -1,7 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/views/profilemgrview.dart';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import '../main.dart';
import 'contactsview.dart';
@ -21,11 +19,13 @@ class _DoubleColumnViewState extends State<DoubleColumnView> {
children: <Widget>[
Flexible(
flex: flwtch.columns[0],
child: ContactsView(profile: flwtch.selectedProfile),
child: ContactsView(),
),
Flexible(
flex: flwtch.columns[1],
child: flwtch.selectedConversation == "" ? Center(child:Text("pick a contact")) : Container(child:MessageView(profile:flwtch.selectedProfile, conversationHandle:flwtch.selectedConversation)),
child: flwtch.selectedConversation == "" ?
Center(child:Text("pick a contact")) : //dev
Container(child:MessageView(profile:flwtch.selectedProfile, conversationHandle:flwtch.selectedConversation)),
),
],
);

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/main.dart';
import 'package:flutter_app/opaque.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class GlobalSettingsView extends StatefulWidget {
@override
@ -21,7 +21,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cwtch Settings'),
title: Text(AppLocalizations.of(context).cwtchSettingsTitle),
),
body: _buildSettingsList(),
);
@ -32,14 +32,14 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
builder: (context, theme, child) {
return Center(child: Column(
children: [
Text("Language"),
Text(AppLocalizations.of(context).settingLanguage),
TextField(
controller: myController,
onChanged: (text) {
print("First text field: $text");
},
),
Text("Zoom"),
Text(AppLocalizations.of(context).settingInterfaceZoom),
SwitchListTile(
title: Text('Theme',
style: TextStyle(color: theme.current().mainTextColor())),
@ -54,11 +54,11 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
secondary: Icon(Icons.lightbulb_outline,
color: theme.current().mainTextColor()),
),
Text("Experiments enabled"),
Text("Text magnification reference"),
Text("Acknowledgements"),
Text("Version: xxx"),
Text("Built on: xxx"),
Text(AppLocalizations.of(context).experimentsEnabled),
Text("Text magnification reference"),//dev
Text("Acknowledgements"),//todo
Text(AppLocalizations.of(context).version),
Text(AppLocalizations.of(context).builddate),
]
));
}

View File

@ -1,11 +1,6 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_app/cwtch/cwtch.dart';
import 'package:provider/provider.dart';
import '../main.dart';
import '../model.dart';
import '../opaque.dart';
import '../widgets/messagelist.dart';
@ -64,27 +59,27 @@ class _MessageViewState extends State<MessageView> {
),
SizedBox(
width: 100,
height: 80,
child: Column(
children: <Widget>[
ElevatedButton(
child: Icon(Icons.send, color: Opaque.current().mainTextColor()),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonColor()),
), onPressed: _sendMessage,
),
Row (
children: <Widget>[
SizedBox(width:45, child:ElevatedButton(
child: Icon(Icons.emoji_emotions_outlined, color: Opaque.current().mainTextColor())
)),
SizedBox(width:45, child:ElevatedButton(
child: Icon(Icons.attach_file, color: Opaque.current().mainTextColor())
)),
]
)
]
),
height: 80,
child: Column(
children: <Widget>[
ElevatedButton(
child: Icon(Icons.send, color: Opaque.current().mainTextColor()),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonColor()),
), onPressed: _sendMessage,
),
Row (
children: <Widget>[
SizedBox(width:45, child:ElevatedButton(
child: Icon(Icons.emoji_emotions_outlined, color: Opaque.current().mainTextColor())
)),
SizedBox(width:45, child:ElevatedButton(
child: Icon(Icons.attach_file, color: Opaque.current().mainTextColor())
)),
]
)
]
),
),
],
),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_app/widgets/profilerow.dart';
import 'package:provider/provider.dart';
import '../main.dart';
@ -26,21 +27,26 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
Widget build(BuildContext context) {
return Scaffold (
appBar: AppBar(
title: Text('Profiles'),
title: Text(AppLocalizations.of(context).profileName),
actions: [
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _testChangingContactInfo),
IconButton(icon: Icon(Icons.lock_open), onPressed: _modalUnlockProfiles,),
IconButton(icon: Icon(Icons.settings), onPressed: _pushGlobalSettings),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _pushAddEditProfile,
tooltip: 'New Profile',
tooltip: AppLocalizations.of(context).addNewProfileBtn,
child: const Icon(Icons.add),
),
body: _buildProfileManager(),//_buildSuggestions(),
);
}
void _testChangingContactInfo() {
Provider.of<ProfileListState>(context, listen:false).onions.first.nickname = "yay!";
}
void _pushGlobalSettings() {
Navigator.of(context).push(
MaterialPageRoute<void>(
@ -79,17 +85,17 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Enter a password to view your profiles'),
Text(AppLocalizations.of(context).enterProfilePassword),
TextField(
obscureText: true,
controller: ctrlrPassword,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
labelText: AppLocalizations.of(context).password1Label,
),
),
ElevatedButton(
child: const Text('Unlock'),
child: Text(AppLocalizations.of(context).unlock),
onPressed: () {
Provider.of<FlwtchState>(context, listen: false).cwtch.LoadProfiles(ctrlrPassword.value.text);
Navigator.pop(context);
@ -105,9 +111,9 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
Widget _buildProfileManager() {
final tiles = Provider.of<ProfileListState>(context).onions.map(
(ProfileInfoState profile) {
return ChangeNotifierProvider<ProfileInfoState>(
create: (context) => profile,
builder: (context, child) => ProfileRow(profile),
return ChangeNotifierProvider<ProfileInfoState>.value(
value: profile,
builder: (context, child) => ProfileRow(),
);
},
);

View File

@ -24,11 +24,13 @@ class _TripleColumnViewState extends State<TripleColumnView> {
),
Flexible(
flex: flwtch.columns[1],
child: flwtch.selectedProfile == null ? Center(child:Text("pick a profile")) : ContactsView(profile:flwtch.selectedProfile),
child: flwtch.selectedProfile == null ? Center(child:Text("pick a profile")) : ContactsView(),//dev
),
Flexible(
flex: flwtch.columns[2],
child: flwtch.selectedConversation == "" ? Center(child:Text("pick a contact")) : Container(child:MessageView(profile:flwtch.selectedProfile, conversationHandle:flwtch.selectedConversation)),
child: flwtch.selectedConversation == "" ?
Center(child:Text("pick a contact")) : //dev
Container(child:MessageView(profile:flwtch.selectedProfile, conversationHandle:flwtch.selectedConversation)),
),
]
);

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/views/messageview.dart';
import 'package:provider/provider.dart';
import '../main.dart';
import '../model.dart';
import '../opaque.dart';
class ContactRow extends StatefulWidget {
@override
_ContactRowState createState() => _ContactRowState();
}
class _ContactRowState extends State<ContactRow> {
@override
Widget build(BuildContext context) {
var contact = Provider.of<ContactInfoState>(context);
return ListTile(
leading: SizedBox(
width: 60,
height: 60,
child: ClipOval(
child: SizedBox(width:60, height:60, child:Container(color:Colors.white, width: 60, height: 60, child: Image(image: AssetImage("assets/profiles/001-centaur.png"), width:50,height:50,))),
//child: SizedBox(width:60, height:60, child:Container(color:Colors.white, width: 60, height: 60, child: Image(image: AssetImage(contact.imagePath), width:50,height:50,))),
),
),
trailing: contact.isInvitation != null && contact.isInvitation ? Column(children:<Widget>[Icon(Icons.favorite, color: Opaque.current().mainTextColor()),Icon(Icons.delete, color: Opaque.current().mainTextColor())]) : Text("99+"),//(nb: Icons.create is a pencil and we use it for "edit", not create)
title: Text(
contact.nickname,
style: Provider.of<FlwtchState>(context).biggerFont,
),
subtitle: Text(contact.status),
onTap: () {
setState(() {
var flwtch = Provider.of<FlwtchState>(context, listen:false);
flwtch.setState(() => flwtch.selectedConversation = contact.onion);
// case 2/3 handled by Double/TripleColumnView respectively
if (flwtch.columns.length == 1) _pushMessageView(contact.onion);
});
},
);
}
void _pushMessageView(String handle) {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext builderContext) {
return MultiProvider(
providers: [ChangeNotifierProvider<ProfileInfoState>(create: (_) => Provider.of<ProfileInfoState>(context)),],
child: MessageView(conversationHandle: handle),
);
},
),
);
}
}

View File

@ -35,7 +35,7 @@ class _MessageListState extends State<MessageList> {
itemCount: conversationNumMessages,
itemBuilder: (context, index) {
return MessageBubble(
profile: widget.profile,
profile: Provider.of<ProfileInfoState>(context),
contactOnion: widget.conversationHandle,
messageIndex: index,
);
@ -50,7 +50,7 @@ class _MessageListState extends State<MessageList> {
return;
}
Provider.of<FlwtchState>(context, listen: false).cwtch.NumMessages(widget.profile.onion, widget.conversationHandle).then((n) {
Provider.of<FlwtchState>(context, listen: false).cwtch.NumMessages(Provider.of<ProfileInfoState>(context, listen: false).onion, widget.conversationHandle).then((n) {
if (n != conversationNumMessages) setState(() => conversationNumMessages = n);
});
}

View File

@ -9,9 +9,6 @@ import '../model.dart';
import '../opaque.dart';
class ProfileRow extends StatefulWidget {
final ProfileInfoState profile;
ProfileRow(this.profile);
@override
_ProfileRowState createState() => _ProfileRowState();
}
@ -19,35 +16,36 @@ class ProfileRow extends StatefulWidget {
class _ProfileRowState extends State<ProfileRow> {
@override
Widget build(BuildContext context) {
var profile = Provider.of<ProfileInfoState>(context);
return ListTile(
leading: SizedBox(
width: 60,
height: 60,
child: ClipOval(
child: SizedBox(width:60, height:60, child:Container(color:Colors.white, width: 60, height: 60, child: Image(image: AssetImage("assets/" + widget.profile.imagePath), width:50,height:50,))),
child: SizedBox(width:60, height:60, child:Container(color:Colors.white, width: 60, height: 60, child: Image(image: AssetImage("assets/" + profile.imagePath), width:50,height:50,))),
),
) ,
trailing: IconButton(
icon: Icon(Icons.create, color: Provider.of<OpaqueTheme>(context).current().mainTextColor()),
onPressed: () { _pushAddEditProfile(onion: widget.profile.onion); },
onPressed: () { _pushAddEditProfile(onion: profile.onion); },
),//(nb: Icons.create is a pencil and we use it for "edit", not create)
title: Text(
widget.profile.nickname,
profile.nickname,
style: Provider.of<FlwtchState>(context).biggerFont,
),
subtitle: Text(widget.profile.onion),
subtitle: Text(profile.onion),
onTap: () {
setState(() {
var flwtch = Provider.of<FlwtchState>(context, listen:false);
flwtch.cwtch.SelectProfile(widget.profile.onion);
flwtch.cwtch.SelectProfile(profile.onion);
flwtch.setState(() {
flwtch.selectedProfile = widget.profile;
flwtch.selectedProfile = profile;
flwtch.selectedConversation = "";
});
switch (flwtch.columns.length) {
case 1: _pushContactList(widget.profile, false); break;
case 2: _pushContactList(widget.profile, true); break;
case 1: _pushContactList(profile, false); break;
case 2: _pushContactList(profile, true); break;
} // case 3: handled by TripleColumnView
});
},
@ -57,10 +55,13 @@ class _ProfileRowState extends State<ProfileRow> {
void _pushContactList(ProfileInfoState profile, bool includeDoublePane) {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return Provider(
create: (_) => Provider.of<FlwtchState>(context),
child: includeDoublePane ? DoubleColumnView() : ContactsView(profile:profile),
builder: (BuildContext buildcontext) {
return MultiProvider(
providers: [
ChangeNotifierProvider<ProfileInfoState>.value(value: profile),
ChangeNotifierProvider<ContactListState>(create: (_) => ContactListState(Provider.of<FlwtchState>(buildcontext).cwtch, profile.onion),),
],
builder: (context, widget) => includeDoublePane ? DoubleColumnView() : ContactsView(),
);
},
),

View File

@ -1,10 +1,7 @@
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../main.dart';
import '../model.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class TorStatusLabel extends StatefulWidget {
@override
@ -22,7 +19,7 @@ class _TorStatusState extends State<TorStatusLabel> {
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
return Text(
snapshot.hasData ?
snapshot.data : "Tor not yet Connected",
snapshot.data : AppLocalizations.of(context).loadingTor,
style: Theme
.of(context)
.textTheme

View File

@ -1,6 +1,20 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.0"
async:
dependency: transitive
description:
@ -43,6 +57,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0-nullsafety.5"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
cupertino_icons:
dependency: "direct main"
description:
@ -70,24 +98,71 @@ packages:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.1"
version: "6.0.0-nullsafety.4"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lokalise:
dependency: "direct dev"
description:
name: flutter_lokalise
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
freezed_annotation:
dependency: transitive
description:
name: freezed_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.1"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.2"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
intl:
dependency: transitive
description:
name: intl
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.1"
version: "0.17.0-nullsafety.2"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "0.11.4"
matcher:
dependency: transitive
description:
@ -151,13 +226,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+3"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
version: "3.0.0"
plugin_platform_interface:
dependency: transitive
description:
@ -171,7 +253,7 @@ packages:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.13"
version: "4.0.0-nullsafety.4"
provider:
dependency: "direct main"
description:
@ -179,6 +261,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.2+3"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
sky_engine:
dependency: transitive
description: flutter
@ -212,6 +301,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety.3"
string_unescape:
dependency: transitive
description:
name: string_unescape
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.1"
term_glyph:
dependency: transitive
description:
@ -254,6 +350,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
sdks:
dart: ">=2.12.0-0.0 <3.0.0"
flutter: ">=1.16.0 <2.0.0"
flutter: ">=1.16.0"

View File

@ -24,7 +24,9 @@ dependencies:
flutter:
sdk: flutter
provider: "4.3.2+3"
#intl_translation: any
flutter_localizations:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
@ -35,12 +37,26 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lokalise: any
# alternatively: flutter pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/intl/app_localizations.dart lib/l10n/intl_*.arb --api-token X --project-id Y
#flutter_lokalise:
# project_id: ""
# api_token: ""
# include_tags:
# - tag1
# - tag2
flutter_intl:
enabled: true
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# makes flutter build/run generate app_localizations.dart (per l10n.yaml)
generate: true
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in