Compare commits

...

3 Commits

Author SHA1 Message Date
Sarah Jamie Lewis 7c587bf295 Flutter Upgrade + Translations 2021-06-07 15:12:24 -07:00
Sarah Jamie Lewis 54c2818cf2 Fix Self-Invitations
continuous-integration/drone/pr Build is passing Details
2021-06-07 14:15:19 -07:00
Sarah Jamie Lewis f3d713cfcc Fix invitation wrapping
continuous-integration/drone/pr Build is passing Details
2021-06-04 17:04:06 -07:00
17 changed files with 120 additions and 69 deletions

View File

@ -1,5 +1,6 @@
{
"@@locale": "de",
"accepted": "",
"acceptGroupBtn": "Annehmen",
"acceptGroupInviteLabel": "Möchtest Du die Einladung annehmen",
"acknowledgedLabel": "bestätigt",
@ -19,6 +20,7 @@
"chatBtn": "Chat",
"chatHistoryDefault": "",
"contactAlreadyExists": "",
"contactSuggestion": "",
"conversationSettings": "",
"copiedClipboardNotification": "in die Zwischenablage kopiert",
"copiedToClipboardNotification": "in die Zwischenablage kopiert",
@ -121,6 +123,7 @@
"radioNoPassword": "Unverschlüsselt (kein Passwort)",
"radioUsePassword": "Passwort",
"reallyLeaveThisGroupPrompt": "",
"rejected": "",
"rejectGroupBtn": "Ablehnen",
"saveBtn": "Speichern",
"savePeerHistory": "Peer-Verlauf speichern",
@ -128,6 +131,7 @@
"saveProfileBtn": "Profil speichern",
"search": "Suche...",
"searchList": "",
"sendAnInvitation": "",
"server": "Server",
"serverConnectivityConnected": "Server verbunden",
"serverConnectivityDisconnected": "Server getrennt",

View File

@ -1,5 +1,6 @@
{
"@@locale": "en",
"accepted": "Accepted!",
"acceptGroupBtn": "Accept",
"acceptGroupInviteLabel": "Do you want to accept the invitation to",
"acknowledgedLabel": "Acknowledged",
@ -19,6 +20,7 @@
"chatBtn": "Chat",
"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.",
"contactAlreadyExists": "Contact Already Exists",
"contactSuggestion": "This is a contact suggestion for: ",
"conversationSettings": "Conversation Settings",
"copiedClipboardNotification": "Copied to clipboard",
"copiedToClipboardNotification": "Copied to Clipboard",
@ -121,6 +123,7 @@
"radioNoPassword": "Unencrypted (No password)",
"radioUsePassword": "Password",
"reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.",
"rejected": "Rejected!",
"rejectGroupBtn": "Reject",
"saveBtn": "Save",
"savePeerHistory": "Save Peer History",
@ -128,6 +131,7 @@
"saveProfileBtn": "Save Profile",
"search": "Search...",
"searchList": "Search List",
"sendAnInvitation": "You sent an invitation for: ",
"server": "Server",
"serverConnectivityConnected": "Server Connected",
"serverConnectivityDisconnected": "Server Disconnected",

View File

@ -1,5 +1,6 @@
{
"@@locale": "es",
"accepted": "",
"acceptGroupBtn": "Aceptar",
"acceptGroupInviteLabel": "¿Quieres aceptar la invitación a ",
"acknowledgedLabel": "Reconocido",
@ -19,6 +20,7 @@
"chatBtn": "Chat",
"chatHistoryDefault": "",
"contactAlreadyExists": "",
"contactSuggestion": "",
"conversationSettings": "",
"copiedClipboardNotification": "Copiado al portapapeles",
"copiedToClipboardNotification": "Copiado al portapapeles",
@ -121,6 +123,7 @@
"radioNoPassword": "Sin cifrado (sin contraseña)",
"radioUsePassword": "Contraseña",
"reallyLeaveThisGroupPrompt": "",
"rejected": "",
"rejectGroupBtn": "Rechazar",
"saveBtn": "Guardar",
"savePeerHistory": "Guardar el historial con contacto",
@ -128,6 +131,7 @@
"saveProfileBtn": "Guardar perfil",
"search": "Búsqueda...",
"searchList": "Buscar en la lista",
"sendAnInvitation": "",
"server": "Servidor",
"serverConnectivityConnected": "Servidor conectado",
"serverConnectivityDisconnected": "Servidor desconectado",

View File

@ -1,5 +1,6 @@
{
"@@locale": "fr",
"accepted": "",
"acceptGroupBtn": "Accepter",
"acceptGroupInviteLabel": "Voulez-vous accepter l'invitation au groupe",
"acknowledgedLabel": "Confirmé",
@ -19,6 +20,7 @@
"chatBtn": "Discuter",
"chatHistoryDefault": "",
"contactAlreadyExists": "",
"contactSuggestion": "",
"conversationSettings": "",
"copiedClipboardNotification": "Copié dans le presse-papier",
"copiedToClipboardNotification": "Copié dans le presse-papier",
@ -121,6 +123,7 @@
"radioNoPassword": "",
"radioUsePassword": "",
"reallyLeaveThisGroupPrompt": "",
"rejected": "",
"rejectGroupBtn": "Refuser",
"saveBtn": "Sauvegarder",
"savePeerHistory": "",
@ -128,6 +131,7 @@
"saveProfileBtn": "",
"search": "",
"searchList": "",
"sendAnInvitation": "",
"server": "",
"serverConnectivityConnected": "",
"serverConnectivityDisconnected": "",

View File

@ -1,5 +1,6 @@
{
"@@locale": "it",
"accepted": "",
"acceptGroupBtn": "Accetta",
"acceptGroupInviteLabel": "Vuoi accettare l'invito a",
"acknowledgedLabel": "Riconosciuto",
@ -19,6 +20,7 @@
"chatBtn": "Chat",
"chatHistoryDefault": "",
"contactAlreadyExists": "",
"contactSuggestion": "",
"conversationSettings": "",
"copiedClipboardNotification": "Copiato negli Appunti",
"copiedToClipboardNotification": "Copiato negli Appunti",
@ -121,6 +123,7 @@
"radioNoPassword": "Non criptato (senza password)",
"radioUsePassword": "Password",
"reallyLeaveThisGroupPrompt": "",
"rejected": "",
"rejectGroupBtn": "Rifiuta",
"saveBtn": "Salva",
"savePeerHistory": "Salva cronologia peer",
@ -128,6 +131,7 @@
"saveProfileBtn": "Salva il profilo",
"search": "Ricerca...",
"searchList": "Cerca nella lista",
"sendAnInvitation": "",
"server": "Server",
"serverConnectivityConnected": "Server connesso",
"serverConnectivityDisconnected": "Server disconnesso",

View File

@ -1,5 +1,6 @@
{
"@@locale": "pt",
"accepted": "",
"acceptGroupBtn": "Aceitar",
"acceptGroupInviteLabel": "Você quer aceitar o convite para",
"acknowledgedLabel": "Confirmada",
@ -19,6 +20,7 @@
"chatBtn": "Chat",
"chatHistoryDefault": "",
"contactAlreadyExists": "",
"contactSuggestion": "",
"conversationSettings": "",
"copiedClipboardNotification": "Copiado",
"copiedToClipboardNotification": "Copiado",
@ -121,6 +123,7 @@
"radioNoPassword": "",
"radioUsePassword": "",
"reallyLeaveThisGroupPrompt": "",
"rejected": "",
"rejectGroupBtn": "Recusar",
"saveBtn": "Salvar",
"savePeerHistory": "",
@ -128,6 +131,7 @@
"saveProfileBtn": "",
"search": "",
"searchList": "",
"sendAnInvitation": "",
"server": "",
"serverConnectivityConnected": "",
"serverConnectivityDisconnected": "",

View File

@ -1383,6 +1383,8 @@ ThemeData mkThemeData(Settings opaque) {
)),
),
),
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(),

View File

@ -177,7 +177,9 @@ class _MessageViewState extends State<MessageView> {
),
ChangeNotifierProvider.value(
value: Provider.of<ProfileInfoState>(ctx, listen: false),
child: DropdownContacts(onChanged: (newVal) {
child: DropdownContacts(filter: (contact) {
return contact.onion != Provider.of<ContactInfoState>(context).onion;
}, onChanged: (newVal) {
setState(() {
this.selectedContact = newVal;
});

View File

@ -3,6 +3,10 @@ import 'package:provider/provider.dart';
import '../model.dart';
bool noFilter(ContactInfoState peer) {
return true;
}
// Dropdown menu populated from Provider.of<ProfileInfoState>'s contact list
// Includes both peers and groups; begins empty/nothing selected
// Displays nicknames to UI but uses handles as values
@ -10,8 +14,10 @@ import '../model.dart';
class DropdownContacts extends StatefulWidget {
DropdownContacts({
required this.onChanged,
this.filter = noFilter,
});
final Function(dynamic) onChanged;
final bool Function(ContactInfoState) filter;
@override
_DropdownContactsState createState() => _DropdownContactsState();
@ -24,7 +30,7 @@ class _DropdownContactsState extends State<DropdownContacts> {
Widget build(BuildContext context) {
return DropdownButton(
value: this.selected,
items: Provider.of<ProfileInfoState>(context, listen: false).contactList.contacts.map<DropdownMenuItem<String>>((ContactInfoState contact) {
items: Provider.of<ProfileInfoState>(context, listen: false).contactList.contacts.where(widget.filter).map<DropdownMenuItem<String>>((ContactInfoState contact) {
return DropdownMenuItem<String>(value: contact.onion, child: Text(contact.nickname));
}).toList(),
onChanged: (String? newVal) {

View File

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:cwtch/cwtch_icons_icons.dart';
import 'package:cwtch/widgets/malformedbubble.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../main.dart';
@ -54,24 +55,33 @@ class InvitationBubbleState extends State<InvitationBubble> {
style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor())));
// todo: translations
// 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.
var selfInvite = Provider.of<MessageState>(context).inviteNick == Provider.of<ProfileInfoState>(context).onion;
if (selfInvite) {
return MalformedBubble();
}
var wdgMessage = fromMe
? senderInviteChrome("You sent an invitation for", isGroup ? "a group" : Provider.of<MessageState>(context).message, myKey)
: inviteChrome(isGroup ? AppLocalizations.of(context)!.inviteToGroup : "This is a contact suggestion for:", Provider.of<MessageState>(context).inviteNick,
Provider.of<MessageState>(context).inviteTarget, myKey);
? senderInviteChrome(AppLocalizations.of(context)!.sendAnInvitation,
isGroup ? Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget)!.nickname : Provider.of<MessageState>(context).message, myKey)
: (inviteChrome(isGroup ? AppLocalizations.of(context)!.inviteToGroup : AppLocalizations.of(context)!.contactSuggestion, Provider.of<MessageState>(context).inviteNick,
Provider.of<MessageState>(context).inviteTarget, myKey));
Widget wdgDecorations;
if (fromMe) {
wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageState>(context).ackd, errored: Provider.of<MessageState>(context).error, fromMe: fromMe, prettyDate: prettyDate);
} else if (isAccepted) {
wdgDecorations = Text("Accepted!");
wdgDecorations = Text(AppLocalizations.of(context)!.accepted + '\u202F');
} else if (this.rejected) {
wdgDecorations = Text("Rejected.");
wdgDecorations = Text(AppLocalizations.of(context)!.rejected + '\u202F');
} else {
wdgDecorations = Center(
widthFactor: 1,
child: Row(children: [
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text("Reject"), onPressed: _btnReject)),
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text("Accept"), onPressed: _btnAccept)),
child: Wrap(children: [
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text(AppLocalizations.of(context)!.rejectGroupBtn + '\u202F'), onPressed: _btnReject)),
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text(AppLocalizations.of(context)!.acceptGroupBtn + '\u202F'), onPressed: _btnAccept)),
]));
}
@ -95,15 +105,16 @@ class InvitationBubbleState extends State<InvitationBubble> {
widthFactor: 1.0,
child: Padding(
padding: EdgeInsets.all(9.0),
child: Row(mainAxisSize: MainAxisSize.min, children: [
Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(4), child: Icon(CwtchIcons.send_invite, size: 32))),
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(CwtchIcons.send_invite, size: 32))),
Center(
widthFactor: 1.0,
child: Column(
crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations])),
widthFactor: 1.0,
child: Column(
crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations]),
)
])))));
});
}
@ -129,53 +140,49 @@ class InvitationBubbleState extends State<InvitationBubble> {
// Construct an invite chrome for the sender
Widget senderInviteChrome(String chrome, String targetName, String myKey) {
return Center(
widthFactor: 1,
child: Row(children: [
SelectableText(
chrome,
focusNode: _focus,
style: TextStyle(
color: Provider.of<Settings>(context).theme.messageFromMeTextColor(),
),
textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine,
),
SelectableText(
targetName + '\u202F',
key: Key(myKey),
focusNode: _focus,
style: TextStyle(
color: Provider.of<Settings>(context).theme.messageFromMeTextColor(),
),
textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine,
)
]));
return Wrap(children: [
SelectableText(
chrome + '\u202F',
style: TextStyle(
color: Provider.of<Settings>(context).theme.messageFromMeTextColor(),
),
textAlign: TextAlign.left,
maxLines: 2,
textWidthBasis: TextWidthBasis.longestLine,
),
SelectableText(
targetName + '\u202F',
key: Key(myKey),
style: TextStyle(
color: Provider.of<Settings>(context).theme.messageFromMeTextColor(),
),
textAlign: TextAlign.left,
maxLines: 2,
textWidthBasis: TextWidthBasis.longestLine,
)
]);
}
// Construct an invite chrome
Widget inviteChrome(String chrome, String targetName, String targetId, String myKey) {
return Center(
widthFactor: 1,
child: Row(children: [
SelectableText(
chrome,
focusNode: _focus,
style: TextStyle(
color: Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
),
textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine,
),
SelectableText(
targetName,
key: Key(myKey),
focusNode: _focus,
style: TextStyle(color: Provider.of<Settings>(context).theme.messageFromOtherTextColor()),
textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine,
)
]));
return Wrap(children: [
SelectableText(
chrome + '\u202F',
style: TextStyle(
color: Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
),
textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine,
maxLines: 2,
),
SelectableText(
targetName + '\u202F',
key: Key(myKey),
style: TextStyle(color: Provider.of<Settings>(context).theme.messageFromOtherTextColor()),
textAlign: TextAlign.left,
maxLines: 2,
textWidthBasis: TextWidthBasis.longestLine,
)
]);
}
}

