From 2394a1daaae43b826380276a31241ac94589fb6c Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 24 May 2021 17:11:39 -0700 Subject: [PATCH] Upgrade to null safe sdk --- lib/cwtch/cwtch.dart | 12 +-- lib/cwtch/cwtchNotifier.dart | 14 ++-- lib/cwtch/ffi.dart | 12 +-- lib/cwtch/gomobile.dart | 18 ++--- lib/main.dart | 8 +- lib/main_test.dart | 2 +- lib/model.dart | 125 +++++++++++++----------------- lib/models/servers.dart | 4 +- lib/opaque.dart | 2 +- lib/settings.dart | 6 +- lib/torstatus.dart | 2 + lib/views/addcontactview.dart | 51 ++++++------ lib/views/addeditprofileview.dart | 52 +++++++------ lib/views/contactsview.dart | 26 ++++--- lib/views/doublecolview.dart | 4 +- lib/views/globalsettingsview.dart | 42 +++++----- lib/views/groupsettingsview.dart | 18 +++-- lib/views/messageview.dart | 8 +- lib/views/peersettingsview.dart | 28 +++---- lib/views/profilemgrview.dart | 15 ++-- lib/views/torstatusview.dart | 2 +- lib/widgets/DropdownContacts.dart | 8 +- lib/widgets/buttontextfield.dart | 4 +- lib/widgets/contactrow.dart | 2 +- lib/widgets/cwtchlabel.dart | 2 +- lib/widgets/invitationbubble.dart | 6 +- lib/widgets/messagebubble.dart | 2 +- lib/widgets/messagerow.dart | 16 ++-- lib/widgets/passwordfield.dart | 2 +- lib/widgets/profileimage.dart | 2 +- lib/widgets/profilerow.dart | 2 +- lib/widgets/textfield.dart | 2 +- lib/widgets/tor_icon.dart | 4 +- lib/widgets/torstatuslabel.dart | 2 +- pubspec.lock | 26 +++---- pubspec.yaml | 4 +- 36 files changed, 267 insertions(+), 268 deletions(-) diff --git a/lib/cwtch/cwtch.dart b/lib/cwtch/cwtch.dart index 87f922d..1b4b307 100644 --- a/lib/cwtch/cwtch.dart +++ b/lib/cwtch/cwtch.dart @@ -26,19 +26,19 @@ abstract class Cwtch { void DebugResetContact(String profileOnion, String contactHandle); // ignore: non_constant_identifier_names - Future ACNEvents(); + Future ACNEvents(); // ignore: non_constant_identifier_names - Future ContactEvents(); + Future ContactEvents(); // ignore: non_constant_identifier_names - Future GetProfiles(); + Future GetProfiles(); // ignore: non_constant_identifier_names - Future NumMessages(String profile, String handle); + Future NumMessages(String profile, String handle); // ignore: non_constant_identifier_names - Future GetMessage(String profile, String handle, int index); + Future GetMessage(String profile, String handle, int index); // ignore: non_constant_identifier_names - Future GetMessages(String profile, String handle, int start, int end); + Future GetMessages(String profile, String handle, int start, int end); // ignore: non_constant_identifier_names void SendMessage(String profile, String handle, String message); // ignore: non_constant_identifier_names diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index c1602d5..ad29852 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -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) // Takes Notifiers and triggers them on appropriate events class CwtchNotifier { - ProfileListState profileCN; - Settings settings; - ErrorHandler error; - TorStatus torStatus; + late ProfileListState profileCN; + late Settings settings; + late ErrorHandler error; + late TorStatus torStatus; CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN) { profileCN = pcn; @@ -74,7 +74,7 @@ class CwtchNotifier { var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["RemotePeer"]).getMessageKey(idx); if (key == null) break; try { - var message = Provider.of(key.currentContext, listen: false); + var message = Provider.of(key.currentContext!, listen: false); if (message == null) break; message.ackd = true; } catch (e) { @@ -94,7 +94,7 @@ class CwtchNotifier { var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx); if (key == null) break; try { - var message = Provider.of(key.currentContext, listen: false); + var message = Provider.of(key.currentContext!, listen: false); if (message == null) break; message.ackd = true; } catch (e) { @@ -109,7 +109,7 @@ class CwtchNotifier { var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx); if (key == null) break; try { - var message = Provider.of(key.currentContext, listen: false); + var message = Provider.of(key.currentContext!, listen: false); if (message == null) break; message.error = true; } catch (e) { diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index ec29c2d..9c6d33f 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -56,9 +56,9 @@ typedef acn_events_function = Pointer Function(); typedef ACNEventsFn = Pointer Function(); class CwtchFfi implements Cwtch { - DynamicLibrary library; - CwtchNotifier cwtchNotifier; - Isolate cwtchIsolate; + late DynamicLibrary library; + late CwtchNotifier cwtchNotifier; + late Isolate cwtchIsolate; CwtchFfi(CwtchNotifier _cwtchNotifier) { if (Platform.isWindows) { @@ -79,9 +79,9 @@ class CwtchFfi implements Cwtch { String bundledTor = ""; Map envVars = Platform.environment; if (Platform.isLinux) { - home = envVars['HOME']; + home = (envVars['HOME'])!; } else if (Platform.isWindows) { - home = envVars['UserProfile']; + home = (envVars['UserProfile'])!; bundledTor = "Tor\\Tor\\tor.exe"; } 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 static Stream pollAppbusEvents() async* { - DynamicLibrary library; + late DynamicLibrary library; if (Platform.isWindows) { library = DynamicLibrary.open("libCwtch.dll"); } else if (Platform.isLinux) { diff --git a/lib/cwtch/gomobile.dart b/lib/cwtch/gomobile.dart index ce30d74..f8f6060 100644 --- a/lib/cwtch/gomobile.dart +++ b/lib/cwtch/gomobile.dart @@ -26,9 +26,9 @@ class CwtchGomobile implements Cwtch { final appbusEventChannelName = 'test.flutter.dev/eventBus'; - Future androidLibraryDir; - Future androidHomeDirectory; - CwtchNotifier cwtchNotifier; + late Future androidLibraryDir; + late Future androidHomeDirectory; + late CwtchNotifier cwtchNotifier; CwtchGomobile(CwtchNotifier _cwtchNotifier) { print("gomobile.dart: CwtchGomobile()"); @@ -73,34 +73,34 @@ class CwtchGomobile implements Cwtch { } // ignore: non_constant_identifier_names - Future ACNEvents() { + Future ACNEvents() { return cwtchPlatform.invokeMethod("ACNEvents"); } // ignore: non_constant_identifier_names - Future ContactEvents() { + Future ContactEvents() { return cwtchPlatform.invokeMethod("ContactEvents"); } // ignore: non_constant_identifier_names - Future GetProfiles() { + Future GetProfiles() { print("gomobile.dart: GetProfiles()"); return cwtchPlatform.invokeMethod("GetProfiles"); } // ignore: non_constant_identifier_names - Future NumMessages(String profile, String handle) { + Future NumMessages(String profile, String handle) { return cwtchPlatform.invokeMethod("NumMessages", {"profile": profile, "contact": handle}); } // ignore: non_constant_identifier_names - Future GetMessage(String profile, String handle, int index) { + Future GetMessage(String profile, String handle, int index) { print("gomobile.dart GetMessage " + index.toString()); return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "index": index}); } // ignore: non_constant_identifier_names - Future GetMessages(String profile, String handle, int start, int end) { + Future GetMessages(String profile, String handle, int start, int end) { return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "start": start, "end": end}); } diff --git a/lib/main.dart b/lib/main.dart index 8581fe3..d7d8ed4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -35,14 +35,14 @@ class Flwtch extends StatefulWidget { class FlwtchState extends State { final TextStyle biggerFont = const TextStyle(fontSize: 18); - Cwtch cwtch; + late Cwtch cwtch; bool cwtchInit = false; - ProfileInfoState selectedProfile; + late ProfileInfoState selectedProfile; String selectedConversation = ""; var columns = [1]; // default or 'single column' mode //var columns = [1, 1, 2]; - AppModel appStatus; - ProfileListState profs; + late AppModel appStatus; + late ProfileListState profs; @override initState() { diff --git a/lib/main_test.dart b/lib/main_test.dart index 0703049..22459bc 100644 --- a/lib/main_test.dart +++ b/lib/main_test.dart @@ -63,6 +63,6 @@ class DiskAssetBundle extends CachingAssetBundle { @override Future load(String key) async { - return _cache[key]; + return _cache[key]!; } } diff --git a/lib/model.dart b/lib/model.dart index c0cdddc..022ce27 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -14,33 +14,11 @@ import 'main.dart'; /// UI State /// //////////////////// -//todo: delete -class ProfileModel { - String onion; - String nickname; - String creationDate; - String imagePath; - HashMap 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 { final int o; final String d; - ChatMessage({this.o, this.d}); + ChatMessage({required this.o, required this.d}); ChatMessage.fromJson(Map json) : o = json['o'], @@ -74,16 +52,16 @@ class ProfileListState extends ChangeNotifier { ProfileInfoState getProfile(String 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 { List _contacts = []; - String _filter; + String _filter = ""; int get num => _contacts.length; int get numFiltered => isFiltered ? filteredList().length : num; - bool get isFiltered => _filter != null && _filter != ""; + bool get isFiltered => _filter != ""; String get filter => _filter; set filter(String newVal) { _filter = newVal; @@ -142,7 +120,7 @@ class ContactListState extends ChangeNotifier { ContactInfoState getContact(String 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; ProfileInfoState({ - this.onion, + required this.onion, nickname = "", imagePath = "", unreadMessages = 0, @@ -253,21 +231,21 @@ class ProfileInfoState extends ChangeNotifier { class ContactInfoState extends ChangeNotifier { final String profileOnion; final String onion; - String _nickname; + late String _nickname; - bool _isInvitation; - bool _isBlocked; - String _status; - String _imagePath; - String _savePeerHistory; - int _unreadMessages = 0; - int _totalMessages = 0; - DateTime _lastMessageTime; - Map keys; + late bool _isInvitation; + late bool _isBlocked; + late String _status; + late String _imagePath; + late String _savePeerHistory; + late int _unreadMessages = 0; + late int _totalMessages = 0; + late DateTime _lastMessageTime; + late Map> keys; // todo: a nicer way to model contacts, groups and other "entities" - bool _isGroup; - String _server; + late bool _isGroup; + late String _server; ContactInfoState( this.profileOnion, @@ -293,14 +271,14 @@ class ContactInfoState extends ChangeNotifier { this._totalMessages = numMessages; this._unreadMessages = numUnread; this._savePeerHistory = savePeerHistory; - this._lastMessageTime = lastMessageTime; + this._lastMessageTime = lastMessageTime == null ? DateTime.fromMillisecondsSinceEpoch(0) : lastMessageTime; this._server = server; - keys = Map(); + keys = Map>(); } - get nickname => this._nickname; + String get nickname => this._nickname; - get savePeerHistory => this._savePeerHistory; + String get savePeerHistory => this._savePeerHistory; set savePeerHistory(String newVal) { this._savePeerHistory = newVal; notifyListeners(); @@ -311,49 +289,49 @@ class ContactInfoState extends ChangeNotifier { notifyListeners(); } - get isGroup => this._isGroup; + bool get isGroup => this._isGroup; set isGroup(bool newVal) { this._isGroup = newVal; notifyListeners(); } - get isBlocked => this._isBlocked; + bool get isBlocked => this._isBlocked; set isBlocked(bool newVal) { this._isBlocked = newVal; notifyListeners(); } - get isInvitation => this._isInvitation; + bool get isInvitation => this._isInvitation; set isInvitation(bool newVal) { this._isInvitation = newVal; notifyListeners(); } - get status => this._status; + String get status => this._status; set status(String newVal) { this._status = newVal; notifyListeners(); } - get unreadMessages => this._unreadMessages; + int get unreadMessages => this._unreadMessages; set unreadMessages(int newVal) { this._unreadMessages = newVal; notifyListeners(); } - get totalMessages => this._totalMessages; + int get totalMessages => this._totalMessages; set totalMessages(int newVal) { this._totalMessages = newVal; notifyListeners(); } - get imagePath => this._imagePath; + String get imagePath => this._imagePath; set imagePath(String newVal) { this._imagePath = newVal; notifyListeners(); } - get lastMessageTime => this._lastMessageTime; + DateTime get lastMessageTime => this._lastMessageTime; set lastMessageTime(DateTime newVal) { this._lastMessageTime = newVal; notifyListeners(); @@ -374,7 +352,8 @@ class ContactInfoState extends ChangeNotifier { if (keys[index] == null) { keys[index] = GlobalKey(); } - return keys[index]; + GlobalKey ret = keys[index]!; + return ret; } } @@ -382,24 +361,24 @@ class MessageState extends ChangeNotifier { final String profileOnion; final String contactHandle; final int messageIndex; - String _message; - int _overlay; - String _inviteTarget; - String _inviteNick; - DateTime _timestamp; - String _senderOnion; - String _senderImage; - String _signature = ""; - bool _ackd = false; - bool _error = false; - bool _loaded = false; - bool _malformed = false; + late String _message; + late int _overlay; + late String _inviteTarget; + late String _inviteNick; + late DateTime _timestamp; + late String _senderOnion; + late String _senderImage; + late String _signature = ""; + late bool _ackd = false; + late bool _error = false; + late bool _loaded = false; + late bool _malformed = false; MessageState({ - BuildContext context, - this.profileOnion, - this.contactHandle, - this.messageIndex, + required BuildContext context, + required this.profileOnion, + required this.contactHandle, + required this.messageIndex, }) { this._senderOnion = profileOnion; tryLoad(context); @@ -408,8 +387,8 @@ class MessageState extends ChangeNotifier { get message => this._message; get overlay => this._overlay; get timestamp => this._timestamp; - get ackd => this._ackd; - get error => this._error; + bool get ackd => this._ackd; + bool get error => this._error; get malformed => this._malformed; get senderOnion => this._senderOnion; get senderImage => this._senderImage; @@ -444,7 +423,7 @@ class MessageState extends ChangeNotifier { dynamic message = jsonDecode(messageWrapper['Message']); this._message = message['d']; this._overlay = int.parse(message['o'].toString()); - this._timestamp = DateTime.tryParse(messageWrapper['Timestamp']); + this._timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!; this._senderOnion = messageWrapper['PeerID']; this._senderImage = messageWrapper['ContactImage']; @@ -490,7 +469,7 @@ class MessageState extends ChangeNotifier { class AppModel { final Cwtch cwtch; - AppModel({this.cwtch}); + AppModel({required this.cwtch}); Stream contactEvents() async* { while (true) { diff --git a/lib/models/servers.dart b/lib/models/servers.dart index dfc6202..854ce57 100644 --- a/lib/models/servers.dart +++ b/lib/models/servers.dart @@ -11,7 +11,7 @@ class ServerListState extends ChangeNotifier { ServerInfoState getServer(String 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 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 status; - ServerInfoState({this.onion, this.status}); + ServerInfoState({required this.onion, required this.status}); } diff --git a/lib/opaque.dart b/lib/opaque.dart index 9c21952..9126b4c 100644 --- a/lib/opaque.dart +++ b/lib/opaque.dart @@ -1225,7 +1225,7 @@ class Opaque extends OpaqueThemeType { return sidePaneMinSize() + chatPaneMinSize(); } - static OpaqueThemeType _current; + static late OpaqueThemeType _current; static final OpaqueThemeType dark = CwtchDark(); static final OpaqueThemeType light = CwtchLight(); static void setDark() { diff --git a/lib/settings.dart b/lib/settings.dart index 2696f78..7d3de53 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -14,12 +14,12 @@ const TapirGroupsExperiment = "tapir-groups-experiment"; /// Settings Pane. class Settings extends ChangeNotifier { Locale locale; - PackageInfo packageInfo; + late PackageInfo packageInfo; OpaqueThemeType theme; - bool experimentsEnabled; + late bool experimentsEnabled; HashMap experiments = HashMap.identity(); - bool blockUnknownConnections; + late bool blockUnknownConnections; /// Set the dark theme. void setDark() { diff --git a/lib/torstatus.dart b/lib/torstatus.dart index 076d3e1..5d0c09a 100644 --- a/lib/torstatus.dart +++ b/lib/torstatus.dart @@ -5,6 +5,8 @@ class TorStatus extends ChangeNotifier { String status; bool connected; + TorStatus({this.connected = false, this.progress = 0, this.status = ""}); + /// Called by the event bus. handleUpdate(int new_progress, String new_status) { if (progress == 100) { diff --git a/lib/views/addcontactview.dart b/lib/views/addcontactview.dart index 1c254d1..b66dbdb 100644 --- a/lib/views/addcontactview.dart +++ b/lib/views/addcontactview.dart @@ -36,7 +36,7 @@ class _AddContactViewState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(AppLocalizations.of(context).titleManageContacts), + title: Text(AppLocalizations.of(context)!.titleManageContacts), ), body: _buildForm(), ); @@ -46,7 +46,7 @@ class _AddContactViewState extends State { ctrlrOnion.text = Provider.of(context).onion; /// We display a different number of tabs dependening on the experiment setup - bool groupsEnabled = Provider.of(context).experimentsEnabled && Provider.of(context).experiments[TapirGroupsExperiment]; + bool groupsEnabled = Provider.of(context).experimentsEnabled && Provider.of(context).experiments[TapirGroupsExperiment]!; return Consumer(builder: (context, globalErrorHandler, child) { return DefaultTabController( length: groupsEnabled ? 4 : 1, @@ -62,7 +62,7 @@ class _AddContactViewState extends State { void _copyOnion() { Clipboard.setData(new ClipboardData(text: Provider.of(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); } @@ -72,7 +72,7 @@ class _AddContactViewState extends State { tabs: [ Tab( icon: Icon(Icons.person_add_rounded), - text: AppLocalizations.of(context).addPeer, + text: AppLocalizations.of(context)!.addPeer, ), ], ); @@ -84,11 +84,11 @@ class _AddContactViewState extends State { tabs: [ Tab( 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.group), text: AppLocalizations.of(context).createGroup), - Tab(icon: Icon(Icons.group_add), text: AppLocalizations.of(context).joinGroup), + 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_add), text: AppLocalizations.of(context)!.joinGroup), ], ); } @@ -103,7 +103,7 @@ class _AddContactViewState extends State { autovalidateMode: AutovalidateMode.always, key: _formKey, child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - CwtchLabel(label: AppLocalizations.of(context).profileOnionLabel), + CwtchLabel(label: AppLocalizations.of(context)!.profileOnionLabel), SizedBox( height: 20, ), @@ -111,12 +111,12 @@ class _AddContactViewState extends State { controller: ctrlrOnion, onPressed: _copyOnion, icon: Icon(Icons.copy), - tooltip: AppLocalizations.of(context).copyBtn, + tooltip: AppLocalizations.of(context)!.copyBtn, ), SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).pasteAddressToAddContact), + CwtchLabel(label: AppLocalizations.of(context)!.pasteAddressToAddContact), SizedBox( height: 20, ), @@ -127,9 +127,9 @@ class _AddContactViewState extends State { return null; } if (globalErrorHandler.invalidImportStringError) { - return AppLocalizations.of(context).invalidImportString; + return AppLocalizations.of(context)!.invalidImportString; } else if (globalErrorHandler.contactAlreadyExistsError) { - return AppLocalizations.of(context).contactAlreadyExists; + return AppLocalizations.of(context)!.contactAlreadyExists; } else if (globalErrorHandler.explicitAddContactSuccess) {} return null; }, @@ -144,12 +144,13 @@ class _AddContactViewState extends State { Future.delayed(const Duration(milliseconds: 500), () { 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); Navigator.pop(context); } }); }, + labelText: '', ) ]))); } @@ -176,13 +177,13 @@ class _AddContactViewState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - CwtchLabel(label: AppLocalizations.of(context).server), + CwtchLabel(label: AppLocalizations.of(context)!.server), SizedBox( height: 20, ), DropdownButton( onChanged: (newServer) { - server = newServer; + server = newServer.toString(); }, value: server, items: Provider.of(context).serverList.servers.map>((ServerInfoState serverInfo) { @@ -194,17 +195,22 @@ class _AddContactViewState extends State { SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).groupName), + CwtchLabel(label: AppLocalizations.of(context)!.groupName), SizedBox( 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( height: 20, ), ElevatedButton( onPressed: () {}, - child: Text(AppLocalizations.of(context).createGroupBtn), + child: Text(AppLocalizations.of(context)!.createGroupBtn), ), ], ))); @@ -219,7 +225,7 @@ class _AddContactViewState extends State { autovalidateMode: AutovalidateMode.always, key: _joinGroupFormKey, child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - CwtchLabel(label: AppLocalizations.of(context).joinGroupTab), + CwtchLabel(label: AppLocalizations.of(context)!.joinGroupTab), SizedBox( height: 20, ), @@ -230,7 +236,7 @@ class _AddContactViewState extends State { return null; } if (globalErrorHandler.importBundleError) { - return AppLocalizations.of(context).invalidImportString; + return AppLocalizations.of(context)!.invalidImportString; } else if (globalErrorHandler.importBundleSuccess) {} return null; }, @@ -240,12 +246,13 @@ class _AddContactViewState extends State { Future.delayed(const Duration(milliseconds: 500), () { 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); Navigator.pop(context); } }); }, + labelText: '', ) ]))); } diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index e54fb7e..e5db4bd 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -16,7 +16,7 @@ import '../opaque.dart'; import '../settings.dart'; class AddEditProfileView extends StatefulWidget { - const AddEditProfileView({Key key}) : super(key: key); + const AddEditProfileView({Key? key}) : super(key: key); @override _AddEditProfileViewState createState() => _AddEditProfileViewState(); @@ -30,8 +30,8 @@ class _AddEditProfileViewState extends State { final ctrlrPass = TextEditingController(text: ""); final ctrlrPass2 = TextEditingController(text: ""); final ctrlrOnion = TextEditingController(text: ""); - bool usePassword; - bool deleted; + late bool usePassword; + late bool deleted; @override void initState() { @@ -48,15 +48,15 @@ class _AddEditProfileViewState extends State { ctrlrOnion.text = Provider.of(context).onion; return Scaffold( appBar: AppBar( - title: Text(Provider.of(context).onion.isEmpty ? AppLocalizations.of(context).addProfileTitle : AppLocalizations.of(context).editProfileTitle), + title: Text(Provider.of(context).onion.isEmpty ? AppLocalizations.of(context)!.addProfileTitle : AppLocalizations.of(context)!.editProfileTitle), ), body: _buildForm(), ); } - void _handleSwitchPassword(bool value) { + void _handleSwitchPassword(bool? value) { setState(() { - usePassword = value; + usePassword = value!; }); } @@ -88,16 +88,18 @@ class _AddEditProfileViewState extends State { diameter: 120, maskOut: false, border: theme.theme.portraitOnlineBorderColor(), + badgeTextColor: Colors.red, + badgeColor: Colors.red, ) ])), Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - CwtchLabel(label: AppLocalizations.of(context).displayNameLabel), + CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel), SizedBox( height: 20, ), CwtchTextField( controller: ctrlrNick, - labelText: AppLocalizations.of(context).yourDisplayName, + labelText: AppLocalizations.of(context)!.yourDisplayName, validator: (value) { if (value.isEmpty) { return "Please enter a display name"; @@ -112,7 +114,7 @@ class _AddEditProfileViewState extends State { SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).addressLabel), + CwtchLabel(label: AppLocalizations.of(context)!.addressLabel), SizedBox( height: 20, ), @@ -120,7 +122,7 @@ class _AddEditProfileViewState extends State { controller: ctrlrOnion, onPressed: _copyOnion, icon: Icon(Icons.copy), - tooltip: AppLocalizations.of(context).copyBtn, + tooltip: AppLocalizations.of(context)!.copyBtn, ) ])), // We only allow setting password types on profile creation @@ -132,7 +134,7 @@ class _AddEditProfileViewState extends State { onChanged: _handleSwitchPassword, ), Text( - AppLocalizations.of(context).radioUsePassword, + AppLocalizations.of(context)!.radioUsePassword, style: TextStyle(color: theme.current().mainTextColor()), ), ])), @@ -145,7 +147,7 @@ class _AddEditProfileViewState extends State { Visibility( visible: Provider.of(context, listen: false).onion.isNotEmpty, child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - CwtchLabel(label: AppLocalizations.of(context).currentPasswordLabel), + CwtchLabel(label: AppLocalizations.of(context)!.currentPasswordLabel), SizedBox( height: 20, ), @@ -154,7 +156,7 @@ class _AddEditProfileViewState extends State { validator: (value) { // Password field can be empty when just updating the profile, not on creation if (Provider.of(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { - return AppLocalizations.of(context).passwordErrorEmpty; + return AppLocalizations.of(context)!.passwordErrorEmpty; } return null; }, @@ -163,7 +165,7 @@ class _AddEditProfileViewState extends State { height: 20, ), ])), - CwtchLabel(label: AppLocalizations.of(context).password1Label), + CwtchLabel(label: AppLocalizations.of(context)!.password1Label), SizedBox( height: 20, ), @@ -172,10 +174,10 @@ class _AddEditProfileViewState extends State { validator: (value) { // Password field can be empty when just updating the profile, not on creation if (Provider.of(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { - return AppLocalizations.of(context).passwordErrorEmpty; + return AppLocalizations.of(context)!.passwordErrorEmpty; } if (value != ctrlrPass2.value.text) { - return AppLocalizations.of(context).passwordErrorMatch; + return AppLocalizations.of(context)!.passwordErrorMatch; } return null; }, @@ -183,7 +185,7 @@ class _AddEditProfileViewState extends State { SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).password2Label), + CwtchLabel(label: AppLocalizations.of(context)!.password2Label), SizedBox( height: 20, ), @@ -192,10 +194,10 @@ class _AddEditProfileViewState extends State { validator: (value) { // Password field can be empty when just updating the profile, not on creation if (Provider.of(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { - return AppLocalizations.of(context).passwordErrorEmpty; + return AppLocalizations.of(context)!.passwordErrorEmpty; } if (value != ctrlrPass.value.text) { - return AppLocalizations.of(context).passwordErrorMatch; + return AppLocalizations.of(context)!.passwordErrorMatch; } return null; }), @@ -211,7 +213,7 @@ class _AddEditProfileViewState extends State { child: ElevatedButton( onPressed: _createPressed, child: Text( - Provider.of(context).onion.isEmpty ? AppLocalizations.of(context).addNewProfileBtn : AppLocalizations.of(context).saveProfileBtn, + Provider.of(context).onion.isEmpty ? AppLocalizations.of(context)!.addNewProfileBtn : AppLocalizations.of(context)!.saveProfileBtn, textAlign: TextAlign.center, ), ), @@ -225,7 +227,7 @@ class _AddEditProfileViewState extends State { height: 20, ), Tooltip( - message: AppLocalizations.of(context).enterCurrentPasswordForDelete, + message: AppLocalizations.of(context)!.enterCurrentPasswordForDelete, child: ElevatedButton.icon( onPressed: checkCurrentPassword() ? null @@ -234,7 +236,7 @@ class _AddEditProfileViewState extends State { }, style: ElevatedButton.styleFrom(primary: theme.current().defaultButtonColor()), 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 { // This will run all the validations in the form including // 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). - if (_formKey.currentState.validate()) { + if (_formKey.currentState!.validate()) { if (Provider.of(context, listen: false).onion.isEmpty) { if (usePassword == true) { Provider.of(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, ctrlrPass.value.text); @@ -322,7 +324,7 @@ showAlertDialog(BuildContext context) { foregroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonTextColor()), overlayColor: MaterialStateProperty.all(Opaque.current().defaultButtonActiveColor()), padding: MaterialStateProperty.all(EdgeInsets.all(20))), - child: Text(AppLocalizations.of(context).deleteProfileConfirmBtn), + child: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn), onPressed: () { // TODO Actually Delete the Peer Navigator.of(context).pop(); // dismiss dialog @@ -331,7 +333,7 @@ showAlertDialog(BuildContext context) { // set up the AlertDialog AlertDialog alert = AlertDialog( - title: Text(AppLocalizations.of(context).deleteProfileConfirmBtn), + title: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn), actions: [ cancelButton, continueButton, diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index ca4ad57..65169c8 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -12,14 +12,14 @@ import '../model.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class ContactsView extends StatefulWidget { - const ContactsView({Key key}) : super(key: key); + const ContactsView({Key? key}) : super(key: key); @override _ContactsViewState createState() => _ContactsViewState(); } class _ContactsViewState extends State { - TextEditingController ctrlrFilter; + late TextEditingController ctrlrFilter; bool showSearchBar = false; @override @@ -37,13 +37,15 @@ class _ContactsViewState extends State { imagePath: Provider.of(context).imagePath, diameter: 42, border: Provider.of(context).theme.portraitOnlineBorderColor(), + badgeTextColor: Colors.red, + badgeColor: Colors.red, ), SizedBox( width: 10, ), Expanded( child: Text( - "%1 » %2".replaceAll("%1", Provider.of(context).nickname ?? Provider.of(context).onion ?? '').replaceAll("%2", "Contacts"), + "%1 » %2".replaceAll("%1", Provider.of(context).nickname).replaceAll("%2", "Contacts"), overflow: TextOverflow.ellipsis, )), //todo ]), @@ -66,7 +68,7 @@ class _ContactsViewState extends State { ), floatingActionButton: FloatingActionButton( onPressed: _pushAddContact, - tooltip: AppLocalizations.of(context).tooltipAddContact, + tooltip: AppLocalizations.of(context)!.tooltipAddContact, child: const Icon(Icons.person_add_sharp), ), body: showSearchBar || Provider.of(context).isFiltered ? _buildFilterable() : _buildContactList(), @@ -75,16 +77,18 @@ class _ContactsViewState extends State { Widget _buildFilterable() { Widget txtfield = CwtchTextField( - controller: ctrlrFilter, - labelText: AppLocalizations.of(context).search, - onChanged: (newVal) { - Provider.of(context, listen: false).filter = newVal; - }); + controller: ctrlrFilter, + labelText: AppLocalizations.of(context)!.search, + onChanged: (newVal) { + Provider.of(context, listen: false).filter = newVal; + }, + validator: (value) {}, + ); return Column(children: [Padding(padding: EdgeInsets.all(8), child: txtfield), Expanded(child: _buildContactList())]); } Widget _buildContactList() { - final tiles = Provider.of(context).filteredList().map((ContactInfoState contact) { + final tiles = Provider.of(context).contacts.map((ContactInfoState contact) { return ChangeNotifierProvider.value(key: ValueKey(contact.profileOnion + "" + contact.onion), value: contact, builder: (_, __) => ContactRow()); }); final divided = ListTile.divideTiles( @@ -119,7 +123,7 @@ class _ContactsViewState extends State { } 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. ScaffoldMessenger.of(context).showSnackBar(snackBar); } diff --git a/lib/views/doublecolview.dart b/lib/views/doublecolview.dart index ac9c0bc..fba9d8a 100644 --- a/lib/views/doublecolview.dart +++ b/lib/views/doublecolview.dart @@ -20,7 +20,9 @@ class _DoubleColumnViewState extends State { children: [ Flexible( flex: flwtch.columns[0], - child: ContactsView(), + child: ContactsView( + key: widget.key, + ), ), Flexible( flex: flwtch.columns[1], diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 812a6f9..6648d79 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -24,7 +24,7 @@ class _GlobalSettingsViewState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(AppLocalizations.of(context).cwtchSettingsTitle), + title: Text(AppLocalizations.of(context)!.cwtchSettingsTitle), ), body: _buildSettingsList(), ); @@ -43,13 +43,13 @@ class _GlobalSettingsViewState extends State { ), child: Column(children: [ 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()), trailing: DropdownButton( value: Provider.of(context).locale.languageCode, - onChanged: (String newValue) { + onChanged: (String? newValue) { setState(() { - settings.switchLocale(Locale(newValue, '')); + settings.switchLocale(Locale(newValue!, '')); saveSettings(context); }); }, @@ -60,7 +60,7 @@ class _GlobalSettingsViewState extends State { ); }).toList())), 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, onChanged: (bool value) { if (value) { @@ -75,11 +75,11 @@ class _GlobalSettingsViewState extends State { secondary: Icon(Icons.lightbulb_outline, color: settings.current().mainTextColor()), ), 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()), trailing: DropdownButton( value: "Single", - onChanged: (String newValue) { + onChanged: (String? newValue) { if (newValue == "Double (1:2)") { Provider.of(context).columns = [1, 2]; } else if (newValue == "Double (1:4)") { @@ -95,8 +95,8 @@ class _GlobalSettingsViewState extends State { ); }).toList())), SwitchListTile( - title: Text(AppLocalizations.of(context).blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor())), - subtitle: Text(AppLocalizations.of(context).descriptionBlockUnknownConnections), + title: Text(AppLocalizations.of(context)!.blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor())), + subtitle: Text(AppLocalizations.of(context)!.descriptionBlockUnknownConnections), value: settings.blockUnknownConnections, onChanged: (bool value) { if (value) { @@ -111,8 +111,8 @@ class _GlobalSettingsViewState extends State { secondary: Icon(Icons.app_blocking, color: settings.current().mainTextColor()), ), SwitchListTile( - title: Text(AppLocalizations.of(context).experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor())), - subtitle: Text(AppLocalizations.of(context).descriptionExperiments), + title: Text(AppLocalizations.of(context)!.experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor())), + subtitle: Text(AppLocalizations.of(context)!.descriptionExperiments), value: settings.experimentsEnabled, onChanged: (bool value) { if (value) { @@ -130,9 +130,9 @@ class _GlobalSettingsViewState extends State { child: Column( children: [ SwitchListTile( - title: Text(AppLocalizations.of(context).enableGroups, style: TextStyle(color: settings.current().mainTextColor())), - subtitle: Text(AppLocalizations.of(context).descriptionExperimentsGroups), - value: settings.experiments.containsKey(TapirGroupsExperiment) && settings.experiments[TapirGroupsExperiment], + title: Text(AppLocalizations.of(context)!.enableGroups, style: TextStyle(color: settings.current().mainTextColor())), + subtitle: Text(AppLocalizations.of(context)!.descriptionExperimentsGroups), + value: settings.experiments.containsKey(TapirGroupsExperiment) && settings.experiments[TapirGroupsExperiment]!, onChanged: (bool value) { if (value) { settings.enableExperiment(TapirGroupsExperiment); @@ -156,7 +156,7 @@ class _GlobalSettingsViewState extends State { height: 128, )), applicationName: "Cwtch (Flutter UI)", - applicationVersion: AppLocalizations.of(context).version.replaceAll("%1", constructVersionString(Provider.of(context).packageInfo)), + applicationVersion: AppLocalizations.of(context)!.version.replaceAll("%1", constructVersionString(Provider.of(context).packageInfo)), 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. String getLanguageFull(context, String languageCode) { if (languageCode == "en") { - return AppLocalizations.of(context).localeEn; + return AppLocalizations.of(context)!.localeEn; } if (languageCode == "es") { - return AppLocalizations.of(context).localeEs; + return AppLocalizations.of(context)!.localeEs; } if (languageCode == "fr") { - return AppLocalizations.of(context).localeFr; + return AppLocalizations.of(context)!.localeFr; } if (languageCode == "pt") { - return AppLocalizations.of(context).localePt; + return AppLocalizations.of(context)!.localePt; } if (languageCode == "de") { - return AppLocalizations.of(context).localeDe; + return AppLocalizations.of(context)!.localeDe; } if (languageCode == "it") { - return AppLocalizations.of(context).localeIt; + return AppLocalizations.of(context)!.localeIt; } return languageCode; } diff --git a/lib/views/groupsettingsview.dart b/lib/views/groupsettingsview.dart index 34dbcfe..6750b81 100644 --- a/lib/views/groupsettingsview.dart +++ b/lib/views/groupsettingsview.dart @@ -42,7 +42,7 @@ class _GroupSettingsViewState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(Provider.of(context).nickname + " " + AppLocalizations.of(context).conversationSettings), + title: Text(Provider.of(context).nickname + " " + AppLocalizations.of(context)!.conversationSettings), ), body: _buildSettingsList(), ); @@ -68,24 +68,28 @@ class _GroupSettingsViewState extends State { SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).groupAddr), + CwtchLabel(label: AppLocalizations.of(context)!.groupAddr), SizedBox( height: 20, ), CwtchTextField( controller: ctrlrGroupAddr, + labelText: '', + validator: (value) {}, ) ]), Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).server), + CwtchLabel(label: AppLocalizations.of(context)!.server), SizedBox( height: 20, ), CwtchTextField( controller: TextEditingController(text: Provider.of(context, listen: false).server), + validator: (value) {}, + labelText: '', ) ]), // Nickname Save Button @@ -93,7 +97,7 @@ class _GroupSettingsViewState extends State { SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).displayNameLabel), + CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel), SizedBox( height: 20, ), @@ -107,14 +111,14 @@ class _GroupSettingsViewState extends State { Provider.of(context, listen: false).cwtch.SetGroupAttribute(profileOnion, handle, "local.name", ctrlrNick.text); }, icon: Icon(Icons.save), - tooltip: AppLocalizations.of(context).saveBtn, + tooltip: AppLocalizations.of(context)!.saveBtn, ) ]), Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).conversationSettings), + CwtchLabel(label: AppLocalizations.of(context)!.conversationSettings), SizedBox( height: 20, ), @@ -127,7 +131,7 @@ class _GroupSettingsViewState extends State { void _copyOnion() { Clipboard.setData(new ClipboardData(text: Provider.of(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); } } diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index 43dddb4..630e505 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -87,7 +87,7 @@ class _MessageViewState extends State { )); } - void _sendMessage([String ignoredParam]) { + void _sendMessage([String? ignoredParam]) { ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text); Provider.of(context, listen: false) .cwtch @@ -95,7 +95,7 @@ class _MessageViewState extends State { _sendMessageHelper(); } - void _sendInvitation([String ignoredParam]) { + void _sendInvitation([String? ignoredParam]) { Provider.of(context, listen: false) .cwtch .SendInvitation(Provider.of(context, listen: false).profileOnion, Provider.of(context, listen: false).onion, this.selectedContact); @@ -167,7 +167,7 @@ class _MessageViewState extends State { mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - Text(AppLocalizations.of(bcontext).invitationLabel), + Text(AppLocalizations.of(bcontext)!.invitationLabel), SizedBox( height: 20, ), @@ -182,7 +182,7 @@ class _MessageViewState extends State { height: 20, ), ElevatedButton( - child: Text(AppLocalizations.of(bcontext).inviteBtn, semanticsLabel: AppLocalizations.of(bcontext).inviteBtn), + child: Text(AppLocalizations.of(bcontext)!.inviteBtn, semanticsLabel: AppLocalizations.of(bcontext)!.inviteBtn), onPressed: () { this._sendInvitation(); Navigator.pop(bcontext); diff --git a/lib/views/peersettingsview.dart b/lib/views/peersettingsview.dart index bda425c..0630ec1 100644 --- a/lib/views/peersettingsview.dart +++ b/lib/views/peersettingsview.dart @@ -59,7 +59,7 @@ class _PeerSettingsViewState extends State { padding: EdgeInsets.all(2), child: 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( height: 20, ), @@ -78,7 +78,7 @@ class _PeerSettingsViewState extends State { Provider.of(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); }, icon: Icon(Icons.save), - tooltip: AppLocalizations.of(context).saveBtn, + tooltip: AppLocalizations.of(context)!.saveBtn, ) ]), @@ -87,7 +87,7 @@ class _PeerSettingsViewState extends State { SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).addressLabel), + CwtchLabel(label: AppLocalizations.of(context)!.addressLabel), SizedBox( height: 20, ), @@ -95,19 +95,19 @@ class _PeerSettingsViewState extends State { controller: TextEditingController(text: Provider.of(context, listen: false).onion), onPressed: _copyOnion, icon: Icon(Icons.copy), - tooltip: AppLocalizations.of(context).copyBtn, + tooltip: AppLocalizations.of(context)!.copyBtn, ) ]), Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 20, ), - CwtchLabel(label: AppLocalizations.of(context).conversationSettings), + CwtchLabel(label: AppLocalizations.of(context)!.conversationSettings), SizedBox( height: 20, ), SwitchListTile( - title: Text(AppLocalizations.of(context).blockBtn, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor())), value: Provider.of(context).isBlocked, onChanged: (bool blocked) { // Save local blocked status @@ -138,15 +138,15 @@ class _PeerSettingsViewState extends State { secondary: Icon(Icons.block, color: settings.current().mainTextColor()), ), ListTile( - title: Text(AppLocalizations.of(context).savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())), - subtitle: Text(AppLocalizations.of(context).savePeerHistoryDescription), + title: Text(AppLocalizations.of(context)!.savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())), + subtitle: Text(AppLocalizations.of(context)!.savePeerHistoryDescription), leading: Icon(Icons.history_sharp, color: settings.current().mainTextColor()), trailing: DropdownButton( value: Provider.of(context).savePeerHistory == "DefaultDeleteHistory" - ? AppLocalizations.of(context).dontSavePeerHistory + ? AppLocalizations.of(context)!.dontSavePeerHistory : (Provider.of(context).savePeerHistory == "SaveHistory" - ? AppLocalizations.of(context).savePeerHistory - : AppLocalizations.of(context).dontSavePeerHistory), + ? AppLocalizations.of(context)!.savePeerHistory + : AppLocalizations.of(context)!.dontSavePeerHistory), onChanged: (newValue) { setState(() { // Set whether or not to dave the Contact History... @@ -154,7 +154,7 @@ class _PeerSettingsViewState extends State { var onion = Provider.of(context, listen: false).onion; const SaveHistoryKey = "SavePeerHistory"; - if (newValue == AppLocalizations.of(context).savePeerHistory) { + if (newValue == AppLocalizations.of(context)!.savePeerHistory) { Provider.of(context, listen: false).savePeerHistory = "SaveHistory"; final setPeerAttribute = { "EventType": "SetPeerAttribute", @@ -174,7 +174,7 @@ class _PeerSettingsViewState extends State { } }); }, - items: [AppLocalizations.of(context).savePeerHistory, AppLocalizations.of(context).dontSavePeerHistory].map>((String value) { + items: [AppLocalizations.of(context)!.savePeerHistory, AppLocalizations.of(context)!.dontSavePeerHistory].map>((String value) { return DropdownMenuItem( value: value, child: Text(value), @@ -188,7 +188,7 @@ class _PeerSettingsViewState extends State { void _copyOnion() { Clipboard.setData(new ClipboardData(text: Provider.of(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); } } diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index e1b826c..0abcc29 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -39,24 +39,24 @@ class _ProfileMgrViewState extends State { child: Scaffold( backgroundColor: Provider.of(context).theme.backgroundMainColor(), appBar: AppBar( - title: Text(AppLocalizations.of(context).titleManageProfiles), + title: Text(AppLocalizations.of(context)!.titleManageProfiles), actions: [ IconButton(icon: TorIcon(), onPressed: _pushTorStatus), IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug), IconButton( icon: Icon(Icons.lock_open), - tooltip: AppLocalizations.of(context).tooltipUnlockProfiles, + tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles, 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( onPressed: _pushAddEditProfile, - tooltip: AppLocalizations.of(context).addNewProfileBtn, + tooltip: AppLocalizations.of(context)!.addNewProfileBtn, child: Icon( Icons.add, - semanticLabel: AppLocalizations.of(context).addNewProfileBtn, + semanticLabel: AppLocalizations.of(context)!.addNewProfileBtn, ), ), body: _buildProfileManager(), //_buildSuggestions(), @@ -122,12 +122,13 @@ class _ProfileMgrViewState extends State { mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - Text(AppLocalizations.of(context).enterProfilePassword), + Text(AppLocalizations.of(context)!.enterProfilePassword), SizedBox( height: 20, ), CwtchPasswordField( controller: ctrlrPassword, + validator: (value) {}, ), SizedBox( height: 20, @@ -136,7 +137,7 @@ class _ProfileMgrViewState extends State { Spacer(), Expanded( 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: () { Provider.of(context, listen: false).cwtch.LoadProfiles(ctrlrPassword.value.text); ctrlrPassword.text = ""; diff --git a/lib/views/torstatusview.dart b/lib/views/torstatusview.dart index b0b128e..41a7ce1 100644 --- a/lib/views/torstatusview.dart +++ b/lib/views/torstatusview.dart @@ -44,7 +44,7 @@ class _TorStatusView extends State { ListTile( leading: TorIcon(), 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( child: Text("Reset"), onPressed: () { diff --git a/lib/widgets/DropdownContacts.dart b/lib/widgets/DropdownContacts.dart index 5a8d80a..ae65c06 100644 --- a/lib/widgets/DropdownContacts.dart +++ b/lib/widgets/DropdownContacts.dart @@ -9,7 +9,7 @@ import '../model.dart'; // Pass an onChanged handler to access value class DropdownContacts extends StatefulWidget { DropdownContacts({ - this.onChanged, + required this.onChanged, }); final Function(dynamic) onChanged; @@ -18,18 +18,18 @@ class DropdownContacts extends StatefulWidget { } class _DropdownContactsState extends State { - String selected; + late String selected; @override Widget build(BuildContext context) { return DropdownButton( value: this.selected, items: Provider.of(context, listen: false).contactList.contacts.map>((ContactInfoState contact) { - return DropdownMenuItem(value: contact.onion, child: Text(contact.nickname ?? contact.onion)); + return DropdownMenuItem(value: contact.onion, child: Text(contact.nickname)); }).toList(), onChanged: (newVal) { setState(() { - this.selected = newVal; + this.selected = newVal.toString(); }); if (widget.onChanged != null) { widget.onChanged(newVal); diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index 5d07c67..afeb050 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -5,9 +5,9 @@ import 'package:provider/provider.dart'; // Provides a styled Text Field for use in Form Widgets. // Callers must provide a text controller, label helper text and a validator. class CwtchButtonTextField extends StatefulWidget { - CwtchButtonTextField({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 Function onPressed; + final Function()? onPressed; final Icon icon; final String tooltip; final bool readonly; diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index 345e222..ce163b2 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -123,7 +123,7 @@ class _ContactRowState extends State { String dateToNiceString(DateTime date) { 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 (DateTime.now().difference(date).inDays > 1) { diff --git a/lib/widgets/cwtchlabel.dart b/lib/widgets/cwtchlabel.dart index a2e062d..324067c 100644 --- a/lib/widgets/cwtchlabel.dart +++ b/lib/widgets/cwtchlabel.dart @@ -6,7 +6,7 @@ import '../settings.dart'; // Callers must provide a label text // TODO: Integrate this with a settings "zoom" / accessibility setting class CwtchLabel extends StatefulWidget { - CwtchLabel({this.label}); + CwtchLabel({required this.label}); final String label; @override diff --git a/lib/widgets/invitationbubble.dart b/lib/widgets/invitationbubble.dart index 8f52d0b..669b68f 100644 --- a/lib/widgets/invitationbubble.dart +++ b/lib/widgets/invitationbubble.dart @@ -37,11 +37,7 @@ class InvitationBubbleState extends State { var senderDisplayStr = ""; if (Provider.of(context).senderOnion != null) { var contact = Provider.of(context).contactList.getContact(Provider.of(context).senderOnion); - if (contact == null) { - senderDisplayStr = Provider.of(context).senderOnion; - } else { - senderDisplayStr = contact.nickname ?? contact.onion; - } + senderDisplayStr = contact.nickname; } var wdgSender = Center( widthFactor: 1, diff --git a/lib/widgets/messagebubble.dart b/lib/widgets/messagebubble.dart index a69b70c..96c8143 100644 --- a/lib/widgets/messagebubble.dart +++ b/lib/widgets/messagebubble.dart @@ -31,7 +31,7 @@ class MessageBubbleState extends State { if (contact == null) { senderDisplayStr = Provider.of(context).senderOnion; } else { - senderDisplayStr = contact.nickname ?? contact.onion; + senderDisplayStr = contact.nickname; } } var wdgSender = SelectableText(senderDisplayStr, diff --git a/lib/widgets/messagerow.dart b/lib/widgets/messagerow.dart index 833d809..764ad5a 100644 --- a/lib/widgets/messagerow.dart +++ b/lib/widgets/messagerow.dart @@ -14,7 +14,7 @@ import 'messagebubble.dart'; import 'messageloadingbubble.dart'; class MessageRow extends StatefulWidget { - MessageRow({Key key}) : super(key: key); + MessageRow({Key? key}) : super(key: key); @override _MessageRowState createState() => _MessageRowState(); @@ -52,10 +52,12 @@ class _MessageRowState extends State { child: Padding( padding: EdgeInsets.all(4.0), child: ProfileImage( - diameter: 48.0, - imagePath: Provider.of(context).senderImage ?? contact.imagePath, - //maskOut: contact.status != "Authenticated", - border: contact.status == "Authenticated" ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()))); + diameter: 48.0, + imagePath: Provider.of(context).senderImage ?? contact.imagePath, + //maskOut: contact.status != "Authenticated", + border: contact.status == "Authenticated" ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), + badgeTextColor: Colors.red, badgeColor: Colors.red, + ))); widgetRow = [ wdgPortrait, @@ -76,7 +78,7 @@ class _MessageRowState extends State { case 101: return InvitationBubble(); } - return null; + return MalformedBubble(); } void _btnAdd() { @@ -94,7 +96,7 @@ class _MessageRowState extends State { final setPeerAttributeJson = jsonEncode(setPeerAttribute); Provider.of(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); } } diff --git a/lib/widgets/passwordfield.dart b/lib/widgets/passwordfield.dart index 054227d..9b384a6 100644 --- a/lib/widgets/passwordfield.dart +++ b/lib/widgets/passwordfield.dart @@ -5,7 +5,7 @@ import '../settings.dart'; // Provides a styled Password Input Field for use in Form Widgets. // Callers must provide a text controller, label helper text and a validator. class CwtchPasswordField extends StatefulWidget { - CwtchPasswordField({this.controller, this.validator}); + CwtchPasswordField({required this.controller, required this.validator}); final TextEditingController controller; final FormFieldValidator validator; diff --git a/lib/widgets/profileimage.dart b/lib/widgets/profileimage.dart index e6d505b..3ed1a4b 100644 --- a/lib/widgets/profileimage.dart +++ b/lib/widgets/profileimage.dart @@ -5,7 +5,7 @@ import 'package:provider/provider.dart'; import '../settings.dart'; 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 String imagePath; final Color border; diff --git a/lib/widgets/profilerow.dart b/lib/widgets/profilerow.dart index 3abc598..b752feb 100644 --- a/lib/widgets/profilerow.dart +++ b/lib/widgets/profilerow.dart @@ -55,7 +55,7 @@ class _ProfileRowState extends State { )), IconButton( enableFeedback: true, - tooltip: AppLocalizations.of(context).editProfile + " " + profile.nickname, + tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname, icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor()), onPressed: () { _pushAddEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath); diff --git a/lib/widgets/textfield.dart b/lib/widgets/textfield.dart index d74b4ad..369c0d1 100644 --- a/lib/widgets/textfield.dart +++ b/lib/widgets/textfield.dart @@ -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({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 String labelText; final FormFieldValidator validator; diff --git a/lib/widgets/tor_icon.dart b/lib/widgets/tor_icon.dart index 2fb657f..b86d6e1 100644 --- a/lib/widgets/tor_icon.dart +++ b/lib/widgets/tor_icon.dart @@ -23,8 +23,8 @@ class _TorIconState extends State { color: Provider.of(context).theme.mainTextColor(), colorBlendMode: BlendMode.srcIn, semanticLabel: Provider.of(context).progress == 100 - ? AppLocalizations.of(context).networkStatusOnline - : (Provider.of(context).progress == 0 ? AppLocalizations.of(context).networkStatusDisconnected : AppLocalizations.of(context).networkStatusAttemptingTor), + ? AppLocalizations.of(context)!.networkStatusOnline + : (Provider.of(context).progress == 0 ? AppLocalizations.of(context)!.networkStatusDisconnected : AppLocalizations.of(context)!.networkStatusAttemptingTor), ); } } diff --git a/lib/widgets/torstatuslabel.dart b/lib/widgets/torstatuslabel.dart index a89d28d..92c14fb 100644 --- a/lib/widgets/torstatuslabel.dart +++ b/lib/widgets/torstatuslabel.dart @@ -18,7 +18,7 @@ class _TorStatusState extends State { stream: Provider.of(context).appStatus.torStatus(), builder: (BuildContext context, AsyncSnapshot snapshot) { return Text( - snapshot.hasData ? snapshot.data : AppLocalizations.of(context).loadingTor, + snapshot.hasData ? snapshot.data! : AppLocalizations.of(context)!.loadingTor, style: Theme.of(context).textTheme.headline4, ); }, diff --git a/pubspec.lock b/pubspec.lock index 8c01490..54950a0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -63,7 +63,7 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" fake_async: dependency: transitive description: @@ -84,7 +84,7 @@ packages: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.1.1" flutter: dependency: "direct main" description: flutter @@ -128,7 +128,7 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.1" + version: "0.13.3" http_parser: dependency: transitive description: @@ -184,42 +184,42 @@ packages: name: package_info_plus url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" package_info_plus_linux: dependency: transitive description: name: package_info_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.2" package_info_plus_macos: dependency: transitive description: name: package_info_plus_macos url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" package_info_plus_web: dependency: transitive description: name: package_info_plus_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" package_info_plus_windows: dependency: transitive description: name: package_info_plus_windows url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" path: dependency: transitive description: @@ -261,7 +261,7 @@ packages: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" pedantic: dependency: transitive description: @@ -296,7 +296,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "4.3.2+3" + version: "5.0.0" sky_engine: dependency: transitive description: flutter @@ -385,7 +385,7 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.1.1" xdg_directories: dependency: transitive description: @@ -394,5 +394,5 @@ packages: source: hosted version: "0.2.0" sdks: - dart: ">=2.12.0 <3.0.0" + dart: ">=2.13.0 <3.0.0" flutter: ">=1.20.0" diff --git a/pubspec.yaml b/pubspec.yaml index 192376a..7b71879 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,12 +18,12 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: sdk: flutter - provider: "4.3.2+3" + provider: 5.0.0 package_info_plus: ^1.0.0 #intl_translation: any flutter_localizations: