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);
// ignore: non_constant_identifier_names
Future<String> ACNEvents();
Future<dynamic> ACNEvents();
// ignore: non_constant_identifier_names
Future<String> ContactEvents();
Future<dynamic> ContactEvents();
// ignore: non_constant_identifier_names
Future<String> GetProfiles();
Future<dynamic> GetProfiles();
// ignore: non_constant_identifier_names
Future<int> NumMessages(String profile, String handle);
Future<dynamic> NumMessages(String profile, String handle);
// 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
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
void SendMessage(String profile, String handle, String message);
// 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)
// 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<MessageState>(key.currentContext, listen: false);
var message = Provider.of<MessageState>(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<MessageState>(key.currentContext, listen: false);
var message = Provider.of<MessageState>(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<MessageState>(key.currentContext, listen: false);
var message = Provider.of<MessageState>(key.currentContext!, listen: false);
if (message == null) break;
message.error = true;
} catch (e) {

View File

@ -56,9 +56,9 @@ typedef acn_events_function = Pointer<Utf8> Function();
typedef ACNEventsFn = Pointer<Utf8> 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<String, String> 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<String> pollAppbusEvents() async* {
DynamicLibrary library;
late DynamicLibrary library;
if (Platform.isWindows) {
library = DynamicLibrary.open("libCwtch.dll");
} else if (Platform.isLinux) {

View File

@ -26,9 +26,9 @@ class CwtchGomobile implements Cwtch {
final appbusEventChannelName = 'test.flutter.dev/eventBus';
Future<String> androidLibraryDir;
Future<Directory> androidHomeDirectory;
CwtchNotifier cwtchNotifier;
late Future<dynamic> androidLibraryDir;
late Future<dynamic> 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<String> ACNEvents() {
Future<dynamic> ACNEvents() {
return cwtchPlatform.invokeMethod("ACNEvents");
}
// ignore: non_constant_identifier_names
Future<String> ContactEvents() {
Future<dynamic> ContactEvents() {
return cwtchPlatform.invokeMethod("ContactEvents");
}
// ignore: non_constant_identifier_names
Future<String> GetProfiles() {
Future<dynamic> GetProfiles() {
print("gomobile.dart: GetProfiles()");
return cwtchPlatform.invokeMethod("GetProfiles");
}
// 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});
}
// 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());
return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "index": index});
}
// 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});
}

View File

@ -35,14 +35,14 @@ class Flwtch extends StatefulWidget {
class FlwtchState extends State<Flwtch> {
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() {

View File

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

View File

@ -14,33 +14,11 @@ import 'main.dart';
/// 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 {
final int o;
final String d;
ChatMessage({this.o, this.d});
ChatMessage({required this.o, required this.d});
ChatMessage.fromJson(Map<String, dynamic> 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<ContactInfoState> _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<String, GlobalKey> 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<String, GlobalKey<MessageBubbleState>> 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<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) {
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<MessageBubbleState>();
}
return keys[index];
GlobalKey<MessageBubbleState> 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<String> contactEvents() async* {
while (true) {

View File

@ -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<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 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();
}
static OpaqueThemeType _current;
static late OpaqueThemeType _current;
static final OpaqueThemeType dark = CwtchDark();
static final OpaqueThemeType light = CwtchLight();
static void setDark() {

View File

@ -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<String, bool> experiments = HashMap.identity();
bool blockUnknownConnections;
late bool blockUnknownConnections;
/// Set the dark theme.
void setDark() {

View File

@ -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) {

View File

@ -36,7 +36,7 @@ class _AddContactViewState extends State<AddContactView> {
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<AddContactView> {
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
/// 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 DefaultTabController(
length: groupsEnabled ? 4 : 1,
@ -62,7 +62,7 @@ class _AddContactViewState extends State<AddContactView> {
void _copyOnion() {
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);
}
@ -72,7 +72,7 @@ class _AddContactViewState extends State<AddContactView> {
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<AddContactView> {
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<AddContactView> {
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<AddContactView> {
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<AddContactView> {
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<AddContactView> {
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<AddContactView> {
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<ProfileInfoState>(context).serverList.servers.map<DropdownMenuItem<String>>((ServerInfoState serverInfo) {
@ -194,17 +195,22 @@ class _AddContactViewState extends State<AddContactView> {
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<AddContactView> {
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<AddContactView> {
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<AddContactView> {
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: '',
)
])));
}

View File

@ -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<AddEditProfileView> {
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<AddEditProfileView> {
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
return Scaffold(
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(),
);
}
void _handleSwitchPassword(bool value) {
void _handleSwitchPassword(bool? value) {
setState(() {
usePassword = value;
usePassword = value!;
});
}
@ -88,16 +88,18 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
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<AddEditProfileView> {
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<AddEditProfileView> {
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<AddEditProfileView> {
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<AddEditProfileView> {
Visibility(
visible: Provider.of<ProfileInfoState>(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<AddEditProfileView> {
validator: (value) {
// 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) {
return AppLocalizations.of(context).passwordErrorEmpty;
return AppLocalizations.of(context)!.passwordErrorEmpty;
}
return null;
},
@ -163,7 +165,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
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<AddEditProfileView> {
validator: (value) {
// 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) {
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<AddEditProfileView> {
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<AddEditProfileView> {
validator: (value) {
// 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) {
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<AddEditProfileView> {
child: ElevatedButton(
onPressed: _createPressed,
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,
),
),
@ -225,7 +227,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
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<AddEditProfileView> {
},
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<AddEditProfileView> {
// 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<ProfileInfoState>(context, listen: false).onion.isEmpty) {
if (usePassword == true) {
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()),
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,

View File

@ -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<ContactsView> {
TextEditingController ctrlrFilter;
late TextEditingController ctrlrFilter;
bool showSearchBar = false;
@override
@ -37,13 +37,15 @@ class _ContactsViewState extends State<ContactsView> {
imagePath: Provider.of<ProfileInfoState>(context).imagePath,
diameter: 42,
border: Provider.of<Settings>(context).theme.portraitOnlineBorderColor(),
badgeTextColor: Colors.red,
badgeColor: Colors.red,
),
SizedBox(
width: 10,
),
Expanded(
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,
)), //todo
]),
@ -66,7 +68,7 @@ class _ContactsViewState extends State<ContactsView> {
),
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<ContactListState>(context).isFiltered ? _buildFilterable() : _buildContactList(),
@ -75,16 +77,18 @@ class _ContactsViewState extends State<ContactsView> {
Widget _buildFilterable() {
Widget txtfield = CwtchTextField(
controller: ctrlrFilter,
labelText: AppLocalizations.of(context).search,
onChanged: (newVal) {
Provider.of<ContactListState>(context, listen: false).filter = newVal;
});
controller: ctrlrFilter,
labelText: AppLocalizations.of(context)!.search,
onChanged: (newVal) {
Provider.of<ContactListState>(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<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());
});
final divided = ListTile.divideTiles(
@ -119,7 +123,7 @@ class _ContactsViewState extends State<ContactsView> {
}
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);
}

View File

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

View File

@ -24,7 +24,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
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<GlobalSettingsView> {
),
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<Settings>(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<GlobalSettingsView> {
);
}).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<GlobalSettingsView> {
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<FlwtchState>(context).columns = [1, 2];
} else if (newValue == "Double (1:4)") {
@ -95,8 +95,8 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
);
}).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<GlobalSettingsView> {
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<GlobalSettingsView> {
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<GlobalSettingsView> {
height: 128,
)),
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',
),
]))));
@ -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;
}

View File

@ -42,7 +42,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
Widget build(BuildContext context) {
return Scaffold(
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(),
);
@ -68,24 +68,28 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
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<ContactInfoState>(context, listen: false).server),
validator: (value) {},
labelText: '',
)
]),
// Nickname Save Button
@ -93,7 +97,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
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<GroupSettingsView> {
Provider.of<FlwtchState>(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<GroupSettingsView> {
void _copyOnion() {
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);
}
}

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);
Provider.of<FlwtchState>(context, listen: false)
.cwtch
@ -95,7 +95,7 @@ class _MessageViewState extends State<MessageView> {
_sendMessageHelper();
}
void _sendInvitation([String ignoredParam]) {
void _sendInvitation([String? ignoredParam]) {
Provider.of<FlwtchState>(context, listen: false)
.cwtch
.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,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(AppLocalizations.of(bcontext).invitationLabel),
Text(AppLocalizations.of(bcontext)!.invitationLabel),
SizedBox(
height: 20,
),
@ -182,7 +182,7 @@ class _MessageViewState extends State<MessageView> {
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);

View File

@ -59,7 +59,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
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<PeerSettingsView> {
Provider.of<FlwtchState>(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<PeerSettingsView> {
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<PeerSettingsView> {
controller: TextEditingController(text: Provider.of<ContactInfoState>(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<ContactInfoState>(context).isBlocked,
onChanged: (bool blocked) {
// Save local blocked status
@ -138,15 +138,15 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
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<ContactInfoState>(context).savePeerHistory == "DefaultDeleteHistory"
? AppLocalizations.of(context).dontSavePeerHistory
? AppLocalizations.of(context)!.dontSavePeerHistory
: (Provider.of<ContactInfoState>(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<PeerSettingsView> {
var onion = Provider.of<ContactInfoState>(context, listen: false).onion;
const SaveHistoryKey = "SavePeerHistory";
if (newValue == AppLocalizations.of(context).savePeerHistory) {
if (newValue == AppLocalizations.of(context)!.savePeerHistory) {
Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = "SaveHistory";
final 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>(
value: value,
child: Text(value),
@ -188,7 +188,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
void _copyOnion() {
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);
}
}

View File

@ -39,24 +39,24 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
child: Scaffold(
backgroundColor: Provider.of<Settings>(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<ProfileMgrView> {
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
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<ProfileMgrView> {
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<FlwtchState>(context, listen: false).cwtch.LoadProfiles(ctrlrPassword.value.text);
ctrlrPassword.text = "";

View File

@ -44,7 +44,7 @@ class _TorStatusView extends State<TorStatusView> {
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: () {

View File

@ -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<DropdownContacts> {
String selected;
late String selected;
@override
Widget build(BuildContext context) {
return DropdownButton(
value: this.selected,
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(),
onChanged: (newVal) {
setState(() {
this.selected = newVal;
this.selected = newVal.toString();
});
if (widget.onChanged != null) {
widget.onChanged(newVal);

View File

@ -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;

View File

@ -123,7 +123,7 @@ class _ContactRowState extends State<ContactRow> {
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) {

View File

@ -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

View File

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

View File

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

View File

@ -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<MessageRow> {
child: Padding(
padding: EdgeInsets.all(4.0),
child: ProfileImage(
diameter: 48.0,
imagePath: Provider.of<MessageState>(context).senderImage ?? contact.imagePath,
//maskOut: contact.status != "Authenticated",
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor())));
diameter: 48.0,
imagePath: Provider.of<MessageState>(context).senderImage ?? contact.imagePath,
//maskOut: contact.status != "Authenticated",
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor(),
badgeTextColor: Colors.red, badgeColor: Colors.red,
)));
widgetRow = <Widget>[
wdgPortrait,
@ -76,7 +78,7 @@ class _MessageRowState extends State<MessageRow> {
case 101:
return InvitationBubble();
}
return null;
return MalformedBubble();
}
void _btnAdd() {
@ -94,7 +96,7 @@ class _MessageRowState extends State<MessageRow> {
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).successfullAddedContact));
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact));
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.
// 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;

View File

@ -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;

View File

@ -55,7 +55,7 @@ class _ProfileRowState extends State<ProfileRow> {
)),
IconButton(
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()),
onPressed: () {
_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.
// 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;

View File

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

View File

@ -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"

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
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: