Upgrade to null safe sdk

This commit is contained in:
Sarah Jamie Lewis 2021-05-24 17:11:39 -07:00
parent 0baa2b707f
commit 2394a1daaa
36 changed files with 267 additions and 268 deletions

View File

@ -26,19 +26,19 @@ abstract class Cwtch {
void DebugResetContact(String profileOnion, String contactHandle); void DebugResetContact(String profileOnion, String contactHandle);
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> ACNEvents(); Future<dynamic> ACNEvents();
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> ContactEvents(); Future<dynamic> ContactEvents();
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> GetProfiles(); Future<dynamic> GetProfiles();
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<int> NumMessages(String profile, String handle); Future<dynamic> NumMessages(String profile, String handle);
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> GetMessage(String profile, String handle, int index); Future<dynamic> GetMessage(String profile, String handle, int index);
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> GetMessages(String profile, String handle, int start, int end); Future<dynamic> GetMessages(String profile, String handle, int start, int end);
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
void SendMessage(String profile, String handle, String message); void SendMessage(String profile, String handle, String message);
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names

View File

@ -10,10 +10,10 @@ import '../settings.dart';
// Class that handles libcwtch-go events (received either via ffi with an isolate or gomobile over a method channel from kotlin) // Class that handles libcwtch-go events (received either via ffi with an isolate or gomobile over a method channel from kotlin)
// Takes Notifiers and triggers them on appropriate events // Takes Notifiers and triggers them on appropriate events
class CwtchNotifier { class CwtchNotifier {
ProfileListState profileCN; late ProfileListState profileCN;
Settings settings; late Settings settings;
ErrorHandler error; late ErrorHandler error;
TorStatus torStatus; late TorStatus torStatus;
CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN) { CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN) {
profileCN = pcn; profileCN = pcn;
@ -74,7 +74,7 @@ class CwtchNotifier {
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["RemotePeer"]).getMessageKey(idx); var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["RemotePeer"]).getMessageKey(idx);
if (key == null) break; if (key == null) break;
try { try {
var message = Provider.of<MessageState>(key.currentContext, listen: false); var message = Provider.of<MessageState>(key.currentContext!, listen: false);
if (message == null) break; if (message == null) break;
message.ackd = true; message.ackd = true;
} catch (e) { } catch (e) {
@ -94,7 +94,7 @@ class CwtchNotifier {
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx); var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx);
if (key == null) break; if (key == null) break;
try { try {
var message = Provider.of<MessageState>(key.currentContext, listen: false); var message = Provider.of<MessageState>(key.currentContext!, listen: false);
if (message == null) break; if (message == null) break;
message.ackd = true; message.ackd = true;
} catch (e) { } catch (e) {
@ -109,7 +109,7 @@ class CwtchNotifier {
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx); var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx);
if (key == null) break; if (key == null) break;
try { try {
var message = Provider.of<MessageState>(key.currentContext, listen: false); var message = Provider.of<MessageState>(key.currentContext!, listen: false);
if (message == null) break; if (message == null) break;
message.error = true; message.error = true;
} catch (e) { } catch (e) {

View File

@ -56,9 +56,9 @@ typedef acn_events_function = Pointer<Utf8> Function();
typedef ACNEventsFn = Pointer<Utf8> Function(); typedef ACNEventsFn = Pointer<Utf8> Function();
class CwtchFfi implements Cwtch { class CwtchFfi implements Cwtch {
DynamicLibrary library; late DynamicLibrary library;
CwtchNotifier cwtchNotifier; late CwtchNotifier cwtchNotifier;
Isolate cwtchIsolate; late Isolate cwtchIsolate;
CwtchFfi(CwtchNotifier _cwtchNotifier) { CwtchFfi(CwtchNotifier _cwtchNotifier) {
if (Platform.isWindows) { if (Platform.isWindows) {
@ -79,9 +79,9 @@ class CwtchFfi implements Cwtch {
String bundledTor = ""; String bundledTor = "";
Map<String, String> envVars = Platform.environment; Map<String, String> envVars = Platform.environment;
if (Platform.isLinux) { if (Platform.isLinux) {
home = envVars['HOME']; home = (envVars['HOME'])!;
} else if (Platform.isWindows) { } else if (Platform.isWindows) {
home = envVars['UserProfile']; home = (envVars['UserProfile'])!;
bundledTor = "Tor\\Tor\\tor.exe"; bundledTor = "Tor\\Tor\\tor.exe";
} }
var cwtchDir = path.join(home, ".cwtch/dev/"); var cwtchDir = path.join(home, ".cwtch/dev/");
@ -121,7 +121,7 @@ class CwtchFfi implements Cwtch {
// Steam of appbus events. Call blocks in libcwtch-go GetAppbusEvent. Static so the isolate can use it // Steam of appbus events. Call blocks in libcwtch-go GetAppbusEvent. Static so the isolate can use it
static Stream<String> pollAppbusEvents() async* { static Stream<String> pollAppbusEvents() async* {
DynamicLibrary library; late DynamicLibrary library;
if (Platform.isWindows) { if (Platform.isWindows) {
library = DynamicLibrary.open("libCwtch.dll"); library = DynamicLibrary.open("libCwtch.dll");
} else if (Platform.isLinux) { } else if (Platform.isLinux) {

View File

@ -26,9 +26,9 @@ class CwtchGomobile implements Cwtch {
final appbusEventChannelName = 'test.flutter.dev/eventBus'; final appbusEventChannelName = 'test.flutter.dev/eventBus';
Future<String> androidLibraryDir; late Future<dynamic> androidLibraryDir;
Future<Directory> androidHomeDirectory; late Future<dynamic> androidHomeDirectory;
CwtchNotifier cwtchNotifier; late CwtchNotifier cwtchNotifier;
CwtchGomobile(CwtchNotifier _cwtchNotifier) { CwtchGomobile(CwtchNotifier _cwtchNotifier) {
print("gomobile.dart: CwtchGomobile()"); print("gomobile.dart: CwtchGomobile()");
@ -73,34 +73,34 @@ class CwtchGomobile implements Cwtch {
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> ACNEvents() { Future<dynamic> ACNEvents() {
return cwtchPlatform.invokeMethod("ACNEvents"); return cwtchPlatform.invokeMethod("ACNEvents");
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> ContactEvents() { Future<dynamic> ContactEvents() {
return cwtchPlatform.invokeMethod("ContactEvents"); return cwtchPlatform.invokeMethod("ContactEvents");
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> GetProfiles() { Future<dynamic> GetProfiles() {
print("gomobile.dart: GetProfiles()"); print("gomobile.dart: GetProfiles()");
return cwtchPlatform.invokeMethod("GetProfiles"); return cwtchPlatform.invokeMethod("GetProfiles");
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<int> NumMessages(String profile, String handle) { Future<dynamic> NumMessages(String profile, String handle) {
return cwtchPlatform.invokeMethod("NumMessages", {"profile": profile, "contact": handle}); return cwtchPlatform.invokeMethod("NumMessages", {"profile": profile, "contact": handle});
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> GetMessage(String profile, String handle, int index) { Future<dynamic> GetMessage(String profile, String handle, int index) {
print("gomobile.dart GetMessage " + index.toString()); print("gomobile.dart GetMessage " + index.toString());
return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "index": index}); return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "index": index});
} }
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<String> GetMessages(String profile, String handle, int start, int end) { Future<dynamic> GetMessages(String profile, String handle, int start, int end) {
return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "start": start, "end": end}); return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "start": start, "end": end});
} }

View File

@ -35,14 +35,14 @@ class Flwtch extends StatefulWidget {
class FlwtchState extends State<Flwtch> { class FlwtchState extends State<Flwtch> {
final TextStyle biggerFont = const TextStyle(fontSize: 18); final TextStyle biggerFont = const TextStyle(fontSize: 18);
Cwtch cwtch; late Cwtch cwtch;
bool cwtchInit = false; bool cwtchInit = false;
ProfileInfoState selectedProfile; late ProfileInfoState selectedProfile;
String selectedConversation = ""; String selectedConversation = "";
var columns = [1]; // default or 'single column' mode var columns = [1]; // default or 'single column' mode
//var columns = [1, 1, 2]; //var columns = [1, 1, 2];
AppModel appStatus; late AppModel appStatus;
ProfileListState profs; late ProfileListState profs;
@override @override
initState() { initState() {

View File

@ -63,6 +63,6 @@ class DiskAssetBundle extends CachingAssetBundle {
@override @override
Future<ByteData> load(String key) async { Future<ByteData> load(String key) async {
return _cache[key]; return _cache[key]!;
} }
} }

View File

@ -14,33 +14,11 @@ import 'main.dart';
/// UI State /// /// UI State ///
//////////////////// ////////////////////
//todo: delete
class ProfileModel {
String onion;
String nickname;
String creationDate;
String imagePath;
HashMap<String, ContactModel> contacts;
}
//todo: delete
class ContactModel {
String onion;
String nickname;
bool isGroup;
bool isInvitation;
bool isBlocked;
String status;
String imagePath;
ContactModel({this.onion, this.nickname, this.status, this.isInvitation, this.isBlocked, this.imagePath});
}
class ChatMessage { class ChatMessage {
final int o; final int o;
final String d; final String d;
ChatMessage({this.o, this.d}); ChatMessage({required this.o, required this.d});
ChatMessage.fromJson(Map<String, dynamic> json) ChatMessage.fromJson(Map<String, dynamic> json)
: o = json['o'], : o = json['o'],
@ -74,16 +52,16 @@ class ProfileListState extends ChangeNotifier {
ProfileInfoState getProfile(String onion) { ProfileInfoState getProfile(String onion) {
int idx = _profiles.indexWhere((element) => element.onion == onion); int idx = _profiles.indexWhere((element) => element.onion == onion);
return idx >= 0 ? _profiles[idx] : null; return idx >= 0 ? _profiles[idx] : ProfileInfoState(onion: onion);
} }
} }
class ContactListState extends ChangeNotifier { class ContactListState extends ChangeNotifier {
List<ContactInfoState> _contacts = []; List<ContactInfoState> _contacts = [];
String _filter; String _filter = "";
int get num => _contacts.length; int get num => _contacts.length;
int get numFiltered => isFiltered ? filteredList().length : num; int get numFiltered => isFiltered ? filteredList().length : num;
bool get isFiltered => _filter != null && _filter != ""; bool get isFiltered => _filter != "";
String get filter => _filter; String get filter => _filter;
set filter(String newVal) { set filter(String newVal) {
_filter = newVal; _filter = newVal;
@ -142,7 +120,7 @@ class ContactListState extends ChangeNotifier {
ContactInfoState getContact(String onion) { ContactInfoState getContact(String onion) {
int idx = _contacts.indexWhere((element) => element.onion == onion); int idx = _contacts.indexWhere((element) => element.onion == onion);
return idx >= 0 ? _contacts[idx] : null; return idx >= 0 ? _contacts[idx] : ContactInfoState("not found", "not found");
} }
} }
@ -156,7 +134,7 @@ class ProfileInfoState extends ChangeNotifier {
bool _online = false; bool _online = false;
ProfileInfoState({ ProfileInfoState({
this.onion, required this.onion,
nickname = "", nickname = "",
imagePath = "", imagePath = "",
unreadMessages = 0, unreadMessages = 0,
@ -253,21 +231,21 @@ class ProfileInfoState extends ChangeNotifier {
class ContactInfoState extends ChangeNotifier { class ContactInfoState extends ChangeNotifier {
final String profileOnion; final String profileOnion;
final String onion; final String onion;
String _nickname; late String _nickname;
bool _isInvitation; late bool _isInvitation;
bool _isBlocked; late bool _isBlocked;
String _status; late String _status;
String _imagePath; late String _imagePath;
String _savePeerHistory; late String _savePeerHistory;
int _unreadMessages = 0; late int _unreadMessages = 0;
int _totalMessages = 0; late int _totalMessages = 0;
DateTime _lastMessageTime; late DateTime _lastMessageTime;
Map<String, GlobalKey> keys; late Map<String, GlobalKey<MessageBubbleState>> keys;
// todo: a nicer way to model contacts, groups and other "entities" // todo: a nicer way to model contacts, groups and other "entities"
bool _isGroup; late bool _isGroup;
String _server; late String _server;
ContactInfoState( ContactInfoState(
this.profileOnion, this.profileOnion,
@ -293,14 +271,14 @@ class ContactInfoState extends ChangeNotifier {
this._totalMessages = numMessages; this._totalMessages = numMessages;
this._unreadMessages = numUnread; this._unreadMessages = numUnread;
this._savePeerHistory = savePeerHistory; this._savePeerHistory = savePeerHistory;
this._lastMessageTime = lastMessageTime; this._lastMessageTime = lastMessageTime == null ? DateTime.fromMillisecondsSinceEpoch(0) : lastMessageTime;
this._server = server; this._server = server;
keys = Map<String, GlobalKey>(); keys = Map<String, GlobalKey<MessageBubbleState>>();
} }
get nickname => this._nickname; String get nickname => this._nickname;
get savePeerHistory => this._savePeerHistory; String get savePeerHistory => this._savePeerHistory;
set savePeerHistory(String newVal) { set savePeerHistory(String newVal) {
this._savePeerHistory = newVal; this._savePeerHistory = newVal;
notifyListeners(); notifyListeners();
@ -311,49 +289,49 @@ class ContactInfoState extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
get isGroup => this._isGroup; bool get isGroup => this._isGroup;
set isGroup(bool newVal) { set isGroup(bool newVal) {
this._isGroup = newVal; this._isGroup = newVal;
notifyListeners(); notifyListeners();
} }
get isBlocked => this._isBlocked; bool get isBlocked => this._isBlocked;
set isBlocked(bool newVal) { set isBlocked(bool newVal) {
this._isBlocked = newVal; this._isBlocked = newVal;
notifyListeners(); notifyListeners();
} }
get isInvitation => this._isInvitation; bool get isInvitation => this._isInvitation;
set isInvitation(bool newVal) { set isInvitation(bool newVal) {
this._isInvitation = newVal; this._isInvitation = newVal;
notifyListeners(); notifyListeners();
} }
get status => this._status; String get status => this._status;
set status(String newVal) { set status(String newVal) {
this._status = newVal; this._status = newVal;
notifyListeners(); notifyListeners();
} }
get unreadMessages => this._unreadMessages; int get unreadMessages => this._unreadMessages;
set unreadMessages(int newVal) { set unreadMessages(int newVal) {
this._unreadMessages = newVal; this._unreadMessages = newVal;
notifyListeners(); notifyListeners();
} }
get totalMessages => this._totalMessages; int get totalMessages => this._totalMessages;
set totalMessages(int newVal) { set totalMessages(int newVal) {
this._totalMessages = newVal; this._totalMessages = newVal;
notifyListeners(); notifyListeners();
} }
get imagePath => this._imagePath; String get imagePath => this._imagePath;
set imagePath(String newVal) { set imagePath(String newVal) {
this._imagePath = newVal; this._imagePath = newVal;
notifyListeners(); notifyListeners();
} }
get lastMessageTime => this._lastMessageTime; DateTime get lastMessageTime => this._lastMessageTime;
set lastMessageTime(DateTime newVal) { set lastMessageTime(DateTime newVal) {
this._lastMessageTime = newVal; this._lastMessageTime = newVal;
notifyListeners(); notifyListeners();
@ -374,7 +352,8 @@ class ContactInfoState extends ChangeNotifier {
if (keys[index] == null) { if (keys[index] == null) {
keys[index] = GlobalKey<MessageBubbleState>(); keys[index] = GlobalKey<MessageBubbleState>();
} }
return keys[index]; GlobalKey<MessageBubbleState> ret = keys[index]!;
return ret;
} }
} }
@ -382,24 +361,24 @@ class MessageState extends ChangeNotifier {
final String profileOnion; final String profileOnion;
final String contactHandle; final String contactHandle;
final int messageIndex; final int messageIndex;
String _message; late String _message;
int _overlay; late int _overlay;
String _inviteTarget; late String _inviteTarget;
String _inviteNick; late String _inviteNick;
DateTime _timestamp; late DateTime _timestamp;
String _senderOnion; late String _senderOnion;
String _senderImage; late String _senderImage;
String _signature = ""; late String _signature = "";
bool _ackd = false; late bool _ackd = false;
bool _error = false; late bool _error = false;
bool _loaded = false; late bool _loaded = false;
bool _malformed = false; late bool _malformed = false;
MessageState({ MessageState({
BuildContext context, required BuildContext context,
this.profileOnion, required this.profileOnion,
this.contactHandle, required this.contactHandle,
this.messageIndex, required this.messageIndex,
}) { }) {
this._senderOnion = profileOnion; this._senderOnion = profileOnion;
tryLoad(context); tryLoad(context);
@ -408,8 +387,8 @@ class MessageState extends ChangeNotifier {
get message => this._message; get message => this._message;
get overlay => this._overlay; get overlay => this._overlay;
get timestamp => this._timestamp; get timestamp => this._timestamp;
get ackd => this._ackd; bool get ackd => this._ackd;
get error => this._error; bool get error => this._error;
get malformed => this._malformed; get malformed => this._malformed;
get senderOnion => this._senderOnion; get senderOnion => this._senderOnion;
get senderImage => this._senderImage; get senderImage => this._senderImage;
@ -444,7 +423,7 @@ class MessageState extends ChangeNotifier {
dynamic message = jsonDecode(messageWrapper['Message']); dynamic message = jsonDecode(messageWrapper['Message']);
this._message = message['d']; this._message = message['d'];
this._overlay = int.parse(message['o'].toString()); this._overlay = int.parse(message['o'].toString());
this._timestamp = DateTime.tryParse(messageWrapper['Timestamp']); this._timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!;
this._senderOnion = messageWrapper['PeerID']; this._senderOnion = messageWrapper['PeerID'];
this._senderImage = messageWrapper['ContactImage']; this._senderImage = messageWrapper['ContactImage'];
@ -490,7 +469,7 @@ class MessageState extends ChangeNotifier {
class AppModel { class AppModel {
final Cwtch cwtch; final Cwtch cwtch;
AppModel({this.cwtch}); AppModel({required this.cwtch});
Stream<String> contactEvents() async* { Stream<String> contactEvents() async* {
while (true) { while (true) {

View File

@ -11,7 +11,7 @@ class ServerListState extends ChangeNotifier {
ServerInfoState getServer(String onion) { ServerInfoState getServer(String onion) {
int idx = _servers.indexWhere((element) => element.onion == onion); int idx = _servers.indexWhere((element) => element.onion == onion);
return idx >= 0 ? _servers[idx] : null; return idx >= 0 ? _servers[idx] : ServerInfoState(onion: "not found", status: "not found");
} }
List<ServerInfoState> get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier List<ServerInfoState> get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier
@ -22,5 +22,5 @@ class ServerInfoState extends ChangeNotifier {
final String onion; final String onion;
final String status; final String status;
ServerInfoState({this.onion, this.status}); ServerInfoState({required this.onion, required this.status});
} }

View File

@ -1225,7 +1225,7 @@ class Opaque extends OpaqueThemeType {
return sidePaneMinSize() + chatPaneMinSize(); return sidePaneMinSize() + chatPaneMinSize();
} }
static OpaqueThemeType _current; static late OpaqueThemeType _current;
static final OpaqueThemeType dark = CwtchDark(); static final OpaqueThemeType dark = CwtchDark();
static final OpaqueThemeType light = CwtchLight(); static final OpaqueThemeType light = CwtchLight();
static void setDark() { static void setDark() {

View File

@ -14,12 +14,12 @@ const TapirGroupsExperiment = "tapir-groups-experiment";
/// Settings Pane. /// Settings Pane.
class Settings extends ChangeNotifier { class Settings extends ChangeNotifier {
Locale locale; Locale locale;
PackageInfo packageInfo; late PackageInfo packageInfo;
OpaqueThemeType theme; OpaqueThemeType theme;
bool experimentsEnabled; late bool experimentsEnabled;
HashMap<String, bool> experiments = HashMap.identity(); HashMap<String, bool> experiments = HashMap.identity();
bool blockUnknownConnections; late bool blockUnknownConnections;
/// Set the dark theme. /// Set the dark theme.
void setDark() { void setDark() {

View File

@ -5,6 +5,8 @@ class TorStatus extends ChangeNotifier {
String status; String status;
bool connected; bool connected;
TorStatus({this.connected = false, this.progress = 0, this.status = ""});
/// Called by the event bus. /// Called by the event bus.
handleUpdate(int new_progress, String new_status) { handleUpdate(int new_progress, String new_status) {
if (progress == 100) { if (progress == 100) {

View File

@ -36,7 +36,7 @@ class _AddContactViewState extends State<AddContactView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(AppLocalizations.of(context).titleManageContacts), title: Text(AppLocalizations.of(context)!.titleManageContacts),
), ),
body: _buildForm(), body: _buildForm(),
); );
@ -46,7 +46,7 @@ class _AddContactViewState extends State<AddContactView> {
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion; ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
/// We display a different number of tabs dependening on the experiment setup /// We display a different number of tabs dependening on the experiment setup
bool groupsEnabled = Provider.of<Settings>(context).experimentsEnabled && Provider.of<Settings>(context).experiments[TapirGroupsExperiment]; bool groupsEnabled = Provider.of<Settings>(context).experimentsEnabled && Provider.of<Settings>(context).experiments[TapirGroupsExperiment]!;
return Consumer<ErrorHandler>(builder: (context, globalErrorHandler, child) { return Consumer<ErrorHandler>(builder: (context, globalErrorHandler, child) {
return DefaultTabController( return DefaultTabController(
length: groupsEnabled ? 4 : 1, length: groupsEnabled ? 4 : 1,
@ -62,7 +62,7 @@ class _AddContactViewState extends State<AddContactView> {
void _copyOnion() { void _copyOnion() {
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion)); Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification)); final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedClipboardNotification));
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
} }
@ -72,7 +72,7 @@ class _AddContactViewState extends State<AddContactView> {
tabs: [ tabs: [
Tab( Tab(
icon: Icon(Icons.person_add_rounded), icon: Icon(Icons.person_add_rounded),
text: AppLocalizations.of(context).addPeer, text: AppLocalizations.of(context)!.addPeer,
), ),
], ],
); );
@ -84,11 +84,11 @@ class _AddContactViewState extends State<AddContactView> {
tabs: [ tabs: [
Tab( Tab(
icon: Icon(Icons.person_add_rounded), icon: Icon(Icons.person_add_rounded),
text: AppLocalizations.of(context).addPeer, text: AppLocalizations.of(context)!.addPeer,
), ),
Tab(icon: Icon(Icons.backup), text: AppLocalizations.of(context).titleManageServers), Tab(icon: Icon(Icons.backup), text: AppLocalizations.of(context)!.titleManageServers),
Tab(icon: Icon(Icons.group), text: AppLocalizations.of(context).createGroup), Tab(icon: Icon(Icons.group), text: AppLocalizations.of(context)!.createGroup),
Tab(icon: Icon(Icons.group_add), text: AppLocalizations.of(context).joinGroup), Tab(icon: Icon(Icons.group_add), text: AppLocalizations.of(context)!.joinGroup),
], ],
); );
} }
@ -103,7 +103,7 @@ class _AddContactViewState extends State<AddContactView> {
autovalidateMode: AutovalidateMode.always, autovalidateMode: AutovalidateMode.always,
key: _formKey, key: _formKey,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
CwtchLabel(label: AppLocalizations.of(context).profileOnionLabel), CwtchLabel(label: AppLocalizations.of(context)!.profileOnionLabel),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -111,12 +111,12 @@ class _AddContactViewState extends State<AddContactView> {
controller: ctrlrOnion, controller: ctrlrOnion,
onPressed: _copyOnion, onPressed: _copyOnion,
icon: Icon(Icons.copy), icon: Icon(Icons.copy),
tooltip: AppLocalizations.of(context).copyBtn, tooltip: AppLocalizations.of(context)!.copyBtn,
), ),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).pasteAddressToAddContact), CwtchLabel(label: AppLocalizations.of(context)!.pasteAddressToAddContact),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -127,9 +127,9 @@ class _AddContactViewState extends State<AddContactView> {
return null; return null;
} }
if (globalErrorHandler.invalidImportStringError) { if (globalErrorHandler.invalidImportStringError) {
return AppLocalizations.of(context).invalidImportString; return AppLocalizations.of(context)!.invalidImportString;
} else if (globalErrorHandler.contactAlreadyExistsError) { } else if (globalErrorHandler.contactAlreadyExistsError) {
return AppLocalizations.of(context).contactAlreadyExists; return AppLocalizations.of(context)!.contactAlreadyExists;
} else if (globalErrorHandler.explicitAddContactSuccess) {} } else if (globalErrorHandler.explicitAddContactSuccess) {}
return null; return null;
}, },
@ -144,12 +144,13 @@ class _AddContactViewState extends State<AddContactView> {
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
if (globalErrorHandler.explicitAddContactSuccess) { if (globalErrorHandler.explicitAddContactSuccess) {
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).successfullAddedContact + peerAddr)); final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact + peerAddr));
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
Navigator.pop(context); Navigator.pop(context);
} }
}); });
}, },
labelText: '',
) )
]))); ])));
} }
@ -176,13 +177,13 @@ class _AddContactViewState extends State<AddContactView> {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
CwtchLabel(label: AppLocalizations.of(context).server), CwtchLabel(label: AppLocalizations.of(context)!.server),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
DropdownButton( DropdownButton(
onChanged: (newServer) { onChanged: (newServer) {
server = newServer; server = newServer.toString();
}, },
value: server, value: server,
items: Provider.of<ProfileInfoState>(context).serverList.servers.map<DropdownMenuItem<String>>((ServerInfoState serverInfo) { items: Provider.of<ProfileInfoState>(context).serverList.servers.map<DropdownMenuItem<String>>((ServerInfoState serverInfo) {
@ -194,17 +195,22 @@ class _AddContactViewState extends State<AddContactView> {
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).groupName), CwtchLabel(label: AppLocalizations.of(context)!.groupName),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchTextField(controller: ctrlrGroupName, labelText: AppLocalizations.of(context).groupNameLabel, onChanged: (newValue) {}), CwtchTextField(
controller: ctrlrGroupName,
labelText: AppLocalizations.of(context)!.groupNameLabel,
onChanged: (newValue) {},
validator: (value) {},
),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
ElevatedButton( ElevatedButton(
onPressed: () {}, onPressed: () {},
child: Text(AppLocalizations.of(context).createGroupBtn), child: Text(AppLocalizations.of(context)!.createGroupBtn),
), ),
], ],
))); )));
@ -219,7 +225,7 @@ class _AddContactViewState extends State<AddContactView> {
autovalidateMode: AutovalidateMode.always, autovalidateMode: AutovalidateMode.always,
key: _joinGroupFormKey, key: _joinGroupFormKey,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
CwtchLabel(label: AppLocalizations.of(context).joinGroupTab), CwtchLabel(label: AppLocalizations.of(context)!.joinGroupTab),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -230,7 +236,7 @@ class _AddContactViewState extends State<AddContactView> {
return null; return null;
} }
if (globalErrorHandler.importBundleError) { if (globalErrorHandler.importBundleError) {
return AppLocalizations.of(context).invalidImportString; return AppLocalizations.of(context)!.invalidImportString;
} else if (globalErrorHandler.importBundleSuccess) {} } else if (globalErrorHandler.importBundleSuccess) {}
return null; return null;
}, },
@ -240,12 +246,13 @@ class _AddContactViewState extends State<AddContactView> {
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
if (globalErrorHandler.importBundleSuccess) { if (globalErrorHandler.importBundleSuccess) {
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).successfullAddedContact + importBundle)); final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact + importBundle));
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
Navigator.pop(context); Navigator.pop(context);
} }
}); });
}, },
labelText: '',
) )
]))); ])));
} }

View File

@ -16,7 +16,7 @@ import '../opaque.dart';
import '../settings.dart'; import '../settings.dart';
class AddEditProfileView extends StatefulWidget { class AddEditProfileView extends StatefulWidget {
const AddEditProfileView({Key key}) : super(key: key); const AddEditProfileView({Key? key}) : super(key: key);
@override @override
_AddEditProfileViewState createState() => _AddEditProfileViewState(); _AddEditProfileViewState createState() => _AddEditProfileViewState();
@ -30,8 +30,8 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
final ctrlrPass = TextEditingController(text: ""); final ctrlrPass = TextEditingController(text: "");
final ctrlrPass2 = TextEditingController(text: ""); final ctrlrPass2 = TextEditingController(text: "");
final ctrlrOnion = TextEditingController(text: ""); final ctrlrOnion = TextEditingController(text: "");
bool usePassword; late bool usePassword;
bool deleted; late bool deleted;
@override @override
void initState() { void initState() {
@ -48,15 +48,15 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion; ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(Provider.of<ProfileInfoState>(context).onion.isEmpty ? AppLocalizations.of(context).addProfileTitle : AppLocalizations.of(context).editProfileTitle), title: Text(Provider.of<ProfileInfoState>(context).onion.isEmpty ? AppLocalizations.of(context)!.addProfileTitle : AppLocalizations.of(context)!.editProfileTitle),
), ),
body: _buildForm(), body: _buildForm(),
); );
} }
void _handleSwitchPassword(bool value) { void _handleSwitchPassword(bool? value) {
setState(() { setState(() {
usePassword = value; usePassword = value!;
}); });
} }
@ -88,16 +88,18 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
diameter: 120, diameter: 120,
maskOut: false, maskOut: false,
border: theme.theme.portraitOnlineBorderColor(), border: theme.theme.portraitOnlineBorderColor(),
badgeTextColor: Colors.red,
badgeColor: Colors.red,
) )
])), ])),
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
CwtchLabel(label: AppLocalizations.of(context).displayNameLabel), CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchTextField( CwtchTextField(
controller: ctrlrNick, controller: ctrlrNick,
labelText: AppLocalizations.of(context).yourDisplayName, labelText: AppLocalizations.of(context)!.yourDisplayName,
validator: (value) { validator: (value) {
if (value.isEmpty) { if (value.isEmpty) {
return "Please enter a display name"; return "Please enter a display name";
@ -112,7 +114,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).addressLabel), CwtchLabel(label: AppLocalizations.of(context)!.addressLabel),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -120,7 +122,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
controller: ctrlrOnion, controller: ctrlrOnion,
onPressed: _copyOnion, onPressed: _copyOnion,
icon: Icon(Icons.copy), icon: Icon(Icons.copy),
tooltip: AppLocalizations.of(context).copyBtn, tooltip: AppLocalizations.of(context)!.copyBtn,
) )
])), ])),
// We only allow setting password types on profile creation // We only allow setting password types on profile creation
@ -132,7 +134,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
onChanged: _handleSwitchPassword, onChanged: _handleSwitchPassword,
), ),
Text( Text(
AppLocalizations.of(context).radioUsePassword, AppLocalizations.of(context)!.radioUsePassword,
style: TextStyle(color: theme.current().mainTextColor()), style: TextStyle(color: theme.current().mainTextColor()),
), ),
])), ])),
@ -145,7 +147,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
Visibility( Visibility(
visible: Provider.of<ProfileInfoState>(context, listen: false).onion.isNotEmpty, visible: Provider.of<ProfileInfoState>(context, listen: false).onion.isNotEmpty,
child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
CwtchLabel(label: AppLocalizations.of(context).currentPasswordLabel), CwtchLabel(label: AppLocalizations.of(context)!.currentPasswordLabel),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -154,7 +156,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
validator: (value) { validator: (value) {
// Password field can be empty when just updating the profile, not on creation // Password field can be empty when just updating the profile, not on creation
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
return AppLocalizations.of(context).passwordErrorEmpty; return AppLocalizations.of(context)!.passwordErrorEmpty;
} }
return null; return null;
}, },
@ -163,7 +165,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
height: 20, height: 20,
), ),
])), ])),
CwtchLabel(label: AppLocalizations.of(context).password1Label), CwtchLabel(label: AppLocalizations.of(context)!.password1Label),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -172,10 +174,10 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
validator: (value) { validator: (value) {
// Password field can be empty when just updating the profile, not on creation // Password field can be empty when just updating the profile, not on creation
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
return AppLocalizations.of(context).passwordErrorEmpty; return AppLocalizations.of(context)!.passwordErrorEmpty;
} }
if (value != ctrlrPass2.value.text) { if (value != ctrlrPass2.value.text) {
return AppLocalizations.of(context).passwordErrorMatch; return AppLocalizations.of(context)!.passwordErrorMatch;
} }
return null; return null;
}, },
@ -183,7 +185,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).password2Label), CwtchLabel(label: AppLocalizations.of(context)!.password2Label),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -192,10 +194,10 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
validator: (value) { validator: (value) {
// Password field can be empty when just updating the profile, not on creation // Password field can be empty when just updating the profile, not on creation
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
return AppLocalizations.of(context).passwordErrorEmpty; return AppLocalizations.of(context)!.passwordErrorEmpty;
} }
if (value != ctrlrPass.value.text) { if (value != ctrlrPass.value.text) {
return AppLocalizations.of(context).passwordErrorMatch; return AppLocalizations.of(context)!.passwordErrorMatch;
} }
return null; return null;
}), }),
@ -211,7 +213,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
child: ElevatedButton( child: ElevatedButton(
onPressed: _createPressed, onPressed: _createPressed,
child: Text( child: Text(
Provider.of<ProfileInfoState>(context).onion.isEmpty ? AppLocalizations.of(context).addNewProfileBtn : AppLocalizations.of(context).saveProfileBtn, Provider.of<ProfileInfoState>(context).onion.isEmpty ? AppLocalizations.of(context)!.addNewProfileBtn : AppLocalizations.of(context)!.saveProfileBtn,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
@ -225,7 +227,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
height: 20, height: 20,
), ),
Tooltip( Tooltip(
message: AppLocalizations.of(context).enterCurrentPasswordForDelete, message: AppLocalizations.of(context)!.enterCurrentPasswordForDelete,
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: checkCurrentPassword() onPressed: checkCurrentPassword()
? null ? null
@ -234,7 +236,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
}, },
style: ElevatedButton.styleFrom(primary: theme.current().defaultButtonColor()), style: ElevatedButton.styleFrom(primary: theme.current().defaultButtonColor()),
icon: Icon(Icons.delete_forever), icon: Icon(Icons.delete_forever),
label: Text(AppLocalizations.of(context).deleteBtn), label: Text(AppLocalizations.of(context)!.deleteBtn),
)) ))
])) ]))
])))))); ]))))));
@ -251,7 +253,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
// This will run all the validations in the form including // This will run all the validations in the form including
// checking that display name is not empty, and an actual check that the passwords // checking that display name is not empty, and an actual check that the passwords
// match (and are provided if the user has requested an encrypted profile). // match (and are provided if the user has requested an encrypted profile).
if (_formKey.currentState.validate()) { if (_formKey.currentState!.validate()) {
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty) { if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty) {
if (usePassword == true) { if (usePassword == true) {
Provider.of<FlwtchState>(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, ctrlrPass.value.text); Provider.of<FlwtchState>(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, ctrlrPass.value.text);
@ -322,7 +324,7 @@ showAlertDialog(BuildContext context) {
foregroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonTextColor()), foregroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonTextColor()),
overlayColor: MaterialStateProperty.all(Opaque.current().defaultButtonActiveColor()), overlayColor: MaterialStateProperty.all(Opaque.current().defaultButtonActiveColor()),
padding: MaterialStateProperty.all(EdgeInsets.all(20))), padding: MaterialStateProperty.all(EdgeInsets.all(20))),
child: Text(AppLocalizations.of(context).deleteProfileConfirmBtn), child: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn),
onPressed: () { onPressed: () {
// TODO Actually Delete the Peer // TODO Actually Delete the Peer
Navigator.of(context).pop(); // dismiss dialog Navigator.of(context).pop(); // dismiss dialog
@ -331,7 +333,7 @@ showAlertDialog(BuildContext context) {
// set up the AlertDialog // set up the AlertDialog
AlertDialog alert = AlertDialog( AlertDialog alert = AlertDialog(
title: Text(AppLocalizations.of(context).deleteProfileConfirmBtn), title: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn),
actions: [ actions: [
cancelButton, cancelButton,
continueButton, continueButton,

View File

@ -12,14 +12,14 @@ import '../model.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class ContactsView extends StatefulWidget { class ContactsView extends StatefulWidget {
const ContactsView({Key key}) : super(key: key); const ContactsView({Key? key}) : super(key: key);
@override @override
_ContactsViewState createState() => _ContactsViewState(); _ContactsViewState createState() => _ContactsViewState();
} }
class _ContactsViewState extends State<ContactsView> { class _ContactsViewState extends State<ContactsView> {
TextEditingController ctrlrFilter; late TextEditingController ctrlrFilter;
bool showSearchBar = false; bool showSearchBar = false;
@override @override
@ -37,13 +37,15 @@ class _ContactsViewState extends State<ContactsView> {
imagePath: Provider.of<ProfileInfoState>(context).imagePath, imagePath: Provider.of<ProfileInfoState>(context).imagePath,
diameter: 42, diameter: 42,
border: Provider.of<Settings>(context).theme.portraitOnlineBorderColor(), border: Provider.of<Settings>(context).theme.portraitOnlineBorderColor(),
badgeTextColor: Colors.red,
badgeColor: Colors.red,
), ),
SizedBox( SizedBox(
width: 10, width: 10,
), ),
Expanded( Expanded(
child: Text( child: Text(
"%1 » %2".replaceAll("%1", Provider.of<ProfileInfoState>(context).nickname ?? Provider.of<ProfileInfoState>(context).onion ?? '').replaceAll("%2", "Contacts"), "%1 » %2".replaceAll("%1", Provider.of<ProfileInfoState>(context).nickname).replaceAll("%2", "Contacts"),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
)), //todo )), //todo
]), ]),
@ -66,7 +68,7 @@ class _ContactsViewState extends State<ContactsView> {
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: _pushAddContact, onPressed: _pushAddContact,
tooltip: AppLocalizations.of(context).tooltipAddContact, tooltip: AppLocalizations.of(context)!.tooltipAddContact,
child: const Icon(Icons.person_add_sharp), child: const Icon(Icons.person_add_sharp),
), ),
body: showSearchBar || Provider.of<ContactListState>(context).isFiltered ? _buildFilterable() : _buildContactList(), body: showSearchBar || Provider.of<ContactListState>(context).isFiltered ? _buildFilterable() : _buildContactList(),
@ -75,16 +77,18 @@ class _ContactsViewState extends State<ContactsView> {
Widget _buildFilterable() { Widget _buildFilterable() {
Widget txtfield = CwtchTextField( Widget txtfield = CwtchTextField(
controller: ctrlrFilter, controller: ctrlrFilter,
labelText: AppLocalizations.of(context).search, labelText: AppLocalizations.of(context)!.search,
onChanged: (newVal) { onChanged: (newVal) {
Provider.of<ContactListState>(context, listen: false).filter = newVal; Provider.of<ContactListState>(context, listen: false).filter = newVal;
}); },
validator: (value) {},
);
return Column(children: [Padding(padding: EdgeInsets.all(8), child: txtfield), Expanded(child: _buildContactList())]); return Column(children: [Padding(padding: EdgeInsets.all(8), child: txtfield), Expanded(child: _buildContactList())]);
} }
Widget _buildContactList() { Widget _buildContactList() {
final tiles = Provider.of<ContactListState>(context).filteredList().map((ContactInfoState contact) { final tiles = Provider.of<ContactListState>(context).contacts.map((ContactInfoState contact) {
return ChangeNotifierProvider<ContactInfoState>.value(key: ValueKey(contact.profileOnion + "" + contact.onion), value: contact, builder: (_, __) => ContactRow()); return ChangeNotifierProvider<ContactInfoState>.value(key: ValueKey(contact.profileOnion + "" + contact.onion), value: contact, builder: (_, __) => ContactRow());
}); });
final divided = ListTile.divideTiles( final divided = ListTile.divideTiles(
@ -119,7 +123,7 @@ class _ContactsViewState extends State<ContactsView> {
} }
void _copyOnion() { void _copyOnion() {
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification)); //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. // Find the Scaffold in the widget tree and use it to show a SnackBar.
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
} }

View File

@ -20,7 +20,9 @@ class _DoubleColumnViewState extends State<DoubleColumnView> {
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
flex: flwtch.columns[0], flex: flwtch.columns[0],
child: ContactsView(), child: ContactsView(
key: widget.key,
),
), ),
Flexible( Flexible(
flex: flwtch.columns[1], flex: flwtch.columns[1],

View File

@ -24,7 +24,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(AppLocalizations.of(context).cwtchSettingsTitle), title: Text(AppLocalizations.of(context)!.cwtchSettingsTitle),
), ),
body: _buildSettingsList(), body: _buildSettingsList(),
); );
@ -43,13 +43,13 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
), ),
child: Column(children: [ child: Column(children: [
ListTile( ListTile(
title: Text(AppLocalizations.of(context).settingLanguage, style: TextStyle(color: settings.current().mainTextColor())), title: Text(AppLocalizations.of(context)!.settingLanguage, style: TextStyle(color: settings.current().mainTextColor())),
leading: Icon(Icons.language, color: settings.current().mainTextColor()), leading: Icon(Icons.language, color: settings.current().mainTextColor()),
trailing: DropdownButton( trailing: DropdownButton(
value: Provider.of<Settings>(context).locale.languageCode, value: Provider.of<Settings>(context).locale.languageCode,
onChanged: (String newValue) { onChanged: (String? newValue) {
setState(() { setState(() {
settings.switchLocale(Locale(newValue, '')); settings.switchLocale(Locale(newValue!, ''));
saveSettings(context); saveSettings(context);
}); });
}, },
@ -60,7 +60,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
); );
}).toList())), }).toList())),
SwitchListTile( SwitchListTile(
title: Text(AppLocalizations.of(context).settingTheme, style: TextStyle(color: settings.current().mainTextColor())), title: Text(AppLocalizations.of(context)!.settingTheme, style: TextStyle(color: settings.current().mainTextColor())),
value: settings.current() == Opaque.light, value: settings.current() == Opaque.light,
onChanged: (bool value) { onChanged: (bool value) {
if (value) { if (value) {
@ -75,11 +75,11 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
secondary: Icon(Icons.lightbulb_outline, color: settings.current().mainTextColor()), secondary: Icon(Icons.lightbulb_outline, color: settings.current().mainTextColor()),
), ),
ListTile( ListTile(
title: Text(/*AppLocalizations.of(context).settingLanguage*/ "UI Columns", style: TextStyle(color: settings.current().mainTextColor())), title: Text(/*AppLocalizations.of(context)!.settingLanguage*/ "UI Columns", style: TextStyle(color: settings.current().mainTextColor())),
leading: Icon(Icons.table_chart, color: settings.current().mainTextColor()), leading: Icon(Icons.table_chart, color: settings.current().mainTextColor()),
trailing: DropdownButton( trailing: DropdownButton(
value: "Single", value: "Single",
onChanged: (String newValue) { onChanged: (String? newValue) {
if (newValue == "Double (1:2)") { if (newValue == "Double (1:2)") {
Provider.of<FlwtchState>(context).columns = [1, 2]; Provider.of<FlwtchState>(context).columns = [1, 2];
} else if (newValue == "Double (1:4)") { } else if (newValue == "Double (1:4)") {
@ -95,8 +95,8 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
); );
}).toList())), }).toList())),
SwitchListTile( SwitchListTile(
title: Text(AppLocalizations.of(context).blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor())), title: Text(AppLocalizations.of(context)!.blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor())),
subtitle: Text(AppLocalizations.of(context).descriptionBlockUnknownConnections), subtitle: Text(AppLocalizations.of(context)!.descriptionBlockUnknownConnections),
value: settings.blockUnknownConnections, value: settings.blockUnknownConnections,
onChanged: (bool value) { onChanged: (bool value) {
if (value) { if (value) {
@ -111,8 +111,8 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
secondary: Icon(Icons.app_blocking, color: settings.current().mainTextColor()), secondary: Icon(Icons.app_blocking, color: settings.current().mainTextColor()),
), ),
SwitchListTile( SwitchListTile(
title: Text(AppLocalizations.of(context).experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor())), title: Text(AppLocalizations.of(context)!.experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor())),
subtitle: Text(AppLocalizations.of(context).descriptionExperiments), subtitle: Text(AppLocalizations.of(context)!.descriptionExperiments),
value: settings.experimentsEnabled, value: settings.experimentsEnabled,
onChanged: (bool value) { onChanged: (bool value) {
if (value) { if (value) {
@ -130,9 +130,9 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
child: Column( child: Column(
children: [ children: [
SwitchListTile( SwitchListTile(
title: Text(AppLocalizations.of(context).enableGroups, style: TextStyle(color: settings.current().mainTextColor())), title: Text(AppLocalizations.of(context)!.enableGroups, style: TextStyle(color: settings.current().mainTextColor())),
subtitle: Text(AppLocalizations.of(context).descriptionExperimentsGroups), subtitle: Text(AppLocalizations.of(context)!.descriptionExperimentsGroups),
value: settings.experiments.containsKey(TapirGroupsExperiment) && settings.experiments[TapirGroupsExperiment], value: settings.experiments.containsKey(TapirGroupsExperiment) && settings.experiments[TapirGroupsExperiment]!,
onChanged: (bool value) { onChanged: (bool value) {
if (value) { if (value) {
settings.enableExperiment(TapirGroupsExperiment); settings.enableExperiment(TapirGroupsExperiment);
@ -156,7 +156,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
height: 128, height: 128,
)), )),
applicationName: "Cwtch (Flutter UI)", applicationName: "Cwtch (Flutter UI)",
applicationVersion: AppLocalizations.of(context).version.replaceAll("%1", constructVersionString(Provider.of<Settings>(context).packageInfo)), applicationVersion: AppLocalizations.of(context)!.version.replaceAll("%1", constructVersionString(Provider.of<Settings>(context).packageInfo)),
applicationLegalese: '\u{a9} 2021 Open Privacy Research Society', applicationLegalese: '\u{a9} 2021 Open Privacy Research Society',
), ),
])))); ]))));
@ -177,22 +177,22 @@ String constructVersionString(PackageInfo pinfo) {
/// an individual language code. There might be a more efficient way of doing this. /// an individual language code. There might be a more efficient way of doing this.
String getLanguageFull(context, String languageCode) { String getLanguageFull(context, String languageCode) {
if (languageCode == "en") { if (languageCode == "en") {
return AppLocalizations.of(context).localeEn; return AppLocalizations.of(context)!.localeEn;
} }
if (languageCode == "es") { if (languageCode == "es") {
return AppLocalizations.of(context).localeEs; return AppLocalizations.of(context)!.localeEs;
} }
if (languageCode == "fr") { if (languageCode == "fr") {
return AppLocalizations.of(context).localeFr; return AppLocalizations.of(context)!.localeFr;
} }
if (languageCode == "pt") { if (languageCode == "pt") {
return AppLocalizations.of(context).localePt; return AppLocalizations.of(context)!.localePt;
} }
if (languageCode == "de") { if (languageCode == "de") {
return AppLocalizations.of(context).localeDe; return AppLocalizations.of(context)!.localeDe;
} }
if (languageCode == "it") { if (languageCode == "it") {
return AppLocalizations.of(context).localeIt; return AppLocalizations.of(context)!.localeIt;
} }
return languageCode; return languageCode;
} }

View File

@ -42,7 +42,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(Provider.of<ContactInfoState>(context).nickname + " " + AppLocalizations.of(context).conversationSettings), title: Text(Provider.of<ContactInfoState>(context).nickname + " " + AppLocalizations.of(context)!.conversationSettings),
), ),
body: _buildSettingsList(), body: _buildSettingsList(),
); );
@ -68,24 +68,28 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).groupAddr), CwtchLabel(label: AppLocalizations.of(context)!.groupAddr),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchTextField( CwtchTextField(
controller: ctrlrGroupAddr, controller: ctrlrGroupAddr,
labelText: '',
validator: (value) {},
) )
]), ]),
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).server), CwtchLabel(label: AppLocalizations.of(context)!.server),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchTextField( CwtchTextField(
controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).server), controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).server),
validator: (value) {},
labelText: '',
) )
]), ]),
// Nickname Save Button // Nickname Save Button
@ -93,7 +97,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).displayNameLabel), CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -107,14 +111,14 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
Provider.of<FlwtchState>(context, listen: false).cwtch.SetGroupAttribute(profileOnion, handle, "local.name", ctrlrNick.text); Provider.of<FlwtchState>(context, listen: false).cwtch.SetGroupAttribute(profileOnion, handle, "local.name", ctrlrNick.text);
}, },
icon: Icon(Icons.save), icon: Icon(Icons.save),
tooltip: AppLocalizations.of(context).saveBtn, tooltip: AppLocalizations.of(context)!.saveBtn,
) )
]), ]),
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).conversationSettings), CwtchLabel(label: AppLocalizations.of(context)!.conversationSettings),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -127,7 +131,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
void _copyOnion() { void _copyOnion() {
Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion)); Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion));
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification)); final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedClipboardNotification));
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
} }
} }

