Merge pull request 'Delete Profile / Leave Conversation + Translation Dump via Erinn' (#191) from beta_fixes into trunk
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Reviewed-on: #191
This commit is contained in:
commit
f08062c0fb
|
@ -1 +1 @@
|
|||
v0.0.2-63-g033de73-2021-06-11-21-41
|
||||
v0.0.2-66-g39187a7-2021-06-15-00-32
|
|
@ -203,11 +203,20 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
val groupName = (a.get("groupname") as? String) ?: "";
|
||||
Cwtch.createGroup(profile, server, groupName);
|
||||
}
|
||||
"DeleteProfile" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val groupHandle = (a.get("pass") as? String) ?: "";
|
||||
Cwtch.deleteProfile(profile, groupHandle);
|
||||
}
|
||||
"LeaveConversation" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val contactHandle = (a.get("contactHandle") as? String) ?: "";
|
||||
Cwtch.leaveConversation(profile, contactHandle);
|
||||
}
|
||||
"LeaveGroup" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val groupHandle = (a.get("groupHandle") as? String) ?: "";
|
||||
Log.i("FlwtchWorker.kt", "LeaveGroup: need to recompile aar and uncomment this line")//todo
|
||||
//Cwtch.leaveGroup(profile, groupHandle);
|
||||
Cwtch.leaveGroup(profile, groupHandle);
|
||||
}
|
||||
"RejectInvite" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:flutter/src/services/text_input.dart';
|
||||
|
||||
abstract class Cwtch {
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<dynamic> Start();
|
||||
|
@ -10,6 +12,8 @@ abstract class Cwtch {
|
|||
void CreateProfile(String nick, String pass);
|
||||
// ignore: non_constant_identifier_names
|
||||
void LoadProfiles(String pass);
|
||||
// ignore: non_constant_identifier_names
|
||||
void DeleteProfile(String onion, String pass);
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void ResetTor();
|
||||
|
@ -48,6 +52,9 @@ abstract class Cwtch {
|
|||
// ignore: non_constant_identifier_names
|
||||
void SendInvitation(String profile, String handle, String target);
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void LeaveConversation(String profile, String handle);
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void CreateGroup(String profile, String server, String groupName);
|
||||
// ignore: non_constant_identifier_names
|
||||
|
|
|
@ -64,6 +64,14 @@ class CwtchNotifier {
|
|||
profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(data["GroupID"], DateTime.now());
|
||||
}
|
||||
break;
|
||||
case "PeerDeleted":
|
||||
profileCN.delete(data["Identity"]);
|
||||
// todo standarize
|
||||
error.handleUpdate("deleteprofile.success");
|
||||
break;
|
||||
case "DeleteContact":
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.removeContact(data["RemotePeer"]);
|
||||
break;
|
||||
case "DeleteGroup":
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.removeContact(data["GroupID"]);
|
||||
break;
|
||||
|
@ -152,7 +160,10 @@ class CwtchNotifier {
|
|||
break;
|
||||
case "AppError":
|
||||
print("New App Error: $data");
|
||||
if (data["Data"] != null) {
|
||||
// special case for delete error (todo: standardize cwtch errors)
|
||||
if (data["Error"] == "Password did not match") {
|
||||
error.handleUpdate("deleteprofile.error");
|
||||
} else if (data["Data"] != null) {
|
||||
error.handleUpdate(data["Data"]);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
|||
import 'dart:isolate';
|
||||
import 'dart:io' show Platform;
|
||||
import 'package:cwtch/cwtch/cwtchNotifier.dart';
|
||||
import 'package:flutter/src/services/text_input.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
@ -385,15 +386,26 @@ class CwtchFfi implements Cwtch {
|
|||
CreateGroup(u1, u1.length, u2, u2.length, u3, u3.length);
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void LeaveConversation(String profileOnion, String handle) {
|
||||
var leaveConversation = library.lookup<NativeFunction<string_string_to_void_function>>("c_LeaveConversation");
|
||||
// ignore: non_constant_identifier_names
|
||||
final LeaveConversation = leaveConversation.asFunction<VoidFromStringStringFn>();
|
||||
final u1 = profileOnion.toNativeUtf8();
|
||||
final u2 = handle.toNativeUtf8();
|
||||
LeaveConversation(u1, u1.length, u2, u2.length);
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void LeaveGroup(String profileOnion, String groupHandle) {
|
||||
var leaveGroup = library.lookup<NativeFunction<string_string_to_void_function>>("c_LeaveGroup");
|
||||
// ignore: non_constant_identifier_names
|
||||
final RejectInvite = leaveGroup.asFunction<VoidFromStringStringFn>();
|
||||
final LeaveGroup = leaveGroup.asFunction<VoidFromStringStringFn>();
|
||||
final u1 = profileOnion.toNativeUtf8();
|
||||
final u2 = groupHandle.toNativeUtf8();
|
||||
RejectInvite(u1, u1.length, u2, u2.length);
|
||||
LeaveGroup(u1, u1.length, u2, u2.length);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -405,4 +417,15 @@ class CwtchFfi implements Cwtch {
|
|||
final utf8handle = handle.toNativeUtf8();
|
||||
updateMessageFlags(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index, flags);
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void DeleteProfile(String onion, String currentPassword) {
|
||||
var deleteprofile = library.lookup<NativeFunction<string_string_to_void_function>>("c_DeleteProfile");
|
||||
// ignore: non_constant_identifier_names
|
||||
final DeleteProfile = deleteprofile.asFunction<VoidFromStringStringFn>();
|
||||
final u1 = onion.toNativeUtf8();
|
||||
final u2 = currentPassword.toNativeUtf8();
|
||||
DeleteProfile(u1, u1.length, u2, u2.length);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,11 @@ class CwtchGomobile implements Cwtch {
|
|||
cwtchPlatform.invokeMethod("LoadProfiles", {"pass": pass});
|
||||
}
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void DeleteProfile(String onion, String pass) {
|
||||
cwtchPlatform.invokeMethod("DeleteProfile", {"onion": onion, "pass": pass});
|
||||
}
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<dynamic> ACNEvents() {
|
||||
return cwtchPlatform.invokeMethod("ACNEvents");
|
||||
|
@ -179,7 +184,7 @@ class CwtchGomobile implements Cwtch {
|
|||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void RejectInvite(String profileOnion, String groupHandle) {
|
||||
cwtchPlatform.invokeMethod("RejectInvite", {"ProfileOnion": profileOnion, "handle": groupHandle});
|
||||
cwtchPlatform.invokeMethod("RejectInvite", {"ProfileOnion": profileOnion, "groupHandle": groupHandle});
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -190,7 +195,13 @@ class CwtchGomobile implements Cwtch {
|
|||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void LeaveGroup(String profileOnion, String groupHandle) {
|
||||
cwtchPlatform.invokeMethod("LeaveGroup", {"ProfileOnion": profileOnion, "handle": groupHandle});
|
||||
cwtchPlatform.invokeMethod("LeaveGroup", {"ProfileOnion": profileOnion, "groupHandle": groupHandle});
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void LeaveConversation(String profileOnion, String contactHandle) {
|
||||
cwtchPlatform.invokeMethod("LeaveConversation", {"ProfileOnion": profileOnion, "contactHandle": contactHandle});
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -17,6 +17,10 @@ class ErrorHandler extends ChangeNotifier {
|
|||
bool importBundleError = false;
|
||||
bool importBundleSuccess = false;
|
||||
|
||||
static const String deleteProfileErrorPrefix = "deleteprofile";
|
||||
bool deleteProfileError = false;
|
||||
bool deleteProfileSuccess = false;
|
||||
|
||||
/// Called by the event bus.
|
||||
handleUpdate(String error) {
|
||||
var parts = error.split(".");
|
||||
|
@ -30,6 +34,9 @@ class ErrorHandler extends ChangeNotifier {
|
|||
case importBundleErrorPrefix:
|
||||
handleImportBundleError(errorType);
|
||||
break;
|
||||
case deleteProfileErrorPrefix:
|
||||
handleDeleteProfileError(errorType);
|
||||
break;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
|
@ -69,4 +76,19 @@ class ErrorHandler extends ChangeNotifier {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleDeleteProfileError(String errorType) {
|
||||
// Reset add contact errors
|
||||
deleteProfileError = false;
|
||||
deleteProfileSuccess = false;
|
||||
|
||||
switch (errorType) {
|
||||
case successErrorType:
|
||||
deleteProfileSuccess = true;
|
||||
break;
|
||||
default:
|
||||
deleteProfileError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,11 @@ class ProfileListState extends ChangeNotifier {
|
|||
int idx = _profiles.indexWhere((element) => element.onion == onion);
|
||||
return idx >= 0 ? _profiles[idx] : null;
|
||||
}
|
||||
|
||||
void delete(String onion) {
|
||||
_profiles.removeWhere((element) => element.onion == onion);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
class ContactListState extends ChangeNotifier {
|
||||
|
|
|
@ -167,7 +167,7 @@ class _AddContactViewState extends State<AddContactView> {
|
|||
Widget addGroupTab() {
|
||||
// TODO We should replace with with a "Paste in Server Key Bundle"
|
||||
if (Provider.of<ProfileInfoState>(context).serverList.servers.isEmpty) {
|
||||
return Text("You need to add a server before you can create a group.");
|
||||
return Text(AppLocalizations.of(context)!.addServerFirst);
|
||||
}
|
||||
|
||||
return Container(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -12,6 +13,7 @@ import 'package:provider/provider.dart';
|
|||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import '../cwtch_icons_icons.dart';
|
||||
import '../errorHandler.dart';
|
||||
import '../main.dart';
|
||||
import '../opaque.dart';
|
||||
import '../settings.dart';
|
||||
|
@ -100,7 +102,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
),
|
||||
CwtchTextField(
|
||||
controller: ctrlrNick,
|
||||
autofocus: true,
|
||||
autofocus: false,
|
||||
labelText: AppLocalizations.of(context)!.yourDisplayName,
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
|
@ -166,6 +168,9 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
|
||||
return AppLocalizations.of(context)!.passwordErrorEmpty;
|
||||
}
|
||||
if (Provider.of<ErrorHandler>(context).deleteProfileError == true) {
|
||||
return AppLocalizations.of(context)!.enterCurrentPasswordForDelete;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
|
@ -237,11 +242,9 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
Tooltip(
|
||||
message: AppLocalizations.of(context)!.enterCurrentPasswordForDelete,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: checkCurrentPassword()
|
||||
? null
|
||||
: () {
|
||||
showAlertDialog(context);
|
||||
},
|
||||
onPressed: () {
|
||||
showAlertDialog(context);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(primary: theme.current().defaultButtonColor()),
|
||||
icon: Icon(Icons.delete_forever),
|
||||
label: Text(AppLocalizations.of(context)!.deleteBtn),
|
||||
|
@ -307,52 +310,49 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO Stub - wire this into a libCwtch call.
|
||||
bool checkCurrentPassword() {
|
||||
return ctrlrOldPass.value.text.isEmpty;
|
||||
showAlertDialog(BuildContext context) {
|
||||
// set up the buttons
|
||||
Widget cancelButton = TextButton(
|
||||
child: Text(AppLocalizations.of(context)!.cancel),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // dismiss dialog
|
||||
},
|
||||
);
|
||||
Widget continueButton = TextButton(
|
||||
child: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn),
|
||||
onPressed: () {
|
||||
var onion = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.DeleteProfile(onion, ctrlrOldPass.value.text);
|
||||
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 500),
|
||||
() {
|
||||
if (globalErrorHandler.deleteProfileSuccess) {
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.deleteProfileSuccess + ":" + onion));
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
Navigator.of(context).popUntil((route) => route.isFirst); // dismiss dialog
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// set up the AlertDialog
|
||||
AlertDialog alert = AlertDialog(
|
||||
title: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn),
|
||||
actions: [
|
||||
cancelButton,
|
||||
continueButton,
|
||||
],
|
||||
);
|
||||
|
||||
// show the dialog
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
showAlertDialog(BuildContext context) {
|
||||
// set up the buttons
|
||||
Widget cancelButton = TextButton(
|
||||
child: Text("Cancel"),
|
||||
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))),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // dismiss dialog
|
||||
},
|
||||
);
|
||||
Widget continueButton = TextButton(
|
||||
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))),
|
||||
child: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn),
|
||||
onPressed: () {
|
||||
// TODO Actually Delete the Peer
|
||||
Navigator.of(context).pop(); // dismiss dialog
|
||||
},
|
||||
);
|
||||
|
||||
// set up the AlertDialog
|
||||
AlertDialog alert = AlertDialog(
|
||||
title: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn),
|
||||
actions: [
|
||||
cancelButton,
|
||||
continueButton,
|
||||
],
|
||||
);
|
||||
|
||||
// show the dialog
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import '../main.dart';
|
||||
import '../model.dart';
|
||||
import 'contactsview.dart';
|
||||
|
@ -27,7 +27,7 @@ class _DoubleColumnViewState extends State<DoubleColumnView> {
|
|||
Flexible(
|
||||
flex: flwtch.columns[1],
|
||||
child: flwtch.selectedConversation == ""
|
||||
? Center(child: Text("pick a contact"))
|
||||
? Center(child: Text(AppLocalizations.of(context)!.addContactFirst))
|
||||
: //dev
|
||||
MultiProvider(providers: [
|
||||
ChangeNotifierProvider.value(value: Provider.of<ProfileInfoState>(context)),
|
||||
|
|
|
@ -159,7 +159,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
|||
showAlertDialog(BuildContext context) {
|
||||
// set up the buttons
|
||||
Widget cancelButton = TextButton(
|
||||
child: Text("Cancel"),
|
||||
child: Text(AppLocalizations.of(context)!.cancel),
|
||||
style: ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.all(20))),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // dismiss dialog
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cwtch/cwtch_icons_icons.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -129,7 +130,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
child: TextFormField(
|
||||
key: Key('txtCompose'),
|
||||
controller: ctrlrCompose,
|
||||
autofocus: true,
|
||||
autofocus: !Platform.isAndroid,
|
||||
focusNode: focusNode,
|
||||
textInputAction: TextInputAction.send,
|
||||
onFieldSubmitted: _sendMessage,
|
||||
|
@ -139,11 +140,14 @@ class _MessageViewState extends State<MessageView> {
|
|||
enabled: true,
|
||||
prefixIcon: IconButton(
|
||||
icon: Icon(CwtchIcons.send_invite, size: 24, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||
tooltip: "Send a contact or group invite",
|
||||
tooltip: AppLocalizations.of(context)!.sendInvite,
|
||||
enableFeedback: true,
|
||||
splashColor: Provider.of<Settings>(context).theme.defaultButtonActiveColor(),
|
||||
hoverColor: Provider.of<Settings>(context).theme.defaultButtonActiveColor(),
|
||||
onPressed: () => _modalSendInvitation(context)),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(CwtchIcons.send_24px, size: 24, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||
tooltip: "Send Message",
|
||||
tooltip: AppLocalizations.of(context)!.sendMessage,
|
||||
onPressed: _sendMessage,
|
||||
),
|
||||
))),
|
||||
|
@ -189,10 +193,12 @@ class _MessageViewState extends State<MessageView> {
|
|||
),
|
||||
ElevatedButton(
|
||||
child: Text(AppLocalizations.of(bcontext)!.inviteBtn, semanticsLabel: AppLocalizations.of(bcontext)!.inviteBtn),
|
||||
onPressed: () {
|
||||
this._sendInvitation();
|
||||
Navigator.pop(bcontext);
|
||||
},
|
||||
onPressed: this.selectedContact == ""
|
||||
? null
|
||||
: () {
|
||||
this._sendInvitation();
|
||||
Navigator.pop(bcontext);
|
||||
},
|
||||
),
|
||||
],
|
||||
)),
|
||||
|
|
|
@ -78,7 +78,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
|||
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
|
||||
// todo translations
|
||||
final snackBar = SnackBar(content: Text("Nickname changed successfully"));
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.nickChangeSuccess));
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
},
|
||||
icon: Icon(Icons.save),
|
||||
|
@ -187,6 +187,22 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
|||
);
|
||||
}).toList())),
|
||||
]),
|
||||
Column(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Row(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, children: [
|
||||
Tooltip(
|
||||
message: AppLocalizations.of(context)!.leaveGroup,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
showAlertDialog(context);
|
||||
},
|
||||
icon: Icon(CwtchIcons.leave_chat),
|
||||
label: Text(AppLocalizations.of(context)!.leaveGroup),
|
||||
))
|
||||
])
|
||||
]),
|
||||
])))));
|
||||
});
|
||||
});
|
||||
|
@ -197,4 +213,44 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
|||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedClipboardNotification));
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}
|
||||
|
||||
showAlertDialog(BuildContext context) {
|
||||
// set up the buttons
|
||||
Widget cancelButton = TextButton(
|
||||
child: Text("Cancel"),
|
||||
style: ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.all(20))),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // dismiss dialog
|
||||
},
|
||||
);
|
||||
Widget continueButton = TextButton(
|
||||
style: ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.all(20))),
|
||||
child: Text(AppLocalizations.of(context)!.yesLeave),
|
||||
onPressed: () {
|
||||
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
||||
var handle = Provider.of<ContactInfoState>(context, listen: false).onion;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.LeaveConversation(profileOnion, handle);
|
||||
Future.delayed(Duration(milliseconds: 500), () {
|
||||
Navigator.of(context).popUntil((route) => route.settings.name == "conversations"); // dismiss dialog
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// set up the AlertDialog
|
||||
AlertDialog alert = AlertDialog(
|
||||
title: Text(AppLocalizations.of(context)!.reallyLeaveThisGroupPrompt),
|
||||
actions: [
|
||||
cancelButton,
|
||||
continueButton,
|
||||
],
|
||||
);
|
||||
|
||||
// show the dialog
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class _TorStatusView extends State<TorStatusView> {
|
|||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("Tor Network Status"),
|
||||
title: Text(AppLocalizations.of(context)!.torNetworkStatus),
|
||||
),
|
||||
body: _buildSettingsList(),
|
||||
);
|
||||
|
@ -43,10 +43,10 @@ class _TorStatusView extends State<TorStatusView> {
|
|||
child: Column(children: [
|
||||
ListTile(
|
||||
leading: TorIcon(),
|
||||
title: Text("Tor Status"),
|
||||
title: Text(AppLocalizations.of(context)!.torStatus),
|
||||
subtitle: Text(torStatus.progress == 100 ? AppLocalizations.of(context)!.networkStatusOnline : torStatus.status),
|
||||
trailing: ElevatedButton(
|
||||
child: Text("Reset"),
|
||||
child: Text(AppLocalizations.of(context)!.resetTor),
|
||||
onPressed: () {
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.ResetTor();
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:cwtch/views/profilemgrview.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import '../main.dart';
|
||||
import 'contactsview.dart';
|
||||
import 'messageview.dart';
|
||||
|
@ -22,12 +22,12 @@ class _TripleColumnViewState extends State<TripleColumnView> {
|
|||
),
|
||||
Flexible(
|
||||
flex: flwtch.columns[1],
|
||||
child: flwtch.selectedProfile == null ? Center(child: Text("pick a profile")) : ContactsView(), //dev
|
||||
child: flwtch.selectedProfile == null ? Center(child: Text(AppLocalizations.of(context)!.createProfileToBegin)) : ContactsView(), //dev
|
||||
),
|
||||
Flexible(
|
||||
flex: flwtch.columns[2],
|
||||
child: flwtch.selectedConversation == ""
|
||||
? Center(child: Text("pick a contact"))
|
||||
? Center(child: Text(AppLocalizations.of(context)!.addContactFirst))
|
||||
: //dev
|
||||
Container(child: MessageView()),
|
||||
),
|
||||
|
|
|
@ -17,6 +17,18 @@ class CwtchButtonTextField extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _CwtchButtonTextFieldState extends State<CwtchButtonTextField> {
|
||||
late final FocusNode _focusNode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_focusNode = FocusNode();
|
||||
_focusNode.addListener(() {
|
||||
// Select all...
|
||||
if (_focusNode.hasFocus) widget.controller.selection = TextSelection(baseOffset: 0, extentOffset: widget.controller.text.length);
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<Settings>(builder: (context, theme, child) {
|
||||
|
@ -24,6 +36,7 @@ class _CwtchButtonTextFieldState extends State<CwtchButtonTextField> {
|
|||
controller: widget.controller,
|
||||
readOnly: widget.readonly,
|
||||
showCursor: !widget.readonly,
|
||||
focusNode: _focusNode,
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: IconButton(
|
||||
onPressed: widget.onPressed,
|
||||
|
|
|
@ -23,10 +23,13 @@ class InvitationBubble extends StatefulWidget {
|
|||
class InvitationBubbleState extends State<InvitationBubble> {
|
||||
bool rejected = false;
|
||||
bool isAccepted = false;
|
||||
FocusNode _focus = FocusNode();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (Provider.of<MessageState>(context).malformed) {
|
||||
return MalformedBubble();
|
||||
}
|
||||
|
||||
var fromMe = Provider.of<MessageState>(context).senderOnion == Provider.of<ProfileInfoState>(context).onion;
|
||||
var isGroup = Provider.of<MessageState>(context).overlay == 101;
|
||||
isAccepted = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget) != null;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:cwtch/cwtch_icons_icons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
final Color malformedColor = Color(0xFFE85DA1);
|
||||
|
||||
|
@ -45,7 +46,7 @@ class MalformedBubbleState extends State<MalformedBubble> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [Text("Malformed Message")],
|
||||
children: [Text(AppLocalizations.of(context)!.malformedMessage)],
|
||||
))
|
||||
])))));
|
||||
});
|
||||
|
|
|
@ -33,6 +33,7 @@ class _CwtchTextFieldState extends State<CwtchPasswordField> {
|
|||
controller: widget.controller,
|
||||
validator: widget.validator,
|
||||
obscureText: obscureText,
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
onFieldSubmitted: widget.action,
|
||||
textInputAction: TextInputAction.unspecified,
|
||||
enableSuggestions: false,
|
||||
|
|
|
@ -7,7 +7,7 @@ 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 = null, this.autofocus = false, this.onChanged = doNothing});
|
||||
CwtchTextField({required this.controller, required this.labelText, this.validator, this.autofocus = false, this.onChanged = doNothing});
|
||||
final TextEditingController controller;
|
||||
final String labelText;
|
||||
final FormFieldValidator? validator;
|
||||
|
@ -19,6 +19,18 @@ class CwtchTextField extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _CwtchTextFieldState extends State<CwtchTextField> {
|
||||
late final FocusNode _focusNode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_focusNode = FocusNode();
|
||||
_focusNode.addListener(() {
|
||||
// Select all...
|
||||
if (_focusNode.hasFocus) widget.controller.selection = TextSelection(baseOffset: 0, extentOffset: widget.controller.text.length);
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<Settings>(builder: (context, theme, child) {
|
||||
|
@ -27,6 +39,7 @@ class _CwtchTextFieldState extends State<CwtchTextField> {
|
|||
validator: widget.validator,
|
||||
onChanged: widget.onChanged,
|
||||
autofocus: widget.autofocus,
|
||||
focusNode: _focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: widget.labelText,
|
||||
labelStyle: TextStyle(color: theme.current().mainTextColor(), backgroundColor: theme.current().textfieldBackgroundColor()),
|
||||
|
|
Loading…
Reference in New Issue