Upgrade to null safe sdk
This commit is contained in:
parent
0baa2b707f
commit
2394a1daaa
|
@ -26,19 +26,19 @@ abstract class Cwtch {
|
||||||
void DebugResetContact(String profileOnion, String contactHandle);
|
void DebugResetContact(String profileOnion, String contactHandle);
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> ACNEvents();
|
Future<dynamic> ACNEvents();
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> ContactEvents();
|
Future<dynamic> ContactEvents();
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> GetProfiles();
|
Future<dynamic> GetProfiles();
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<int> NumMessages(String profile, String handle);
|
Future<dynamic> NumMessages(String profile, String handle);
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> GetMessage(String profile, String handle, int index);
|
Future<dynamic> GetMessage(String profile, String handle, int index);
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> GetMessages(String profile, String handle, int start, int end);
|
Future<dynamic> GetMessages(String profile, String handle, int start, int end);
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
void SendMessage(String profile, String handle, String message);
|
void SendMessage(String profile, String handle, String message);
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
|
|
|
@ -10,10 +10,10 @@ import '../settings.dart';
|
||||||
// Class that handles libcwtch-go events (received either via ffi with an isolate or gomobile over a method channel from kotlin)
|
// Class that handles libcwtch-go events (received either via ffi with an isolate or gomobile over a method channel from kotlin)
|
||||||
// Takes Notifiers and triggers them on appropriate events
|
// Takes Notifiers and triggers them on appropriate events
|
||||||
class CwtchNotifier {
|
class CwtchNotifier {
|
||||||
ProfileListState profileCN;
|
late ProfileListState profileCN;
|
||||||
Settings settings;
|
late Settings settings;
|
||||||
ErrorHandler error;
|
late ErrorHandler error;
|
||||||
TorStatus torStatus;
|
late TorStatus torStatus;
|
||||||
|
|
||||||
CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN) {
|
CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN) {
|
||||||
profileCN = pcn;
|
profileCN = pcn;
|
||||||
|
@ -74,7 +74,7 @@ class CwtchNotifier {
|
||||||
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["RemotePeer"]).getMessageKey(idx);
|
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["RemotePeer"]).getMessageKey(idx);
|
||||||
if (key == null) break;
|
if (key == null) break;
|
||||||
try {
|
try {
|
||||||
var message = Provider.of<MessageState>(key.currentContext, listen: false);
|
var message = Provider.of<MessageState>(key.currentContext!, listen: false);
|
||||||
if (message == null) break;
|
if (message == null) break;
|
||||||
message.ackd = true;
|
message.ackd = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -94,7 +94,7 @@ class CwtchNotifier {
|
||||||
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx);
|
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx);
|
||||||
if (key == null) break;
|
if (key == null) break;
|
||||||
try {
|
try {
|
||||||
var message = Provider.of<MessageState>(key.currentContext, listen: false);
|
var message = Provider.of<MessageState>(key.currentContext!, listen: false);
|
||||||
if (message == null) break;
|
if (message == null) break;
|
||||||
message.ackd = true;
|
message.ackd = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -109,7 +109,7 @@ class CwtchNotifier {
|
||||||
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx);
|
var key = profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).getMessageKey(idx);
|
||||||
if (key == null) break;
|
if (key == null) break;
|
||||||
try {
|
try {
|
||||||
var message = Provider.of<MessageState>(key.currentContext, listen: false);
|
var message = Provider.of<MessageState>(key.currentContext!, listen: false);
|
||||||
if (message == null) break;
|
if (message == null) break;
|
||||||
message.error = true;
|
message.error = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -56,9 +56,9 @@ typedef acn_events_function = Pointer<Utf8> Function();
|
||||||
typedef ACNEventsFn = Pointer<Utf8> Function();
|
typedef ACNEventsFn = Pointer<Utf8> Function();
|
||||||
|
|
||||||
class CwtchFfi implements Cwtch {
|
class CwtchFfi implements Cwtch {
|
||||||
DynamicLibrary library;
|
late DynamicLibrary library;
|
||||||
CwtchNotifier cwtchNotifier;
|
late CwtchNotifier cwtchNotifier;
|
||||||
Isolate cwtchIsolate;
|
late Isolate cwtchIsolate;
|
||||||
|
|
||||||
CwtchFfi(CwtchNotifier _cwtchNotifier) {
|
CwtchFfi(CwtchNotifier _cwtchNotifier) {
|
||||||
if (Platform.isWindows) {
|
if (Platform.isWindows) {
|
||||||
|
@ -79,9 +79,9 @@ class CwtchFfi implements Cwtch {
|
||||||
String bundledTor = "";
|
String bundledTor = "";
|
||||||
Map<String, String> envVars = Platform.environment;
|
Map<String, String> envVars = Platform.environment;
|
||||||
if (Platform.isLinux) {
|
if (Platform.isLinux) {
|
||||||
home = envVars['HOME'];
|
home = (envVars['HOME'])!;
|
||||||
} else if (Platform.isWindows) {
|
} else if (Platform.isWindows) {
|
||||||
home = envVars['UserProfile'];
|
home = (envVars['UserProfile'])!;
|
||||||
bundledTor = "Tor\\Tor\\tor.exe";
|
bundledTor = "Tor\\Tor\\tor.exe";
|
||||||
}
|
}
|
||||||
var cwtchDir = path.join(home, ".cwtch/dev/");
|
var cwtchDir = path.join(home, ".cwtch/dev/");
|
||||||
|
@ -121,7 +121,7 @@ class CwtchFfi implements Cwtch {
|
||||||
|
|
||||||
// Steam of appbus events. Call blocks in libcwtch-go GetAppbusEvent. Static so the isolate can use it
|
// Steam of appbus events. Call blocks in libcwtch-go GetAppbusEvent. Static so the isolate can use it
|
||||||
static Stream<String> pollAppbusEvents() async* {
|
static Stream<String> pollAppbusEvents() async* {
|
||||||
DynamicLibrary library;
|
late DynamicLibrary library;
|
||||||
if (Platform.isWindows) {
|
if (Platform.isWindows) {
|
||||||
library = DynamicLibrary.open("libCwtch.dll");
|
library = DynamicLibrary.open("libCwtch.dll");
|
||||||
} else if (Platform.isLinux) {
|
} else if (Platform.isLinux) {
|
||||||
|
|
|
@ -26,9 +26,9 @@ class CwtchGomobile implements Cwtch {
|
||||||
|
|
||||||
final appbusEventChannelName = 'test.flutter.dev/eventBus';
|
final appbusEventChannelName = 'test.flutter.dev/eventBus';
|
||||||
|
|
||||||
Future<String> androidLibraryDir;
|
late Future<dynamic> androidLibraryDir;
|
||||||
Future<Directory> androidHomeDirectory;
|
late Future<dynamic> androidHomeDirectory;
|
||||||
CwtchNotifier cwtchNotifier;
|
late CwtchNotifier cwtchNotifier;
|
||||||
|
|
||||||
CwtchGomobile(CwtchNotifier _cwtchNotifier) {
|
CwtchGomobile(CwtchNotifier _cwtchNotifier) {
|
||||||
print("gomobile.dart: CwtchGomobile()");
|
print("gomobile.dart: CwtchGomobile()");
|
||||||
|
@ -73,34 +73,34 @@ class CwtchGomobile implements Cwtch {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> ACNEvents() {
|
Future<dynamic> ACNEvents() {
|
||||||
return cwtchPlatform.invokeMethod("ACNEvents");
|
return cwtchPlatform.invokeMethod("ACNEvents");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> ContactEvents() {
|
Future<dynamic> ContactEvents() {
|
||||||
return cwtchPlatform.invokeMethod("ContactEvents");
|
return cwtchPlatform.invokeMethod("ContactEvents");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> GetProfiles() {
|
Future<dynamic> GetProfiles() {
|
||||||
print("gomobile.dart: GetProfiles()");
|
print("gomobile.dart: GetProfiles()");
|
||||||
return cwtchPlatform.invokeMethod("GetProfiles");
|
return cwtchPlatform.invokeMethod("GetProfiles");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<int> NumMessages(String profile, String handle) {
|
Future<dynamic> NumMessages(String profile, String handle) {
|
||||||
return cwtchPlatform.invokeMethod("NumMessages", {"profile": profile, "contact": handle});
|
return cwtchPlatform.invokeMethod("NumMessages", {"profile": profile, "contact": handle});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> GetMessage(String profile, String handle, int index) {
|
Future<dynamic> GetMessage(String profile, String handle, int index) {
|
||||||
print("gomobile.dart GetMessage " + index.toString());
|
print("gomobile.dart GetMessage " + index.toString());
|
||||||
return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "index": index});
|
return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "index": index});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
Future<String> GetMessages(String profile, String handle, int start, int end) {
|
Future<dynamic> GetMessages(String profile, String handle, int start, int end) {
|
||||||
return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "start": start, "end": end});
|
return cwtchPlatform.invokeMethod("GetMessage", {"profile": profile, "contact": handle, "start": start, "end": end});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,14 @@ class Flwtch extends StatefulWidget {
|
||||||
|
|
||||||
class FlwtchState extends State<Flwtch> {
|
class FlwtchState extends State<Flwtch> {
|
||||||
final TextStyle biggerFont = const TextStyle(fontSize: 18);
|
final TextStyle biggerFont = const TextStyle(fontSize: 18);
|
||||||
Cwtch cwtch;
|
late Cwtch cwtch;
|
||||||
bool cwtchInit = false;
|
bool cwtchInit = false;
|
||||||
ProfileInfoState selectedProfile;
|
late ProfileInfoState selectedProfile;
|
||||||
String selectedConversation = "";
|
String selectedConversation = "";
|
||||||
var columns = [1]; // default or 'single column' mode
|
var columns = [1]; // default or 'single column' mode
|
||||||
//var columns = [1, 1, 2];
|
//var columns = [1, 1, 2];
|
||||||
AppModel appStatus;
|
late AppModel appStatus;
|
||||||
ProfileListState profs;
|
late ProfileListState profs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
initState() {
|
initState() {
|
||||||
|
|
|
@ -63,6 +63,6 @@ class DiskAssetBundle extends CachingAssetBundle {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ByteData> load(String key) async {
|
Future<ByteData> load(String key) async {
|
||||||
return _cache[key];
|
return _cache[key]!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
125
lib/model.dart
125
lib/model.dart
|
@ -14,33 +14,11 @@ import 'main.dart';
|
||||||
/// UI State ///
|
/// UI State ///
|
||||||
////////////////////
|
////////////////////
|
||||||
|
|
||||||
//todo: delete
|
|
||||||
class ProfileModel {
|
|
||||||
String onion;
|
|
||||||
String nickname;
|
|
||||||
String creationDate;
|
|
||||||
String imagePath;
|
|
||||||
HashMap<String, ContactModel> contacts;
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo: delete
|
|
||||||
class ContactModel {
|
|
||||||
String onion;
|
|
||||||
String nickname;
|
|
||||||
bool isGroup;
|
|
||||||
bool isInvitation;
|
|
||||||
bool isBlocked;
|
|
||||||
String status;
|
|
||||||
String imagePath;
|
|
||||||
|
|
||||||
ContactModel({this.onion, this.nickname, this.status, this.isInvitation, this.isBlocked, this.imagePath});
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatMessage {
|
class ChatMessage {
|
||||||
final int o;
|
final int o;
|
||||||
final String d;
|
final String d;
|
||||||
|
|
||||||
ChatMessage({this.o, this.d});
|
ChatMessage({required this.o, required this.d});
|
||||||
|
|
||||||
ChatMessage.fromJson(Map<String, dynamic> json)
|
ChatMessage.fromJson(Map<String, dynamic> json)
|
||||||
: o = json['o'],
|
: o = json['o'],
|
||||||
|
@ -74,16 +52,16 @@ class ProfileListState extends ChangeNotifier {
|
||||||
|
|
||||||
ProfileInfoState getProfile(String onion) {
|
ProfileInfoState getProfile(String onion) {
|
||||||
int idx = _profiles.indexWhere((element) => element.onion == onion);
|
int idx = _profiles.indexWhere((element) => element.onion == onion);
|
||||||
return idx >= 0 ? _profiles[idx] : null;
|
return idx >= 0 ? _profiles[idx] : ProfileInfoState(onion: onion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContactListState extends ChangeNotifier {
|
class ContactListState extends ChangeNotifier {
|
||||||
List<ContactInfoState> _contacts = [];
|
List<ContactInfoState> _contacts = [];
|
||||||
String _filter;
|
String _filter = "";
|
||||||
int get num => _contacts.length;
|
int get num => _contacts.length;
|
||||||
int get numFiltered => isFiltered ? filteredList().length : num;
|
int get numFiltered => isFiltered ? filteredList().length : num;
|
||||||
bool get isFiltered => _filter != null && _filter != "";
|
bool get isFiltered => _filter != "";
|
||||||
String get filter => _filter;
|
String get filter => _filter;
|
||||||
set filter(String newVal) {
|
set filter(String newVal) {
|
||||||
_filter = newVal;
|
_filter = newVal;
|
||||||
|
@ -142,7 +120,7 @@ class ContactListState extends ChangeNotifier {
|
||||||
|
|
||||||
ContactInfoState getContact(String onion) {
|
ContactInfoState getContact(String onion) {
|
||||||
int idx = _contacts.indexWhere((element) => element.onion == onion);
|
int idx = _contacts.indexWhere((element) => element.onion == onion);
|
||||||
return idx >= 0 ? _contacts[idx] : null;
|
return idx >= 0 ? _contacts[idx] : ContactInfoState("not found", "not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +134,7 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
bool _online = false;
|
bool _online = false;
|
||||||
|
|
||||||
ProfileInfoState({
|
ProfileInfoState({
|
||||||
this.onion,
|
required this.onion,
|
||||||
nickname = "",
|
nickname = "",
|
||||||
imagePath = "",
|
imagePath = "",
|
||||||
unreadMessages = 0,
|
unreadMessages = 0,
|
||||||
|
@ -253,21 +231,21 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
class ContactInfoState extends ChangeNotifier {
|
class ContactInfoState extends ChangeNotifier {
|
||||||
final String profileOnion;
|
final String profileOnion;
|
||||||
final String onion;
|
final String onion;
|
||||||
String _nickname;
|
late String _nickname;
|
||||||
|
|
||||||
bool _isInvitation;
|
late bool _isInvitation;
|
||||||
bool _isBlocked;
|
late bool _isBlocked;
|
||||||
String _status;
|
late String _status;
|
||||||
String _imagePath;
|
late String _imagePath;
|
||||||
String _savePeerHistory;
|
late String _savePeerHistory;
|
||||||
int _unreadMessages = 0;
|
late int _unreadMessages = 0;
|
||||||
int _totalMessages = 0;
|
late int _totalMessages = 0;
|
||||||
DateTime _lastMessageTime;
|
late DateTime _lastMessageTime;
|
||||||
Map<String, GlobalKey> keys;
|
late Map<String, GlobalKey<MessageBubbleState>> keys;
|
||||||
|
|
||||||
// todo: a nicer way to model contacts, groups and other "entities"
|
// todo: a nicer way to model contacts, groups and other "entities"
|
||||||
bool _isGroup;
|
late bool _isGroup;
|
||||||
String _server;
|
late String _server;
|
||||||
|
|
||||||
ContactInfoState(
|
ContactInfoState(
|
||||||
this.profileOnion,
|
this.profileOnion,
|
||||||
|
@ -293,14 +271,14 @@ class ContactInfoState extends ChangeNotifier {
|
||||||
this._totalMessages = numMessages;
|
this._totalMessages = numMessages;
|
||||||
this._unreadMessages = numUnread;
|
this._unreadMessages = numUnread;
|
||||||
this._savePeerHistory = savePeerHistory;
|
this._savePeerHistory = savePeerHistory;
|
||||||
this._lastMessageTime = lastMessageTime;
|
this._lastMessageTime = lastMessageTime == null ? DateTime.fromMillisecondsSinceEpoch(0) : lastMessageTime;
|
||||||
this._server = server;
|
this._server = server;
|
||||||
keys = Map<String, GlobalKey>();
|
keys = Map<String, GlobalKey<MessageBubbleState>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
get nickname => this._nickname;
|
String get nickname => this._nickname;
|
||||||
|
|
||||||
get savePeerHistory => this._savePeerHistory;
|
String get savePeerHistory => this._savePeerHistory;
|
||||||
set savePeerHistory(String newVal) {
|
set savePeerHistory(String newVal) {
|
||||||
this._savePeerHistory = newVal;
|
this._savePeerHistory = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
@ -311,49 +289,49 @@ class ContactInfoState extends ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
get isGroup => this._isGroup;
|
bool get isGroup => this._isGroup;
|
||||||
set isGroup(bool newVal) {
|
set isGroup(bool newVal) {
|
||||||
this._isGroup = newVal;
|
this._isGroup = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
get isBlocked => this._isBlocked;
|
bool get isBlocked => this._isBlocked;
|
||||||
set isBlocked(bool newVal) {
|
set isBlocked(bool newVal) {
|
||||||
this._isBlocked = newVal;
|
this._isBlocked = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
get isInvitation => this._isInvitation;
|
bool get isInvitation => this._isInvitation;
|
||||||
set isInvitation(bool newVal) {
|
set isInvitation(bool newVal) {
|
||||||
this._isInvitation = newVal;
|
this._isInvitation = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
get status => this._status;
|
String get status => this._status;
|
||||||
set status(String newVal) {
|
set status(String newVal) {
|
||||||
this._status = newVal;
|
this._status = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
get unreadMessages => this._unreadMessages;
|
int get unreadMessages => this._unreadMessages;
|
||||||
set unreadMessages(int newVal) {
|
set unreadMessages(int newVal) {
|
||||||
this._unreadMessages = newVal;
|
this._unreadMessages = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
get totalMessages => this._totalMessages;
|
int get totalMessages => this._totalMessages;
|
||||||
set totalMessages(int newVal) {
|
set totalMessages(int newVal) {
|
||||||
this._totalMessages = newVal;
|
this._totalMessages = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
get imagePath => this._imagePath;
|
String get imagePath => this._imagePath;
|
||||||
set imagePath(String newVal) {
|
set imagePath(String newVal) {
|
||||||
this._imagePath = newVal;
|
this._imagePath = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
get lastMessageTime => this._lastMessageTime;
|
DateTime get lastMessageTime => this._lastMessageTime;
|
||||||
set lastMessageTime(DateTime newVal) {
|
set lastMessageTime(DateTime newVal) {
|
||||||
this._lastMessageTime = newVal;
|
this._lastMessageTime = newVal;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
@ -374,7 +352,8 @@ class ContactInfoState extends ChangeNotifier {
|
||||||
if (keys[index] == null) {
|
if (keys[index] == null) {
|
||||||
keys[index] = GlobalKey<MessageBubbleState>();
|
keys[index] = GlobalKey<MessageBubbleState>();
|
||||||
}
|
}
|
||||||
return keys[index];
|
GlobalKey<MessageBubbleState> ret = keys[index]!;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,24 +361,24 @@ class MessageState extends ChangeNotifier {
|
||||||
final String profileOnion;
|
final String profileOnion;
|
||||||
final String contactHandle;
|
final String contactHandle;
|
||||||
final int messageIndex;
|
final int messageIndex;
|
||||||
String _message;
|
late String _message;
|
||||||
int _overlay;
|
late int _overlay;
|
||||||
String _inviteTarget;
|
late String _inviteTarget;
|
||||||
String _inviteNick;
|
late String _inviteNick;
|
||||||
DateTime _timestamp;
|
late DateTime _timestamp;
|
||||||
String _senderOnion;
|
late String _senderOnion;
|
||||||
String _senderImage;
|
late String _senderImage;
|
||||||
String _signature = "";
|
late String _signature = "";
|
||||||
bool _ackd = false;
|
late bool _ackd = false;
|
||||||
bool _error = false;
|
late bool _error = false;
|
||||||
bool _loaded = false;
|
late bool _loaded = false;
|
||||||
bool _malformed = false;
|
late bool _malformed = false;
|
||||||
|
|
||||||
MessageState({
|
MessageState({
|
||||||
BuildContext context,
|
required BuildContext context,
|
||||||
this.profileOnion,
|
required this.profileOnion,
|
||||||
this.contactHandle,
|
required this.contactHandle,
|
||||||
this.messageIndex,
|
required this.messageIndex,
|
||||||
}) {
|
}) {
|
||||||
this._senderOnion = profileOnion;
|
this._senderOnion = profileOnion;
|
||||||
tryLoad(context);
|
tryLoad(context);
|
||||||
|
@ -408,8 +387,8 @@ class MessageState extends ChangeNotifier {
|
||||||
get message => this._message;
|
get message => this._message;
|
||||||
get overlay => this._overlay;
|
get overlay => this._overlay;
|
||||||
get timestamp => this._timestamp;
|
get timestamp => this._timestamp;
|
||||||
get ackd => this._ackd;
|
bool get ackd => this._ackd;
|
||||||
get error => this._error;
|
bool get error => this._error;
|
||||||
get malformed => this._malformed;
|
get malformed => this._malformed;
|
||||||
get senderOnion => this._senderOnion;
|
get senderOnion => this._senderOnion;
|
||||||
get senderImage => this._senderImage;
|
get senderImage => this._senderImage;
|
||||||
|
@ -444,7 +423,7 @@ class MessageState extends ChangeNotifier {
|
||||||
dynamic message = jsonDecode(messageWrapper['Message']);
|
dynamic message = jsonDecode(messageWrapper['Message']);
|
||||||
this._message = message['d'];
|
this._message = message['d'];
|
||||||
this._overlay = int.parse(message['o'].toString());
|
this._overlay = int.parse(message['o'].toString());
|
||||||
this._timestamp = DateTime.tryParse(messageWrapper['Timestamp']);
|
this._timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!;
|
||||||
this._senderOnion = messageWrapper['PeerID'];
|
this._senderOnion = messageWrapper['PeerID'];
|
||||||
this._senderImage = messageWrapper['ContactImage'];
|
this._senderImage = messageWrapper['ContactImage'];
|
||||||
|
|
||||||
|
@ -490,7 +469,7 @@ class MessageState extends ChangeNotifier {
|
||||||
|
|
||||||
class AppModel {
|
class AppModel {
|
||||||
final Cwtch cwtch;
|
final Cwtch cwtch;
|
||||||
AppModel({this.cwtch});
|
AppModel({required this.cwtch});
|
||||||
|
|
||||||
Stream<String> contactEvents() async* {
|
Stream<String> contactEvents() async* {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ class ServerListState extends ChangeNotifier {
|
||||||
|
|
||||||
ServerInfoState getServer(String onion) {
|
ServerInfoState getServer(String onion) {
|
||||||
int idx = _servers.indexWhere((element) => element.onion == onion);
|
int idx = _servers.indexWhere((element) => element.onion == onion);
|
||||||
return idx >= 0 ? _servers[idx] : null;
|
return idx >= 0 ? _servers[idx] : ServerInfoState(onion: "not found", status: "not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ServerInfoState> get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier
|
List<ServerInfoState> get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier
|
||||||
|
@ -22,5 +22,5 @@ class ServerInfoState extends ChangeNotifier {
|
||||||
final String onion;
|
final String onion;
|
||||||
final String status;
|
final String status;
|
||||||
|
|
||||||
ServerInfoState({this.onion, this.status});
|
ServerInfoState({required this.onion, required this.status});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1225,7 +1225,7 @@ class Opaque extends OpaqueThemeType {
|
||||||
return sidePaneMinSize() + chatPaneMinSize();
|
return sidePaneMinSize() + chatPaneMinSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static OpaqueThemeType _current;
|
static late OpaqueThemeType _current;
|
||||||
static final OpaqueThemeType dark = CwtchDark();
|
static final OpaqueThemeType dark = CwtchDark();
|
||||||
static final OpaqueThemeType light = CwtchLight();
|
static final OpaqueThemeType light = CwtchLight();
|
||||||
static void setDark() {
|
static void setDark() {
|
||||||
|
|
|
@ -14,12 +14,12 @@ const TapirGroupsExperiment = "tapir-groups-experiment";
|
||||||
/// Settings Pane.
|
/// Settings Pane.
|
||||||
class Settings extends ChangeNotifier {
|
class Settings extends ChangeNotifier {
|
||||||
Locale locale;
|
Locale locale;
|
||||||
PackageInfo packageInfo;
|
late PackageInfo packageInfo;
|
||||||
OpaqueThemeType theme;
|
OpaqueThemeType theme;
|
||||||
bool experimentsEnabled;
|
late bool experimentsEnabled;
|
||||||
HashMap<String, bool> experiments = HashMap.identity();
|
HashMap<String, bool> experiments = HashMap.identity();
|
||||||
|
|
||||||
bool blockUnknownConnections;
|
late bool blockUnknownConnections;
|
||||||
|
|
||||||
/// Set the dark theme.
|
/// Set the dark theme.
|
||||||
void setDark() {
|
void setDark() {
|
||||||
|
|
|
@ -5,6 +5,8 @@ class TorStatus extends ChangeNotifier {
|
||||||
String status;
|
String status;
|
||||||
bool connected;
|
bool connected;
|
||||||
|
|
||||||
|
TorStatus({this.connected = false, this.progress = 0, this.status = ""});
|
||||||
|
|
||||||
/// Called by the event bus.
|
/// Called by the event bus.
|
||||||
handleUpdate(int new_progress, String new_status) {
|
handleUpdate(int new_progress, String new_status) {
|
||||||
if (progress == 100) {
|
if (progress == 100) {
|
||||||
|
|
|
@ -36,7 +36,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context).titleManageContacts),
|
title: Text(AppLocalizations.of(context)!.titleManageContacts),
|
||||||
),
|
),
|
||||||
body: _buildForm(),
|
body: _buildForm(),
|
||||||
);
|
);
|
||||||
|
@ -46,7 +46,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
|
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
|
||||||
|
|
||||||
/// We display a different number of tabs dependening on the experiment setup
|
/// We display a different number of tabs dependening on the experiment setup
|
||||||
bool groupsEnabled = Provider.of<Settings>(context).experimentsEnabled && Provider.of<Settings>(context).experiments[TapirGroupsExperiment];
|
bool groupsEnabled = Provider.of<Settings>(context).experimentsEnabled && Provider.of<Settings>(context).experiments[TapirGroupsExperiment]!;
|
||||||
return Consumer<ErrorHandler>(builder: (context, globalErrorHandler, child) {
|
return Consumer<ErrorHandler>(builder: (context, globalErrorHandler, child) {
|
||||||
return DefaultTabController(
|
return DefaultTabController(
|
||||||
length: groupsEnabled ? 4 : 1,
|
length: groupsEnabled ? 4 : 1,
|
||||||
|
@ -62,7 +62,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
|
|
||||||
void _copyOnion() {
|
void _copyOnion() {
|
||||||
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
|
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
|
||||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification));
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedClipboardNotification));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(
|
Tab(
|
||||||
icon: Icon(Icons.person_add_rounded),
|
icon: Icon(Icons.person_add_rounded),
|
||||||
text: AppLocalizations.of(context).addPeer,
|
text: AppLocalizations.of(context)!.addPeer,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -84,11 +84,11 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(
|
Tab(
|
||||||
icon: Icon(Icons.person_add_rounded),
|
icon: Icon(Icons.person_add_rounded),
|
||||||
text: AppLocalizations.of(context).addPeer,
|
text: AppLocalizations.of(context)!.addPeer,
|
||||||
),
|
),
|
||||||
Tab(icon: Icon(Icons.backup), text: AppLocalizations.of(context).titleManageServers),
|
Tab(icon: Icon(Icons.backup), text: AppLocalizations.of(context)!.titleManageServers),
|
||||||
Tab(icon: Icon(Icons.group), text: AppLocalizations.of(context).createGroup),
|
Tab(icon: Icon(Icons.group), text: AppLocalizations.of(context)!.createGroup),
|
||||||
Tab(icon: Icon(Icons.group_add), text: AppLocalizations.of(context).joinGroup),
|
Tab(icon: Icon(Icons.group_add), text: AppLocalizations.of(context)!.joinGroup),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
autovalidateMode: AutovalidateMode.always,
|
autovalidateMode: AutovalidateMode.always,
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
CwtchLabel(label: AppLocalizations.of(context).profileOnionLabel),
|
CwtchLabel(label: AppLocalizations.of(context)!.profileOnionLabel),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -111,12 +111,12 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
controller: ctrlrOnion,
|
controller: ctrlrOnion,
|
||||||
onPressed: _copyOnion,
|
onPressed: _copyOnion,
|
||||||
icon: Icon(Icons.copy),
|
icon: Icon(Icons.copy),
|
||||||
tooltip: AppLocalizations.of(context).copyBtn,
|
tooltip: AppLocalizations.of(context)!.copyBtn,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).pasteAddressToAddContact),
|
CwtchLabel(label: AppLocalizations.of(context)!.pasteAddressToAddContact),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -127,9 +127,9 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (globalErrorHandler.invalidImportStringError) {
|
if (globalErrorHandler.invalidImportStringError) {
|
||||||
return AppLocalizations.of(context).invalidImportString;
|
return AppLocalizations.of(context)!.invalidImportString;
|
||||||
} else if (globalErrorHandler.contactAlreadyExistsError) {
|
} else if (globalErrorHandler.contactAlreadyExistsError) {
|
||||||
return AppLocalizations.of(context).contactAlreadyExists;
|
return AppLocalizations.of(context)!.contactAlreadyExists;
|
||||||
} else if (globalErrorHandler.explicitAddContactSuccess) {}
|
} else if (globalErrorHandler.explicitAddContactSuccess) {}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -144,12 +144,13 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
|
|
||||||
Future.delayed(const Duration(milliseconds: 500), () {
|
Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
if (globalErrorHandler.explicitAddContactSuccess) {
|
if (globalErrorHandler.explicitAddContactSuccess) {
|
||||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).successfullAddedContact + peerAddr));
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact + peerAddr));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
labelText: '',
|
||||||
)
|
)
|
||||||
])));
|
])));
|
||||||
}
|
}
|
||||||
|
@ -176,13 +177,13 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
CwtchLabel(label: AppLocalizations.of(context).server),
|
CwtchLabel(label: AppLocalizations.of(context)!.server),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
DropdownButton(
|
DropdownButton(
|
||||||
onChanged: (newServer) {
|
onChanged: (newServer) {
|
||||||
server = newServer;
|
server = newServer.toString();
|
||||||
},
|
},
|
||||||
value: server,
|
value: server,
|
||||||
items: Provider.of<ProfileInfoState>(context).serverList.servers.map<DropdownMenuItem<String>>((ServerInfoState serverInfo) {
|
items: Provider.of<ProfileInfoState>(context).serverList.servers.map<DropdownMenuItem<String>>((ServerInfoState serverInfo) {
|
||||||
|
@ -194,17 +195,22 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).groupName),
|
CwtchLabel(label: AppLocalizations.of(context)!.groupName),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchTextField(controller: ctrlrGroupName, labelText: AppLocalizations.of(context).groupNameLabel, onChanged: (newValue) {}),
|
CwtchTextField(
|
||||||
|
controller: ctrlrGroupName,
|
||||||
|
labelText: AppLocalizations.of(context)!.groupNameLabel,
|
||||||
|
onChanged: (newValue) {},
|
||||||
|
validator: (value) {},
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
child: Text(AppLocalizations.of(context).createGroupBtn),
|
child: Text(AppLocalizations.of(context)!.createGroupBtn),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)));
|
)));
|
||||||
|
@ -219,7 +225,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
autovalidateMode: AutovalidateMode.always,
|
autovalidateMode: AutovalidateMode.always,
|
||||||
key: _joinGroupFormKey,
|
key: _joinGroupFormKey,
|
||||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
CwtchLabel(label: AppLocalizations.of(context).joinGroupTab),
|
CwtchLabel(label: AppLocalizations.of(context)!.joinGroupTab),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -230,7 +236,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (globalErrorHandler.importBundleError) {
|
if (globalErrorHandler.importBundleError) {
|
||||||
return AppLocalizations.of(context).invalidImportString;
|
return AppLocalizations.of(context)!.invalidImportString;
|
||||||
} else if (globalErrorHandler.importBundleSuccess) {}
|
} else if (globalErrorHandler.importBundleSuccess) {}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -240,12 +246,13 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
|
|
||||||
Future.delayed(const Duration(milliseconds: 500), () {
|
Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
if (globalErrorHandler.importBundleSuccess) {
|
if (globalErrorHandler.importBundleSuccess) {
|
||||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).successfullAddedContact + importBundle));
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact + importBundle));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
labelText: '',
|
||||||
)
|
)
|
||||||
])));
|
])));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import '../opaque.dart';
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
|
|
||||||
class AddEditProfileView extends StatefulWidget {
|
class AddEditProfileView extends StatefulWidget {
|
||||||
const AddEditProfileView({Key key}) : super(key: key);
|
const AddEditProfileView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AddEditProfileViewState createState() => _AddEditProfileViewState();
|
_AddEditProfileViewState createState() => _AddEditProfileViewState();
|
||||||
|
@ -30,8 +30,8 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
final ctrlrPass = TextEditingController(text: "");
|
final ctrlrPass = TextEditingController(text: "");
|
||||||
final ctrlrPass2 = TextEditingController(text: "");
|
final ctrlrPass2 = TextEditingController(text: "");
|
||||||
final ctrlrOnion = TextEditingController(text: "");
|
final ctrlrOnion = TextEditingController(text: "");
|
||||||
bool usePassword;
|
late bool usePassword;
|
||||||
bool deleted;
|
late bool deleted;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -48,15 +48,15 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
|
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(Provider.of<ProfileInfoState>(context).onion.isEmpty ? AppLocalizations.of(context).addProfileTitle : AppLocalizations.of(context).editProfileTitle),
|
title: Text(Provider.of<ProfileInfoState>(context).onion.isEmpty ? AppLocalizations.of(context)!.addProfileTitle : AppLocalizations.of(context)!.editProfileTitle),
|
||||||
),
|
),
|
||||||
body: _buildForm(),
|
body: _buildForm(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleSwitchPassword(bool value) {
|
void _handleSwitchPassword(bool? value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
usePassword = value;
|
usePassword = value!;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,16 +88,18 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
diameter: 120,
|
diameter: 120,
|
||||||
maskOut: false,
|
maskOut: false,
|
||||||
border: theme.theme.portraitOnlineBorderColor(),
|
border: theme.theme.portraitOnlineBorderColor(),
|
||||||
|
badgeTextColor: Colors.red,
|
||||||
|
badgeColor: Colors.red,
|
||||||
)
|
)
|
||||||
])),
|
])),
|
||||||
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
CwtchLabel(label: AppLocalizations.of(context).displayNameLabel),
|
CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchTextField(
|
CwtchTextField(
|
||||||
controller: ctrlrNick,
|
controller: ctrlrNick,
|
||||||
labelText: AppLocalizations.of(context).yourDisplayName,
|
labelText: AppLocalizations.of(context)!.yourDisplayName,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value.isEmpty) {
|
if (value.isEmpty) {
|
||||||
return "Please enter a display name";
|
return "Please enter a display name";
|
||||||
|
@ -112,7 +114,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).addressLabel),
|
CwtchLabel(label: AppLocalizations.of(context)!.addressLabel),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -120,7 +122,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
controller: ctrlrOnion,
|
controller: ctrlrOnion,
|
||||||
onPressed: _copyOnion,
|
onPressed: _copyOnion,
|
||||||
icon: Icon(Icons.copy),
|
icon: Icon(Icons.copy),
|
||||||
tooltip: AppLocalizations.of(context).copyBtn,
|
tooltip: AppLocalizations.of(context)!.copyBtn,
|
||||||
)
|
)
|
||||||
])),
|
])),
|
||||||
// We only allow setting password types on profile creation
|
// We only allow setting password types on profile creation
|
||||||
|
@ -132,7 +134,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
onChanged: _handleSwitchPassword,
|
onChanged: _handleSwitchPassword,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context).radioUsePassword,
|
AppLocalizations.of(context)!.radioUsePassword,
|
||||||
style: TextStyle(color: theme.current().mainTextColor()),
|
style: TextStyle(color: theme.current().mainTextColor()),
|
||||||
),
|
),
|
||||||
])),
|
])),
|
||||||
|
@ -145,7 +147,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: Provider.of<ProfileInfoState>(context, listen: false).onion.isNotEmpty,
|
visible: Provider.of<ProfileInfoState>(context, listen: false).onion.isNotEmpty,
|
||||||
child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
CwtchLabel(label: AppLocalizations.of(context).currentPasswordLabel),
|
CwtchLabel(label: AppLocalizations.of(context)!.currentPasswordLabel),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -154,7 +156,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
// Password field can be empty when just updating the profile, not on creation
|
// Password field can be empty when just updating the profile, not on creation
|
||||||
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
|
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
|
||||||
return AppLocalizations.of(context).passwordErrorEmpty;
|
return AppLocalizations.of(context)!.passwordErrorEmpty;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -163,7 +165,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
])),
|
])),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).password1Label),
|
CwtchLabel(label: AppLocalizations.of(context)!.password1Label),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -172,10 +174,10 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
// Password field can be empty when just updating the profile, not on creation
|
// Password field can be empty when just updating the profile, not on creation
|
||||||
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
|
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
|
||||||
return AppLocalizations.of(context).passwordErrorEmpty;
|
return AppLocalizations.of(context)!.passwordErrorEmpty;
|
||||||
}
|
}
|
||||||
if (value != ctrlrPass2.value.text) {
|
if (value != ctrlrPass2.value.text) {
|
||||||
return AppLocalizations.of(context).passwordErrorMatch;
|
return AppLocalizations.of(context)!.passwordErrorMatch;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -183,7 +185,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).password2Label),
|
CwtchLabel(label: AppLocalizations.of(context)!.password2Label),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -192,10 +194,10 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
// Password field can be empty when just updating the profile, not on creation
|
// Password field can be empty when just updating the profile, not on creation
|
||||||
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
|
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) {
|
||||||
return AppLocalizations.of(context).passwordErrorEmpty;
|
return AppLocalizations.of(context)!.passwordErrorEmpty;
|
||||||
}
|
}
|
||||||
if (value != ctrlrPass.value.text) {
|
if (value != ctrlrPass.value.text) {
|
||||||
return AppLocalizations.of(context).passwordErrorMatch;
|
return AppLocalizations.of(context)!.passwordErrorMatch;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
|
@ -211,7 +213,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _createPressed,
|
onPressed: _createPressed,
|
||||||
child: Text(
|
child: Text(
|
||||||
Provider.of<ProfileInfoState>(context).onion.isEmpty ? AppLocalizations.of(context).addNewProfileBtn : AppLocalizations.of(context).saveProfileBtn,
|
Provider.of<ProfileInfoState>(context).onion.isEmpty ? AppLocalizations.of(context)!.addNewProfileBtn : AppLocalizations.of(context)!.saveProfileBtn,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -225,7 +227,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: AppLocalizations.of(context).enterCurrentPasswordForDelete,
|
message: AppLocalizations.of(context)!.enterCurrentPasswordForDelete,
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: checkCurrentPassword()
|
onPressed: checkCurrentPassword()
|
||||||
? null
|
? null
|
||||||
|
@ -234,7 +236,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(primary: theme.current().defaultButtonColor()),
|
style: ElevatedButton.styleFrom(primary: theme.current().defaultButtonColor()),
|
||||||
icon: Icon(Icons.delete_forever),
|
icon: Icon(Icons.delete_forever),
|
||||||
label: Text(AppLocalizations.of(context).deleteBtn),
|
label: Text(AppLocalizations.of(context)!.deleteBtn),
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
]))))));
|
]))))));
|
||||||
|
@ -251,7 +253,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
||||||
// This will run all the validations in the form including
|
// This will run all the validations in the form including
|
||||||
// checking that display name is not empty, and an actual check that the passwords
|
// checking that display name is not empty, and an actual check that the passwords
|
||||||
// match (and are provided if the user has requested an encrypted profile).
|
// match (and are provided if the user has requested an encrypted profile).
|
||||||
if (_formKey.currentState.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty) {
|
if (Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty) {
|
||||||
if (usePassword == true) {
|
if (usePassword == true) {
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, ctrlrPass.value.text);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, ctrlrPass.value.text);
|
||||||
|
@ -322,7 +324,7 @@ showAlertDialog(BuildContext context) {
|
||||||
foregroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonTextColor()),
|
foregroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonTextColor()),
|
||||||
overlayColor: MaterialStateProperty.all(Opaque.current().defaultButtonActiveColor()),
|
overlayColor: MaterialStateProperty.all(Opaque.current().defaultButtonActiveColor()),
|
||||||
padding: MaterialStateProperty.all(EdgeInsets.all(20))),
|
padding: MaterialStateProperty.all(EdgeInsets.all(20))),
|
||||||
child: Text(AppLocalizations.of(context).deleteProfileConfirmBtn),
|
child: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// TODO Actually Delete the Peer
|
// TODO Actually Delete the Peer
|
||||||
Navigator.of(context).pop(); // dismiss dialog
|
Navigator.of(context).pop(); // dismiss dialog
|
||||||
|
@ -331,7 +333,7 @@ showAlertDialog(BuildContext context) {
|
||||||
|
|
||||||
// set up the AlertDialog
|
// set up the AlertDialog
|
||||||
AlertDialog alert = AlertDialog(
|
AlertDialog alert = AlertDialog(
|
||||||
title: Text(AppLocalizations.of(context).deleteProfileConfirmBtn),
|
title: Text(AppLocalizations.of(context)!.deleteProfileConfirmBtn),
|
||||||
actions: [
|
actions: [
|
||||||
cancelButton,
|
cancelButton,
|
||||||
continueButton,
|
continueButton,
|
||||||
|
|
|
@ -12,14 +12,14 @@ import '../model.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
class ContactsView extends StatefulWidget {
|
class ContactsView extends StatefulWidget {
|
||||||
const ContactsView({Key key}) : super(key: key);
|
const ContactsView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ContactsViewState createState() => _ContactsViewState();
|
_ContactsViewState createState() => _ContactsViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ContactsViewState extends State<ContactsView> {
|
class _ContactsViewState extends State<ContactsView> {
|
||||||
TextEditingController ctrlrFilter;
|
late TextEditingController ctrlrFilter;
|
||||||
bool showSearchBar = false;
|
bool showSearchBar = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -37,13 +37,15 @@ class _ContactsViewState extends State<ContactsView> {
|
||||||
imagePath: Provider.of<ProfileInfoState>(context).imagePath,
|
imagePath: Provider.of<ProfileInfoState>(context).imagePath,
|
||||||
diameter: 42,
|
diameter: 42,
|
||||||
border: Provider.of<Settings>(context).theme.portraitOnlineBorderColor(),
|
border: Provider.of<Settings>(context).theme.portraitOnlineBorderColor(),
|
||||||
|
badgeTextColor: Colors.red,
|
||||||
|
badgeColor: Colors.red,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"%1 » %2".replaceAll("%1", Provider.of<ProfileInfoState>(context).nickname ?? Provider.of<ProfileInfoState>(context).onion ?? '').replaceAll("%2", "Contacts"),
|
"%1 » %2".replaceAll("%1", Provider.of<ProfileInfoState>(context).nickname).replaceAll("%2", "Contacts"),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
)), //todo
|
)), //todo
|
||||||
]),
|
]),
|
||||||
|
@ -66,7 +68,7 @@ class _ContactsViewState extends State<ContactsView> {
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: _pushAddContact,
|
onPressed: _pushAddContact,
|
||||||
tooltip: AppLocalizations.of(context).tooltipAddContact,
|
tooltip: AppLocalizations.of(context)!.tooltipAddContact,
|
||||||
child: const Icon(Icons.person_add_sharp),
|
child: const Icon(Icons.person_add_sharp),
|
||||||
),
|
),
|
||||||
body: showSearchBar || Provider.of<ContactListState>(context).isFiltered ? _buildFilterable() : _buildContactList(),
|
body: showSearchBar || Provider.of<ContactListState>(context).isFiltered ? _buildFilterable() : _buildContactList(),
|
||||||
|
@ -75,16 +77,18 @@ class _ContactsViewState extends State<ContactsView> {
|
||||||
|
|
||||||
Widget _buildFilterable() {
|
Widget _buildFilterable() {
|
||||||
Widget txtfield = CwtchTextField(
|
Widget txtfield = CwtchTextField(
|
||||||
controller: ctrlrFilter,
|
controller: ctrlrFilter,
|
||||||
labelText: AppLocalizations.of(context).search,
|
labelText: AppLocalizations.of(context)!.search,
|
||||||
onChanged: (newVal) {
|
onChanged: (newVal) {
|
||||||
Provider.of<ContactListState>(context, listen: false).filter = newVal;
|
Provider.of<ContactListState>(context, listen: false).filter = newVal;
|
||||||
});
|
},
|
||||||
|
validator: (value) {},
|
||||||
|
);
|
||||||
return Column(children: [Padding(padding: EdgeInsets.all(8), child: txtfield), Expanded(child: _buildContactList())]);
|
return Column(children: [Padding(padding: EdgeInsets.all(8), child: txtfield), Expanded(child: _buildContactList())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildContactList() {
|
Widget _buildContactList() {
|
||||||
final tiles = Provider.of<ContactListState>(context).filteredList().map((ContactInfoState contact) {
|
final tiles = Provider.of<ContactListState>(context).contacts.map((ContactInfoState contact) {
|
||||||
return ChangeNotifierProvider<ContactInfoState>.value(key: ValueKey(contact.profileOnion + "" + contact.onion), value: contact, builder: (_, __) => ContactRow());
|
return ChangeNotifierProvider<ContactInfoState>.value(key: ValueKey(contact.profileOnion + "" + contact.onion), value: contact, builder: (_, __) => ContactRow());
|
||||||
});
|
});
|
||||||
final divided = ListTile.divideTiles(
|
final divided = ListTile.divideTiles(
|
||||||
|
@ -119,7 +123,7 @@ class _ContactsViewState extends State<ContactsView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _copyOnion() {
|
void _copyOnion() {
|
||||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification)); //todo
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedClipboardNotification)); //todo
|
||||||
// Find the Scaffold in the widget tree and use it to show a SnackBar.
|
// Find the Scaffold in the widget tree and use it to show a SnackBar.
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@ class _DoubleColumnViewState extends State<DoubleColumnView> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Flexible(
|
Flexible(
|
||||||
flex: flwtch.columns[0],
|
flex: flwtch.columns[0],
|
||||||
child: ContactsView(),
|
child: ContactsView(
|
||||||
|
key: widget.key,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
flex: flwtch.columns[1],
|
flex: flwtch.columns[1],
|
||||||
|
|
|
@ -24,7 +24,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context).cwtchSettingsTitle),
|
title: Text(AppLocalizations.of(context)!.cwtchSettingsTitle),
|
||||||
),
|
),
|
||||||
body: _buildSettingsList(),
|
body: _buildSettingsList(),
|
||||||
);
|
);
|
||||||
|
@ -43,13 +43,13 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
),
|
),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(AppLocalizations.of(context).settingLanguage, style: TextStyle(color: settings.current().mainTextColor())),
|
title: Text(AppLocalizations.of(context)!.settingLanguage, style: TextStyle(color: settings.current().mainTextColor())),
|
||||||
leading: Icon(Icons.language, color: settings.current().mainTextColor()),
|
leading: Icon(Icons.language, color: settings.current().mainTextColor()),
|
||||||
trailing: DropdownButton(
|
trailing: DropdownButton(
|
||||||
value: Provider.of<Settings>(context).locale.languageCode,
|
value: Provider.of<Settings>(context).locale.languageCode,
|
||||||
onChanged: (String newValue) {
|
onChanged: (String? newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
settings.switchLocale(Locale(newValue, ''));
|
settings.switchLocale(Locale(newValue!, ''));
|
||||||
saveSettings(context);
|
saveSettings(context);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -60,7 +60,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
);
|
);
|
||||||
}).toList())),
|
}).toList())),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: Text(AppLocalizations.of(context).settingTheme, style: TextStyle(color: settings.current().mainTextColor())),
|
title: Text(AppLocalizations.of(context)!.settingTheme, style: TextStyle(color: settings.current().mainTextColor())),
|
||||||
value: settings.current() == Opaque.light,
|
value: settings.current() == Opaque.light,
|
||||||
onChanged: (bool value) {
|
onChanged: (bool value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -75,11 +75,11 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
secondary: Icon(Icons.lightbulb_outline, color: settings.current().mainTextColor()),
|
secondary: Icon(Icons.lightbulb_outline, color: settings.current().mainTextColor()),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(/*AppLocalizations.of(context).settingLanguage*/ "UI Columns", style: TextStyle(color: settings.current().mainTextColor())),
|
title: Text(/*AppLocalizations.of(context)!.settingLanguage*/ "UI Columns", style: TextStyle(color: settings.current().mainTextColor())),
|
||||||
leading: Icon(Icons.table_chart, color: settings.current().mainTextColor()),
|
leading: Icon(Icons.table_chart, color: settings.current().mainTextColor()),
|
||||||
trailing: DropdownButton(
|
trailing: DropdownButton(
|
||||||
value: "Single",
|
value: "Single",
|
||||||
onChanged: (String newValue) {
|
onChanged: (String? newValue) {
|
||||||
if (newValue == "Double (1:2)") {
|
if (newValue == "Double (1:2)") {
|
||||||
Provider.of<FlwtchState>(context).columns = [1, 2];
|
Provider.of<FlwtchState>(context).columns = [1, 2];
|
||||||
} else if (newValue == "Double (1:4)") {
|
} else if (newValue == "Double (1:4)") {
|
||||||
|
@ -95,8 +95,8 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
);
|
);
|
||||||
}).toList())),
|
}).toList())),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: Text(AppLocalizations.of(context).blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor())),
|
title: Text(AppLocalizations.of(context)!.blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor())),
|
||||||
subtitle: Text(AppLocalizations.of(context).descriptionBlockUnknownConnections),
|
subtitle: Text(AppLocalizations.of(context)!.descriptionBlockUnknownConnections),
|
||||||
value: settings.blockUnknownConnections,
|
value: settings.blockUnknownConnections,
|
||||||
onChanged: (bool value) {
|
onChanged: (bool value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -111,8 +111,8 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
secondary: Icon(Icons.app_blocking, color: settings.current().mainTextColor()),
|
secondary: Icon(Icons.app_blocking, color: settings.current().mainTextColor()),
|
||||||
),
|
),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: Text(AppLocalizations.of(context).experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor())),
|
title: Text(AppLocalizations.of(context)!.experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor())),
|
||||||
subtitle: Text(AppLocalizations.of(context).descriptionExperiments),
|
subtitle: Text(AppLocalizations.of(context)!.descriptionExperiments),
|
||||||
value: settings.experimentsEnabled,
|
value: settings.experimentsEnabled,
|
||||||
onChanged: (bool value) {
|
onChanged: (bool value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -130,9 +130,9 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: Text(AppLocalizations.of(context).enableGroups, style: TextStyle(color: settings.current().mainTextColor())),
|
title: Text(AppLocalizations.of(context)!.enableGroups, style: TextStyle(color: settings.current().mainTextColor())),
|
||||||
subtitle: Text(AppLocalizations.of(context).descriptionExperimentsGroups),
|
subtitle: Text(AppLocalizations.of(context)!.descriptionExperimentsGroups),
|
||||||
value: settings.experiments.containsKey(TapirGroupsExperiment) && settings.experiments[TapirGroupsExperiment],
|
value: settings.experiments.containsKey(TapirGroupsExperiment) && settings.experiments[TapirGroupsExperiment]!,
|
||||||
onChanged: (bool value) {
|
onChanged: (bool value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
settings.enableExperiment(TapirGroupsExperiment);
|
settings.enableExperiment(TapirGroupsExperiment);
|
||||||
|
@ -156,7 +156,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
height: 128,
|
height: 128,
|
||||||
)),
|
)),
|
||||||
applicationName: "Cwtch (Flutter UI)",
|
applicationName: "Cwtch (Flutter UI)",
|
||||||
applicationVersion: AppLocalizations.of(context).version.replaceAll("%1", constructVersionString(Provider.of<Settings>(context).packageInfo)),
|
applicationVersion: AppLocalizations.of(context)!.version.replaceAll("%1", constructVersionString(Provider.of<Settings>(context).packageInfo)),
|
||||||
applicationLegalese: '\u{a9} 2021 Open Privacy Research Society',
|
applicationLegalese: '\u{a9} 2021 Open Privacy Research Society',
|
||||||
),
|
),
|
||||||
]))));
|
]))));
|
||||||
|
@ -177,22 +177,22 @@ String constructVersionString(PackageInfo pinfo) {
|
||||||
/// an individual language code. There might be a more efficient way of doing this.
|
/// an individual language code. There might be a more efficient way of doing this.
|
||||||
String getLanguageFull(context, String languageCode) {
|
String getLanguageFull(context, String languageCode) {
|
||||||
if (languageCode == "en") {
|
if (languageCode == "en") {
|
||||||
return AppLocalizations.of(context).localeEn;
|
return AppLocalizations.of(context)!.localeEn;
|
||||||
}
|
}
|
||||||
if (languageCode == "es") {
|
if (languageCode == "es") {
|
||||||
return AppLocalizations.of(context).localeEs;
|
return AppLocalizations.of(context)!.localeEs;
|
||||||
}
|
}
|
||||||
if (languageCode == "fr") {
|
if (languageCode == "fr") {
|
||||||
return AppLocalizations.of(context).localeFr;
|
return AppLocalizations.of(context)!.localeFr;
|
||||||
}
|
}
|
||||||
if (languageCode == "pt") {
|
if (languageCode == "pt") {
|
||||||
return AppLocalizations.of(context).localePt;
|
return AppLocalizations.of(context)!.localePt;
|
||||||
}
|
}
|
||||||
if (languageCode == "de") {
|
if (languageCode == "de") {
|
||||||
return AppLocalizations.of(context).localeDe;
|
return AppLocalizations.of(context)!.localeDe;
|
||||||
}
|
}
|
||||||
if (languageCode == "it") {
|
if (languageCode == "it") {
|
||||||
return AppLocalizations.of(context).localeIt;
|
return AppLocalizations.of(context)!.localeIt;
|
||||||
}
|
}
|
||||||
return languageCode;
|
return languageCode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(Provider.of<ContactInfoState>(context).nickname + " " + AppLocalizations.of(context).conversationSettings),
|
title: Text(Provider.of<ContactInfoState>(context).nickname + " " + AppLocalizations.of(context)!.conversationSettings),
|
||||||
),
|
),
|
||||||
body: _buildSettingsList(),
|
body: _buildSettingsList(),
|
||||||
);
|
);
|
||||||
|
@ -68,24 +68,28 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).groupAddr),
|
CwtchLabel(label: AppLocalizations.of(context)!.groupAddr),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchTextField(
|
CwtchTextField(
|
||||||
controller: ctrlrGroupAddr,
|
controller: ctrlrGroupAddr,
|
||||||
|
labelText: '',
|
||||||
|
validator: (value) {},
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).server),
|
CwtchLabel(label: AppLocalizations.of(context)!.server),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchTextField(
|
CwtchTextField(
|
||||||
controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).server),
|
controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).server),
|
||||||
|
validator: (value) {},
|
||||||
|
labelText: '',
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
// Nickname Save Button
|
// Nickname Save Button
|
||||||
|
@ -93,7 +97,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).displayNameLabel),
|
CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -107,14 +111,14 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SetGroupAttribute(profileOnion, handle, "local.name", ctrlrNick.text);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.SetGroupAttribute(profileOnion, handle, "local.name", ctrlrNick.text);
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.save),
|
icon: Icon(Icons.save),
|
||||||
tooltip: AppLocalizations.of(context).saveBtn,
|
tooltip: AppLocalizations.of(context)!.saveBtn,
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).conversationSettings),
|
CwtchLabel(label: AppLocalizations.of(context)!.conversationSettings),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -127,7 +131,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
||||||
|
|
||||||
void _copyOnion() {
|
void _copyOnion() {
|
||||||
Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion));
|
Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion));
|
||||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification));
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedClipboardNotification));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ class _MessageViewState extends State<MessageView> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sendMessage([String ignoredParam]) {
|
void _sendMessage([String? ignoredParam]) {
|
||||||
ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text);
|
ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text);
|
||||||
Provider.of<FlwtchState>(context, listen: false)
|
Provider.of<FlwtchState>(context, listen: false)
|
||||||
.cwtch
|
.cwtch
|
||||||
|
@ -95,7 +95,7 @@ class _MessageViewState extends State<MessageView> {
|
||||||
_sendMessageHelper();
|
_sendMessageHelper();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sendInvitation([String ignoredParam]) {
|
void _sendInvitation([String? ignoredParam]) {
|
||||||
Provider.of<FlwtchState>(context, listen: false)
|
Provider.of<FlwtchState>(context, listen: false)
|
||||||
.cwtch
|
.cwtch
|
||||||
.SendInvitation(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion, this.selectedContact);
|
.SendInvitation(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion, this.selectedContact);
|
||||||
|
@ -167,7 +167,7 @@ class _MessageViewState extends State<MessageView> {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(AppLocalizations.of(bcontext).invitationLabel),
|
Text(AppLocalizations.of(bcontext)!.invitationLabel),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -182,7 +182,7 @@ class _MessageViewState extends State<MessageView> {
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
child: Text(AppLocalizations.of(bcontext).inviteBtn, semanticsLabel: AppLocalizations.of(bcontext).inviteBtn),
|
child: Text(AppLocalizations.of(bcontext)!.inviteBtn, semanticsLabel: AppLocalizations.of(bcontext)!.inviteBtn),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
this._sendInvitation();
|
this._sendInvitation();
|
||||||
Navigator.pop(bcontext);
|
Navigator.pop(bcontext);
|
||||||
|
|
|
@ -59,7 +59,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
padding: EdgeInsets.all(2),
|
padding: EdgeInsets.all(2),
|
||||||
child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
CwtchLabel(label: AppLocalizations.of(context).displayNameLabel),
|
CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -78,7 +78,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.save),
|
icon: Icon(Icons.save),
|
||||||
tooltip: AppLocalizations.of(context).saveBtn,
|
tooltip: AppLocalizations.of(context)!.saveBtn,
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).addressLabel),
|
CwtchLabel(label: AppLocalizations.of(context)!.addressLabel),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
@ -95,19 +95,19 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).onion),
|
controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).onion),
|
||||||
onPressed: _copyOnion,
|
onPressed: _copyOnion,
|
||||||
icon: Icon(Icons.copy),
|
icon: Icon(Icons.copy),
|
||||||
tooltip: AppLocalizations.of(context).copyBtn,
|
tooltip: AppLocalizations.of(context)!.copyBtn,
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchLabel(label: AppLocalizations.of(context).conversationSettings),
|
CwtchLabel(label: AppLocalizations.of(context)!.conversationSettings),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: Text(AppLocalizations.of(context).blockBtn, style: TextStyle(color: settings.current().mainTextColor())),
|
title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor())),
|
||||||
value: Provider.of<ContactInfoState>(context).isBlocked,
|
value: Provider.of<ContactInfoState>(context).isBlocked,
|
||||||
onChanged: (bool blocked) {
|
onChanged: (bool blocked) {
|
||||||
// Save local blocked status
|
// Save local blocked status
|
||||||
|
@ -138,15 +138,15 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
secondary: Icon(Icons.block, color: settings.current().mainTextColor()),
|
secondary: Icon(Icons.block, color: settings.current().mainTextColor()),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(AppLocalizations.of(context).savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())),
|
title: Text(AppLocalizations.of(context)!.savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())),
|
||||||
subtitle: Text(AppLocalizations.of(context).savePeerHistoryDescription),
|
subtitle: Text(AppLocalizations.of(context)!.savePeerHistoryDescription),
|
||||||
leading: Icon(Icons.history_sharp, color: settings.current().mainTextColor()),
|
leading: Icon(Icons.history_sharp, color: settings.current().mainTextColor()),
|
||||||
trailing: DropdownButton(
|
trailing: DropdownButton(
|
||||||
value: Provider.of<ContactInfoState>(context).savePeerHistory == "DefaultDeleteHistory"
|
value: Provider.of<ContactInfoState>(context).savePeerHistory == "DefaultDeleteHistory"
|
||||||
? AppLocalizations.of(context).dontSavePeerHistory
|
? AppLocalizations.of(context)!.dontSavePeerHistory
|
||||||
: (Provider.of<ContactInfoState>(context).savePeerHistory == "SaveHistory"
|
: (Provider.of<ContactInfoState>(context).savePeerHistory == "SaveHistory"
|
||||||
? AppLocalizations.of(context).savePeerHistory
|
? AppLocalizations.of(context)!.savePeerHistory
|
||||||
: AppLocalizations.of(context).dontSavePeerHistory),
|
: AppLocalizations.of(context)!.dontSavePeerHistory),
|
||||||
onChanged: (newValue) {
|
onChanged: (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
// Set whether or not to dave the Contact History...
|
// Set whether or not to dave the Contact History...
|
||||||
|
@ -154,7 +154,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
var onion = Provider.of<ContactInfoState>(context, listen: false).onion;
|
var onion = Provider.of<ContactInfoState>(context, listen: false).onion;
|
||||||
const SaveHistoryKey = "SavePeerHistory";
|
const SaveHistoryKey = "SavePeerHistory";
|
||||||
|
|
||||||
if (newValue == AppLocalizations.of(context).savePeerHistory) {
|
if (newValue == AppLocalizations.of(context)!.savePeerHistory) {
|
||||||
Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = "SaveHistory";
|
Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = "SaveHistory";
|
||||||
final setPeerAttribute = {
|
final setPeerAttribute = {
|
||||||
"EventType": "SetPeerAttribute",
|
"EventType": "SetPeerAttribute",
|
||||||
|
@ -174,7 +174,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
items: [AppLocalizations.of(context).savePeerHistory, AppLocalizations.of(context).dontSavePeerHistory].map<DropdownMenuItem<String>>((String value) {
|
items: [AppLocalizations.of(context)!.savePeerHistory, AppLocalizations.of(context)!.dontSavePeerHistory].map<DropdownMenuItem<String>>((String value) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: value,
|
value: value,
|
||||||
child: Text(value),
|
child: Text(value),
|
||||||
|
@ -188,7 +188,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
|
|
||||||
void _copyOnion() {
|
void _copyOnion() {
|
||||||
Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion));
|
Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion));
|
||||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification));
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedClipboardNotification));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,24 +39,24 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Provider.of<Settings>(context).theme.backgroundMainColor(),
|
backgroundColor: Provider.of<Settings>(context).theme.backgroundMainColor(),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context).titleManageProfiles),
|
title: Text(AppLocalizations.of(context)!.titleManageProfiles),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(icon: TorIcon(), onPressed: _pushTorStatus),
|
IconButton(icon: TorIcon(), onPressed: _pushTorStatus),
|
||||||
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug),
|
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.lock_open),
|
icon: Icon(Icons.lock_open),
|
||||||
tooltip: AppLocalizations.of(context).tooltipUnlockProfiles,
|
tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles,
|
||||||
onPressed: _modalUnlockProfiles,
|
onPressed: _modalUnlockProfiles,
|
||||||
),
|
),
|
||||||
IconButton(icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context).tooltipOpenSettings, onPressed: _pushGlobalSettings),
|
IconButton(icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context)!.tooltipOpenSettings, onPressed: _pushGlobalSettings),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: _pushAddEditProfile,
|
onPressed: _pushAddEditProfile,
|
||||||
tooltip: AppLocalizations.of(context).addNewProfileBtn,
|
tooltip: AppLocalizations.of(context)!.addNewProfileBtn,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
semanticLabel: AppLocalizations.of(context).addNewProfileBtn,
|
semanticLabel: AppLocalizations.of(context)!.addNewProfileBtn,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: _buildProfileManager(), //_buildSuggestions(),
|
body: _buildProfileManager(), //_buildSuggestions(),
|
||||||
|
@ -122,12 +122,13 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(AppLocalizations.of(context).enterProfilePassword),
|
Text(AppLocalizations.of(context)!.enterProfilePassword),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchPasswordField(
|
CwtchPasswordField(
|
||||||
controller: ctrlrPassword,
|
controller: ctrlrPassword,
|
||||||
|
validator: (value) {},
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
|
@ -136,7 +137,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
||||||
Spacer(),
|
Spacer(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
child: Text(AppLocalizations.of(context).unlock, semanticsLabel: AppLocalizations.of(context).unlock),
|
child: Text(AppLocalizations.of(context)!.unlock, semanticsLabel: AppLocalizations.of(context)!.unlock),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.LoadProfiles(ctrlrPassword.value.text);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.LoadProfiles(ctrlrPassword.value.text);
|
||||||
ctrlrPassword.text = "";
|
ctrlrPassword.text = "";
|
||||||
|
|
|
@ -44,7 +44,7 @@ class _TorStatusView extends State<TorStatusView> {
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: TorIcon(),
|
leading: TorIcon(),
|
||||||
title: Text("Tor Status"),
|
title: Text("Tor Status"),
|
||||||
subtitle: Text(torStatus.progress == 100 ? AppLocalizations.of(context).networkStatusOnline : torStatus.status),
|
subtitle: Text(torStatus.progress == 100 ? AppLocalizations.of(context)!.networkStatusOnline : torStatus.status),
|
||||||
trailing: ElevatedButton(
|
trailing: ElevatedButton(
|
||||||
child: Text("Reset"),
|
child: Text("Reset"),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import '../model.dart';
|
||||||
// Pass an onChanged handler to access value
|
// Pass an onChanged handler to access value
|
||||||
class DropdownContacts extends StatefulWidget {
|
class DropdownContacts extends StatefulWidget {
|
||||||
DropdownContacts({
|
DropdownContacts({
|
||||||
this.onChanged,
|
required this.onChanged,
|
||||||
});
|
});
|
||||||
final Function(dynamic) onChanged;
|
final Function(dynamic) onChanged;
|
||||||
|
|
||||||
|
@ -18,18 +18,18 @@ class DropdownContacts extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DropdownContactsState extends State<DropdownContacts> {
|
class _DropdownContactsState extends State<DropdownContacts> {
|
||||||
String selected;
|
late String selected;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DropdownButton(
|
return DropdownButton(
|
||||||
value: this.selected,
|
value: this.selected,
|
||||||
items: Provider.of<ProfileInfoState>(context, listen: false).contactList.contacts.map<DropdownMenuItem<String>>((ContactInfoState contact) {
|
items: Provider.of<ProfileInfoState>(context, listen: false).contactList.contacts.map<DropdownMenuItem<String>>((ContactInfoState contact) {
|
||||||
return DropdownMenuItem<String>(value: contact.onion, child: Text(contact.nickname ?? contact.onion));
|
return DropdownMenuItem<String>(value: contact.onion, child: Text(contact.nickname));
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: (newVal) {
|
onChanged: (newVal) {
|
||||||
setState(() {
|
setState(() {
|
||||||
this.selected = newVal;
|
this.selected = newVal.toString();
|
||||||
});
|
});
|
||||||
if (widget.onChanged != null) {
|
if (widget.onChanged != null) {
|
||||||
widget.onChanged(newVal);
|
widget.onChanged(newVal);
|
||||||
|
|
|
@ -5,9 +5,9 @@ import 'package:provider/provider.dart';
|
||||||
// Provides a styled Text Field for use in Form Widgets.
|
// Provides a styled Text Field for use in Form Widgets.
|
||||||
// Callers must provide a text controller, label helper text and a validator.
|
// Callers must provide a text controller, label helper text and a validator.
|
||||||
class CwtchButtonTextField extends StatefulWidget {
|
class CwtchButtonTextField extends StatefulWidget {
|
||||||
CwtchButtonTextField({this.controller, this.onPressed, this.icon, this.tooltip, this.readonly = true});
|
CwtchButtonTextField({required this.controller, required this.onPressed, required this.icon, required this.tooltip, this.readonly = true});
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final Function onPressed;
|
final Function()? onPressed;
|
||||||
final Icon icon;
|
final Icon icon;
|
||||||
final String tooltip;
|
final String tooltip;
|
||||||
final bool readonly;
|
final bool readonly;
|
||||||
|
|
|
@ -123,7 +123,7 @@ class _ContactRowState extends State<ContactRow> {
|
||||||
|
|
||||||
String dateToNiceString(DateTime date) {
|
String dateToNiceString(DateTime date) {
|
||||||
if (date.millisecondsSinceEpoch == 0) {
|
if (date.millisecondsSinceEpoch == 0) {
|
||||||
return AppLocalizations.of(context).dateNever;
|
return AppLocalizations.of(context)!.dateNever;
|
||||||
}
|
}
|
||||||
// If the last message was over a day ago, just state the date
|
// If the last message was over a day ago, just state the date
|
||||||
if (DateTime.now().difference(date).inDays > 1) {
|
if (DateTime.now().difference(date).inDays > 1) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import '../settings.dart';
|
||||||
// Callers must provide a label text
|
// Callers must provide a label text
|
||||||
// TODO: Integrate this with a settings "zoom" / accessibility setting
|
// TODO: Integrate this with a settings "zoom" / accessibility setting
|
||||||
class CwtchLabel extends StatefulWidget {
|
class CwtchLabel extends StatefulWidget {
|
||||||
CwtchLabel({this.label});
|
CwtchLabel({required this.label});
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -37,11 +37,7 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
||||||
var senderDisplayStr = "";
|
var senderDisplayStr = "";
|
||||||
if (Provider.of<MessageState>(context).senderOnion != null) {
|
if (Provider.of<MessageState>(context).senderOnion != null) {
|
||||||
var contact = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).senderOnion);
|
var contact = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).senderOnion);
|
||||||
if (contact == null) {
|
senderDisplayStr = contact.nickname;
|
||||||
senderDisplayStr = Provider.of<MessageState>(context).senderOnion;
|
|
||||||
} else {
|
|
||||||
senderDisplayStr = contact.nickname ?? contact.onion;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var wdgSender = Center(
|
var wdgSender = Center(
|
||||||
widthFactor: 1,
|
widthFactor: 1,
|
||||||
|
|
|
@ -31,7 +31,7 @@ class MessageBubbleState extends State<MessageBubble> {
|
||||||
if (contact == null) {
|
if (contact == null) {
|
||||||
senderDisplayStr = Provider.of<MessageState>(context).senderOnion;
|
senderDisplayStr = Provider.of<MessageState>(context).senderOnion;
|
||||||
} else {
|
} else {
|
||||||
senderDisplayStr = contact.nickname ?? contact.onion;
|
senderDisplayStr = contact.nickname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var wdgSender = SelectableText(senderDisplayStr,
|
var wdgSender = SelectableText(senderDisplayStr,
|
||||||
|
|
|
@ -14,7 +14,7 @@ import 'messagebubble.dart';
|
||||||
import 'messageloadingbubble.dart';
|
import 'messageloadingbubble.dart';
|
||||||
|
|
||||||
class MessageRow extends StatefulWidget {
|
class MessageRow extends StatefulWidget {
|
||||||
MessageRow({Key key}) : super(key: key);
|
MessageRow({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageRowState createState() => _MessageRowState();
|
_MessageRowState createState() => _MessageRowState();
|
||||||
|
@ -52,10 +52,12 @@ class _MessageRowState extends State<MessageRow> {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(4.0),
|
padding: EdgeInsets.all(4.0),
|
||||||
child: ProfileImage(
|
child: ProfileImage(
|
||||||
diameter: 48.0,
|
diameter: 48.0,
|
||||||
imagePath: Provider.of<MessageState>(context).senderImage ?? contact.imagePath,
|
imagePath: Provider.of<MessageState>(context).senderImage ?? contact.imagePath,
|
||||||
//maskOut: contact.status != "Authenticated",
|
//maskOut: contact.status != "Authenticated",
|
||||||
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor())));
|
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor(),
|
||||||
|
badgeTextColor: Colors.red, badgeColor: Colors.red,
|
||||||
|
)));
|
||||||
|
|
||||||
widgetRow = <Widget>[
|
widgetRow = <Widget>[
|
||||||
wdgPortrait,
|
wdgPortrait,
|
||||||
|
@ -76,7 +78,7 @@ class _MessageRowState extends State<MessageRow> {
|
||||||
case 101:
|
case 101:
|
||||||
return InvitationBubble();
|
return InvitationBubble();
|
||||||
}
|
}
|
||||||
return null;
|
return MalformedBubble();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _btnAdd() {
|
void _btnAdd() {
|
||||||
|
@ -94,7 +96,7 @@ class _MessageRowState extends State<MessageRow> {
|
||||||
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
|
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
|
||||||
|
|
||||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).successfullAddedContact));
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import '../settings.dart';
|
||||||
// Provides a styled Password Input Field for use in Form Widgets.
|
// Provides a styled Password Input Field for use in Form Widgets.
|
||||||
// Callers must provide a text controller, label helper text and a validator.
|
// Callers must provide a text controller, label helper text and a validator.
|
||||||
class CwtchPasswordField extends StatefulWidget {
|
class CwtchPasswordField extends StatefulWidget {
|
||||||
CwtchPasswordField({this.controller, this.validator});
|
CwtchPasswordField({required this.controller, required this.validator});
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final FormFieldValidator validator;
|
final FormFieldValidator validator;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import 'package:provider/provider.dart';
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
|
|
||||||
class ProfileImage extends StatefulWidget {
|
class ProfileImage extends StatefulWidget {
|
||||||
ProfileImage({this.imagePath, this.diameter, this.border, this.badgeCount = 0, this.badgeColor, this.badgeTextColor, this.maskOut = false});
|
ProfileImage({required this.imagePath, required this.diameter, required this.border, this.badgeCount = 0, required this.badgeColor, required this.badgeTextColor, this.maskOut = false});
|
||||||
final double diameter;
|
final double diameter;
|
||||||
final String imagePath;
|
final String imagePath;
|
||||||
final Color border;
|
final Color border;
|
||||||
|
|
|
@ -55,7 +55,7 @@ class _ProfileRowState extends State<ProfileRow> {
|
||||||
)),
|
)),
|
||||||
IconButton(
|
IconButton(
|
||||||
enableFeedback: true,
|
enableFeedback: true,
|
||||||
tooltip: AppLocalizations.of(context).editProfile + " " + profile.nickname,
|
tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname,
|
||||||
icon: Icon(Icons.create, color: Provider.of<Settings>(context).current().mainTextColor()),
|
icon: Icon(Icons.create, color: Provider.of<Settings>(context).current().mainTextColor()),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_pushAddEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath);
|
_pushAddEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath);
|
||||||
|
|
|
@ -7,7 +7,7 @@ doNothing(String x) {}
|
||||||
// Provides a styled Text Field for use in Form Widgets.
|
// Provides a styled Text Field for use in Form Widgets.
|
||||||
// Callers must provide a text controller, label helper text and a validator.
|
// Callers must provide a text controller, label helper text and a validator.
|
||||||
class CwtchTextField extends StatefulWidget {
|
class CwtchTextField extends StatefulWidget {
|
||||||
CwtchTextField({this.controller, this.labelText, this.validator, this.onChanged = doNothing});
|
CwtchTextField({required this.controller, required this.labelText, required this.validator, this.onChanged = doNothing});
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final String labelText;
|
final String labelText;
|
||||||
final FormFieldValidator validator;
|
final FormFieldValidator validator;
|
||||||
|
|
|
@ -23,8 +23,8 @@ class _TorIconState extends State<TorIcon> {
|
||||||
color: Provider.of<Settings>(context).theme.mainTextColor(),
|
color: Provider.of<Settings>(context).theme.mainTextColor(),
|
||||||
colorBlendMode: BlendMode.srcIn,
|
colorBlendMode: BlendMode.srcIn,
|
||||||
semanticLabel: Provider.of<TorStatus>(context).progress == 100
|
semanticLabel: Provider.of<TorStatus>(context).progress == 100
|
||||||
? AppLocalizations.of(context).networkStatusOnline
|
? AppLocalizations.of(context)!.networkStatusOnline
|
||||||
: (Provider.of<TorStatus>(context).progress == 0 ? AppLocalizations.of(context).networkStatusDisconnected : AppLocalizations.of(context).networkStatusAttemptingTor),
|
: (Provider.of<TorStatus>(context).progress == 0 ? AppLocalizations.of(context)!.networkStatusDisconnected : AppLocalizations.of(context)!.networkStatusAttemptingTor),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ class _TorStatusState extends State<TorStatusLabel> {
|
||||||
stream: Provider.of<FlwtchState>(context).appStatus.torStatus(),
|
stream: Provider.of<FlwtchState>(context).appStatus.torStatus(),
|
||||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
return Text(
|
return Text(
|
||||||
snapshot.hasData ? snapshot.data : AppLocalizations.of(context).loadingTor,
|
snapshot.hasData ? snapshot.data! : AppLocalizations.of(context)!.loadingTor,
|
||||||
style: Theme.of(context).textTheme.headline4,
|
style: Theme.of(context).textTheme.headline4,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
26
pubspec.lock
26
pubspec.lock
|
@ -63,7 +63,7 @@ packages:
|
||||||
name: cupertino_icons
|
name: cupertino_icons
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.3"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -84,7 +84,7 @@ packages:
|
||||||
name: file
|
name: file
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.0"
|
version: "6.1.1"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -128,7 +128,7 @@ packages:
|
||||||
name: http
|
name: http
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.1"
|
version: "0.13.3"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -184,42 +184,42 @@ packages:
|
||||||
name: package_info_plus
|
name: package_info_plus
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
package_info_plus_linux:
|
package_info_plus_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_info_plus_linux
|
name: package_info_plus_linux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.2"
|
||||||
package_info_plus_macos:
|
package_info_plus_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_info_plus_macos
|
name: package_info_plus_macos
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.1"
|
||||||
package_info_plus_platform_interface:
|
package_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_info_plus_platform_interface
|
name: package_info_plus_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
package_info_plus_web:
|
package_info_plus_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_info_plus_web
|
name: package_info_plus_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
package_info_plus_windows:
|
package_info_plus_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_info_plus_windows
|
name: package_info_plus_windows
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -261,7 +261,7 @@ packages:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.1"
|
||||||
pedantic:
|
pedantic:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -296,7 +296,7 @@ packages:
|
||||||
name: provider
|
name: provider
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.3.2+3"
|
version: "5.0.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -385,7 +385,7 @@ packages:
|
||||||
name: win32
|
name: win32
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
version: "2.1.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -394,5 +394,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.2.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.12.0 <3.0.0"
|
dart: ">=2.13.0 <3.0.0"
|
||||||
flutter: ">=1.20.0"
|
flutter: ">=1.20.0"
|
||||||
|
|
|
@ -18,12 +18,12 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.7.0 <3.0.0"
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
provider: "4.3.2+3"
|
provider: 5.0.0
|
||||||
package_info_plus: ^1.0.0
|
package_info_plus: ^1.0.0
|
||||||
#intl_translation: any
|
#intl_translation: any
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
|
|
Loading…
Reference in New Issue