View File

@ -87,7 +87,7 @@ class _MessageViewState extends State<MessageView> {
)); ));
} }
void _sendMessage([String ignoredParam]) { void _sendMessage([String? ignoredParam]) {
ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text); ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text);
Provider.of<FlwtchState>(context, listen: false) Provider.of<FlwtchState>(context, listen: false)
.cwtch .cwtch
@ -95,7 +95,7 @@ class _MessageViewState extends State<MessageView> {
_sendMessageHelper(); _sendMessageHelper();
} }
void _sendInvitation([String ignoredParam]) { void _sendInvitation([String? ignoredParam]) {
Provider.of<FlwtchState>(context, listen: false) Provider.of<FlwtchState>(context, listen: false)
.cwtch .cwtch
.SendInvitation(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion, this.selectedContact); .SendInvitation(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion, this.selectedContact);
@ -167,7 +167,7 @@ class _MessageViewState extends State<MessageView> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
Text(AppLocalizations.of(bcontext).invitationLabel), Text(AppLocalizations.of(bcontext)!.invitationLabel),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -182,7 +182,7 @@ class _MessageViewState extends State<MessageView> {
height: 20, height: 20,
), ),
ElevatedButton( ElevatedButton(
child: Text(AppLocalizations.of(bcontext).inviteBtn, semanticsLabel: AppLocalizations.of(bcontext).inviteBtn), child: Text(AppLocalizations.of(bcontext)!.inviteBtn, semanticsLabel: AppLocalizations.of(bcontext)!.inviteBtn),
onPressed: () { onPressed: () {
this._sendInvitation(); this._sendInvitation();
Navigator.pop(bcontext); Navigator.pop(bcontext);

View File

@ -59,7 +59,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
padding: EdgeInsets.all(2), padding: EdgeInsets.all(2),
child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
CwtchLabel(label: AppLocalizations.of(context).displayNameLabel), CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -78,7 +78,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
}, },
icon: Icon(Icons.save), icon: Icon(Icons.save),
tooltip: AppLocalizations.of(context).saveBtn, tooltip: AppLocalizations.of(context)!.saveBtn,
) )
]), ]),
@ -87,7 +87,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).addressLabel), CwtchLabel(label: AppLocalizations.of(context)!.addressLabel),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
@ -95,19 +95,19 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).onion), controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).onion),
onPressed: _copyOnion, onPressed: _copyOnion,
icon: Icon(Icons.copy), icon: Icon(Icons.copy),
tooltip: AppLocalizations.of(context).copyBtn, tooltip: AppLocalizations.of(context)!.copyBtn,
) )
]), ]),
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchLabel(label: AppLocalizations.of(context).conversationSettings), CwtchLabel(label: AppLocalizations.of(context)!.conversationSettings),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
SwitchListTile( SwitchListTile(
title: Text(AppLocalizations.of(context).blockBtn, style: TextStyle(color: settings.current().mainTextColor())), title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor())),
value: Provider.of<ContactInfoState>(context).isBlocked, value: Provider.of<ContactInfoState>(context).isBlocked,
onChanged: (bool blocked) { onChanged: (bool blocked) {
// Save local blocked status // Save local blocked status
@ -138,15 +138,15 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
secondary: Icon(Icons.block, color: settings.current().mainTextColor()), secondary: Icon(Icons.block, color: settings.current().mainTextColor()),
), ),
ListTile( ListTile(
title: Text(AppLocalizations.of(context).savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())), title: Text(AppLocalizations.of(context)!.savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())),
subtitle: Text(AppLocalizations.of(context).savePeerHistoryDescription), subtitle: Text(AppLocalizations.of(context)!.savePeerHistoryDescription),
leading: Icon(Icons.history_sharp, color: settings.current().mainTextColor()), leading: Icon(Icons.history_sharp, color: settings.current().mainTextColor()),
trailing: DropdownButton( trailing: DropdownButton(
value: Provider.of<ContactInfoState>(context).savePeerHistory == "DefaultDeleteHistory" value: Provider.of<ContactInfoState>(context).savePeerHistory == "DefaultDeleteHistory"
? AppLocalizations.of(context).dontSavePeerHistory ? AppLocalizations.of(context)!.dontSavePeerHistory
: (Provider.of<ContactInfoState>(context).savePeerHistory == "SaveHistory" : (Provider.of<ContactInfoState>(context).savePeerHistory == "SaveHistory"
? AppLocalizations.of(context).savePeerHistory ? AppLocalizations.of(context)!.savePeerHistory
: AppLocalizations.of(context).dontSavePeerHistory), : AppLocalizations.of(context)!.dontSavePeerHistory),
onChanged: (newValue) { onChanged: (newValue) {
setState(() { setState(() {
// Set whether or not to dave the Contact History... // Set whether or not to dave the Contact History...
@ -154,7 +154,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
var onion = Provider.of<ContactInfoState>(context, listen: false).onion; var onion = Provider.of<ContactInfoState>(context, listen: false).onion;
const SaveHistoryKey = "SavePeerHistory"; const SaveHistoryKey = "SavePeerHistory";
if (newValue == AppLocalizations.of(context).savePeerHistory) { if (newValue == AppLocalizations.of(context)!.savePeerHistory) {
Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = "SaveHistory"; Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = "SaveHistory";
final setPeerAttribute = { final setPeerAttribute = {
"EventType": "SetPeerAttribute", "EventType": "SetPeerAttribute",
@ -174,7 +174,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
} }
}); });
}, },
items: [AppLocalizations.of(context).savePeerHistory, AppLocalizations.of(context).dontSavePeerHistory].map<DropdownMenuItem<String>>((String value) { items: [AppLocalizations.of(context)!.savePeerHistory, AppLocalizations.of(context)!.dontSavePeerHistory].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: value, value: value,
child: Text(value), child: Text(value),
@ -188,7 +188,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
void _copyOnion() { void _copyOnion() {
Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion)); Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion));
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification)); final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedClipboardNotification));
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
} }
} }