View File

@ -39,7 +39,6 @@ class _MessageListState extends State<MessageList> {
)),
Expanded(
child: Scrollbar(
isAlwaysShown: true,
controller: ctrlr1,
child: Container(
// Only show broken heart is the contact is offline...
@ -54,7 +53,7 @@ class _MessageListState extends State<MessageList> {
child: ListView.builder(
controller: ctrlr1,
itemCount: Provider.of<ContactInfoState>(outerContext).totalMessages,
reverse: true,
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 trueIndex = Provider.of<ContactInfoState>(outerContext).totalMessages - index - 1;
return ChangeNotifierProvider(

View File

@ -94,7 +94,10 @@ class _MessageRowState extends State<MessageRow> {
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact));
final snackBar = SnackBar(
content: Text(AppLocalizations.of(context)!.successfullAddedContact),
duration: Duration(seconds: 2),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}

View File

@ -2,6 +2,8 @@
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
#include <window_size/window_size_plugin.h>

View File

@ -2,6 +2,8 @@
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_

View File

@ -21,7 +21,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "2.7.0"
boolean_selector:
dependency: transitive
description:
@ -191,7 +191,7 @@ packages:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.4.0"
nested:
dependency: transitive
description:
@ -392,7 +392,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "0.4.0"
typed_data:
dependency: transitive
description:
@ -450,7 +450,7 @@ packages:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.1"
version: "5.1.2"
sdks:
dart: ">=2.13.0 <3.0.0"
flutter: ">=1.20.0"

View File

@ -2,6 +2,8 @@
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
#include <window_size/window_size_plugin.h>

View File

@ -2,6 +2,8 @@
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_