View File

@ -39,24 +39,24 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
child: Scaffold( child: Scaffold(
backgroundColor: Provider.of<Settings>(context).theme.backgroundMainColor(), backgroundColor: Provider.of<Settings>(context).theme.backgroundMainColor(),
appBar: AppBar( appBar: AppBar(
title: Text(AppLocalizations.of(context).titleManageProfiles), title: Text(AppLocalizations.of(context)!.titleManageProfiles),
actions: [ actions: [
IconButton(icon: TorIcon(), onPressed: _pushTorStatus), IconButton(icon: TorIcon(), onPressed: _pushTorStatus),
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug), IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug),
IconButton( IconButton(
icon: Icon(Icons.lock_open), icon: Icon(Icons.lock_open),
tooltip: AppLocalizations.of(context).tooltipUnlockProfiles, tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles,
onPressed: _modalUnlockProfiles, onPressed: _modalUnlockProfiles,
), ),
IconButton(icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context).tooltipOpenSettings, onPressed: _pushGlobalSettings), IconButton(icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context)!.tooltipOpenSettings, onPressed: _pushGlobalSettings),
], ],
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: _pushAddEditProfile, onPressed: _pushAddEditProfile,
tooltip: AppLocalizations.of(context).addNewProfileBtn, tooltip: AppLocalizations.of(context)!.addNewProfileBtn,
child: Icon( child: Icon(
Icons.add, Icons.add,
semanticLabel: AppLocalizations.of(context).addNewProfileBtn, semanticLabel: AppLocalizations.of(context)!.addNewProfileBtn,
), ),
), ),
body: _buildProfileManager(), //_buildSuggestions(), body: _buildProfileManager(), //_buildSuggestions(),
@ -122,12 +122,13 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
Text(AppLocalizations.of(context).enterProfilePassword), Text(AppLocalizations.of(context)!.enterProfilePassword),
SizedBox( SizedBox(
height: 20, height: 20,
), ),
CwtchPasswordField( CwtchPasswordField(
controller: ctrlrPassword, controller: ctrlrPassword,
validator: (value) {},
), ),
SizedBox( SizedBox(
height: 20, height: 20,
@ -136,7 +137,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
Spacer(), Spacer(),
Expanded( Expanded(
child: ElevatedButton( child: ElevatedButton(
child: Text(AppLocalizations.of(context).unlock, semanticsLabel: AppLocalizations.of(context).unlock), child: Text(AppLocalizations.of(context)!.unlock, semanticsLabel: AppLocalizations.of(context)!.unlock),
onPressed: () { onPressed: () {
Provider.of<FlwtchState>(context, listen: false).cwtch.LoadProfiles(ctrlrPassword.value.text); Provider.of<FlwtchState>(context, listen: false).cwtch.LoadProfiles(ctrlrPassword.value.text);
ctrlrPassword.text = ""; ctrlrPassword.text = "";

View File

@ -44,7 +44,7 @@ class _TorStatusView extends State<TorStatusView> {
ListTile( ListTile(
leading: TorIcon(), leading: TorIcon(),
title: Text("Tor Status"), title: Text("Tor Status"),
subtitle: Text(torStatus.progress == 100 ? AppLocalizations.of(context).networkStatusOnline : torStatus.status), subtitle: Text(torStatus.progress == 100 ? AppLocalizations.of(context)!.networkStatusOnline : torStatus.status),
trailing: ElevatedButton( trailing: ElevatedButton(
child: Text("Reset"), child: Text("Reset"),
onPressed: () { onPressed: () {

View File

@ -9,7 +9,7 @@ import '../model.dart';
// Pass an onChanged handler to access value // Pass an onChanged handler to access value
class DropdownContacts extends StatefulWidget { class DropdownContacts extends StatefulWidget {
DropdownContacts({ DropdownContacts({
this.onChanged, required this.onChanged,
}); });
final Function(dynamic) onChanged; final Function(dynamic) onChanged;
@ -18,18 +18,18 @@ class DropdownContacts extends StatefulWidget {
} }
class _DropdownContactsState extends State<DropdownContacts> { class _DropdownContactsState extends State<DropdownContacts> {
String selected; late String selected;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DropdownButton( return DropdownButton(
value: this.selected, 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.map<DropdownMenuItem<String>>((ContactInfoState contact) {
return DropdownMenuItem<String>(value: contact.onion, child: Text(contact.nickname ?? contact.onion)); return DropdownMenuItem<String>(value: contact.onion, child: Text(contact.nickname));
}).toList(), }).toList(),
onChanged: (newVal) { onChanged: (newVal) {
setState(() { setState(() {
this.selected = newVal; this.selected = newVal.toString();
}); });
if (widget.onChanged != null) { if (widget.onChanged != null) {
widget.onChanged(newVal); widget.onChanged(newVal);

View File

@ -5,9 +5,9 @@ import 'package:provider/provider.dart';
// Provides a styled Text Field for use in Form Widgets. // Provides a styled Text Field for use in Form Widgets.
// Callers must provide a text controller, label helper text and a validator. // Callers must provide a text controller, label helper text and a validator.
class CwtchButtonTextField extends StatefulWidget { class CwtchButtonTextField extends StatefulWidget {
CwtchButtonTextField({this.controller, this.onPressed, this.icon, this.tooltip, this.readonly = true}); CwtchButtonTextField({required this.controller, required this.onPressed, required this.icon, required this.tooltip, this.readonly = true});
final TextEditingController controller; final TextEditingController controller;
final Function onPressed; final Function()? onPressed;
final Icon icon; final Icon icon;
final String tooltip; final String tooltip;
final bool readonly; final bool readonly;

View File

@ -123,7 +123,7 @@ class _ContactRowState extends State<ContactRow> {
String dateToNiceString(DateTime date) { String dateToNiceString(DateTime date) {
if (date.millisecondsSinceEpoch == 0) { if (date.millisecondsSinceEpoch == 0) {
return AppLocalizations.of(context).dateNever; return AppLocalizations.of(context)!.dateNever;
} }
// If the last message was over a day ago, just state the date // If the last message was over a day ago, just state the date
if (DateTime.now().difference(date).inDays > 1) { if (DateTime.now().difference(date).inDays > 1) {

View File

@ -6,7 +6,7 @@ import '../settings.dart';
// Callers must provide a label text // Callers must provide a label text
// TODO: Integrate this with a settings "zoom" / accessibility setting // TODO: Integrate this with a settings "zoom" / accessibility setting
class CwtchLabel extends StatefulWidget { class CwtchLabel extends StatefulWidget {
CwtchLabel({this.label}); CwtchLabel({required this.label});
final String label; final String label;
@override @override

View File

@ -37,11 +37,7 @@ class InvitationBubbleState extends State<InvitationBubble> {
var senderDisplayStr = ""; var senderDisplayStr = "";
if (Provider.of<MessageState>(context).senderOnion != null) { if (Provider.of<MessageState>(context).senderOnion != null) {
var contact = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).senderOnion); var contact = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).senderOnion);
if (contact == null) { senderDisplayStr = contact.nickname;
senderDisplayStr = Provider.of<MessageState>(context).senderOnion;
} else {
senderDisplayStr = contact.nickname ?? contact.onion;
}
} }
var wdgSender = Center( var wdgSender = Center(
widthFactor: 1, widthFactor: 1,

View File

@ -31,7 +31,7 @@ class MessageBubbleState extends State<MessageBubble> {
if (contact == null) { if (contact == null) {
senderDisplayStr = Provider.of<MessageState>(context).senderOnion; senderDisplayStr = Provider.of<MessageState>(context).senderOnion;
} else { } else {
senderDisplayStr = contact.nickname ?? contact.onion; senderDisplayStr = contact.nickname;
} }
} }
var wdgSender = SelectableText(senderDisplayStr, var wdgSender = SelectableText(senderDisplayStr,

View File

@ -14,7 +14,7 @@ import 'messagebubble.dart';
import 'messageloadingbubble.dart'; import 'messageloadingbubble.dart';
class MessageRow extends StatefulWidget { class MessageRow extends StatefulWidget {
MessageRow({Key key}) : super(key: key); MessageRow({Key? key}) : super(key: key);
@override @override
_MessageRowState createState() => _MessageRowState(); _MessageRowState createState() => _MessageRowState();
@ -52,10 +52,12 @@ class _MessageRowState extends State<MessageRow> {
child: Padding( child: Padding(
padding: EdgeInsets.all(4.0), padding: EdgeInsets.all(4.0),
child: ProfileImage( child: ProfileImage(
diameter: 48.0, diameter: 48.0,
imagePath: Provider.of<MessageState>(context).senderImage ?? contact.imagePath, imagePath: Provider.of<MessageState>(context).senderImage ?? contact.imagePath,
//maskOut: contact.status != "Authenticated", //maskOut: contact.status != "Authenticated",
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()))); border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor(),
badgeTextColor: Colors.red, badgeColor: Colors.red,
)));
widgetRow = <Widget>[ widgetRow = <Widget>[
wdgPortrait, wdgPortrait,
@ -76,7 +78,7 @@ class _MessageRowState extends State<MessageRow> {
case 101: case 101:
return InvitationBubble(); return InvitationBubble();
} }
return null; return MalformedBubble();
} }
void _btnAdd() { void _btnAdd() {
@ -94,7 +96,7 @@ class _MessageRowState extends State<MessageRow> {
final setPeerAttributeJson = jsonEncode(setPeerAttribute); final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); 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));
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
} }
} }

View File

@ -5,7 +5,7 @@ import '../settings.dart';
// Provides a styled Password Input Field for use in Form Widgets. // Provides a styled Password Input Field for use in Form Widgets.
// Callers must provide a text controller, label helper text and a validator. // Callers must provide a text controller, label helper text and a validator.
class CwtchPasswordField extends StatefulWidget { class CwtchPasswordField extends StatefulWidget {
CwtchPasswordField({this.controller, this.validator}); CwtchPasswordField({required this.controller, required this.validator});
final TextEditingController controller; final TextEditingController controller;
final FormFieldValidator validator; final FormFieldValidator validator;

View File

@ -5,7 +5,7 @@ import 'package:provider/provider.dart';
import '../settings.dart'; import '../settings.dart';
class ProfileImage extends StatefulWidget { class ProfileImage extends StatefulWidget {
ProfileImage({this.imagePath, this.diameter, this.border, this.badgeCount = 0, this.badgeColor, this.badgeTextColor, this.maskOut = false}); ProfileImage({required this.imagePath, required this.diameter, required this.border, this.badgeCount = 0, required this.badgeColor, required this.badgeTextColor, this.maskOut = false});
final double diameter; final double diameter;
final String imagePath; final String imagePath;
final Color border; final Color border;

View File

@ -55,7 +55,7 @@ class _ProfileRowState extends State<ProfileRow> {
)), )),
IconButton( IconButton(
enableFeedback: true, enableFeedback: true,
tooltip: AppLocalizations.of(context).editProfile + " " + profile.nickname, tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname,
icon: Icon(Icons.create, color: Provider.of<Settings>(context).current().mainTextColor()), icon: Icon(Icons.create, color: Provider.of<Settings>(context).current().mainTextColor()),
onPressed: () { onPressed: () {
_pushAddEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath); _pushAddEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath);

View File

@ -7,7 +7,7 @@ doNothing(String x) {}
// Provides a styled Text Field for use in Form Widgets. // Provides a styled Text Field for use in Form Widgets.
// Callers must provide a text controller, label helper text and a validator. // Callers must provide a text controller, label helper text and a validator.
class CwtchTextField extends StatefulWidget { class CwtchTextField extends StatefulWidget {
CwtchTextField({this.controller, this.labelText, this.validator, this.onChanged = doNothing}); CwtchTextField({required this.controller, required this.labelText, required this.validator, this.onChanged = doNothing});
final TextEditingController controller; final TextEditingController controller;
final String labelText; final String labelText;
final FormFieldValidator validator; final FormFieldValidator validator;

View File

@ -23,8 +23,8 @@ class _TorIconState extends State<TorIcon> {
color: Provider.of<Settings>(context).theme.mainTextColor(), color: Provider.of<Settings>(context).theme.mainTextColor(),
colorBlendMode: BlendMode.srcIn, colorBlendMode: BlendMode.srcIn,
semanticLabel: Provider.of<TorStatus>(context).progress == 100 semanticLabel: Provider.of<TorStatus>(context).progress == 100
? AppLocalizations.of(context).networkStatusOnline ? AppLocalizations.of(context)!.networkStatusOnline
: (Provider.of<TorStatus>(context).progress == 0 ? AppLocalizations.of(context).networkStatusDisconnected : AppLocalizations.of(context).networkStatusAttemptingTor), : (Provider.of<TorStatus>(context).progress == 0 ? AppLocalizations.of(context)!.networkStatusDisconnected : AppLocalizations.of(context)!.networkStatusAttemptingTor),
); );
} }
} }

View File

@ -18,7 +18,7 @@ class _TorStatusState extends State<TorStatusLabel> {
stream: Provider.of<FlwtchState>(context).appStatus.torStatus(), stream: Provider.of<FlwtchState>(context).appStatus.torStatus(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) { builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
return Text( return Text(
snapshot.hasData ? snapshot.data : AppLocalizations.of(context).loadingTor, snapshot.hasData ? snapshot.data! : AppLocalizations.of(context)!.loadingTor,
style: Theme.of(context).textTheme.headline4, style: Theme.of(context).textTheme.headline4,
); );
}, },

View File

@ -63,7 +63,7 @@ packages:
name: cupertino_icons name: cupertino_icons
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.2" version: "1.0.3"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -84,7 +84,7 @@ packages:
name: file name: file
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.1.0" version: "6.1.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -128,7 +128,7 @@ packages:
name: http name: http
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.13.1" version: "0.13.3"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -184,42 +184,42 @@ packages:
name: package_info_plus name: package_info_plus
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.1"
package_info_plus_linux: package_info_plus_linux:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_linux name: package_info_plus_linux
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.2"
package_info_plus_macos: package_info_plus_macos:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_macos name: package_info_plus_macos
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.1.1"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_platform_interface name: package_info_plus_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.1"
package_info_plus_web: package_info_plus_web:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_web name: package_info_plus_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.1"
package_info_plus_windows: package_info_plus_windows:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_windows name: package_info_plus_windows
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.1"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -261,7 +261,7 @@ packages:
name: path_provider_windows name: path_provider_windows
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
pedantic: pedantic:
dependency: transitive dependency: transitive
description: description:
@ -296,7 +296,7 @@ packages:
name: provider name: provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.3.2+3" version: "5.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -385,7 +385,7 @@ packages:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.5" version: "2.1.1"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@ -394,5 +394,5 @@ packages:
source: hosted source: hosted
version: "0.2.0" version: "0.2.0"
sdks: sdks:
dart: ">=2.12.0 <3.0.0" dart: ">=2.13.0 <3.0.0"
flutter: ">=1.20.0" flutter: ">=1.20.0"

View File

@ -18,12 +18,12 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
provider: "4.3.2+3" provider: 5.0.0
package_info_plus: ^1.0.0 package_info_plus: ^1.0.0
#intl_translation: any #intl_translation: any
flutter_localizations: flutter_localizations: