Compare commits
1 Commits
trunk
...
profile_im
Author | SHA1 | Date |
---|---|---|
Sarah Jamie Lewis | 03600906c3 |
|
@ -8,7 +8,6 @@ import 'package:cwtch/models/profileservers.dart';
|
||||||
import 'package:cwtch/models/remoteserver.dart';
|
import 'package:cwtch/models/remoteserver.dart';
|
||||||
import 'package:cwtch/models/servers.dart';
|
import 'package:cwtch/models/servers.dart';
|
||||||
import 'package:cwtch/notification_manager.dart';
|
import 'package:cwtch/notification_manager.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:cwtch/torstatus.dart';
|
import 'package:cwtch/torstatus.dart';
|
||||||
|
@ -150,10 +149,9 @@ class CwtchNotifier {
|
||||||
var senderImage = data['Picture'];
|
var senderImage = data['Picture'];
|
||||||
var isAuto = data['Auto'] == "true";
|
var isAuto = data['Auto'] == "true";
|
||||||
String? contenthash = data['ContentHash'];
|
String? contenthash = data['ContentHash'];
|
||||||
var selectedProfile = appState.selectedProfile == data["ProfileOnion"];
|
var selectedConversation = appState.selectedProfile == data["ProfileOnion"] && appState.selectedConversation == identifier;
|
||||||
var selectedConversation = selectedProfile && appState.selectedConversation == identifier;
|
|
||||||
|
|
||||||
profileCN.getProfile(data["ProfileOnion"])?.newMessage(
|
profileCN.getProfile(data["ProfileOnion"])?.contactList.newMessage(
|
||||||
identifier,
|
identifier,
|
||||||
messageID,
|
messageID,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
@ -162,10 +160,9 @@ class CwtchNotifier {
|
||||||
isAuto,
|
isAuto,
|
||||||
data["Data"],
|
data["Data"],
|
||||||
contenthash,
|
contenthash,
|
||||||
selectedProfile,
|
|
||||||
selectedConversation,
|
selectedConversation,
|
||||||
);
|
);
|
||||||
appState.notifyProfileUnread();
|
|
||||||
break;
|
break;
|
||||||
case "PeerAcknowledgement":
|
case "PeerAcknowledgement":
|
||||||
// We don't use these anymore, IndexedAcknowledgement is more suited to the UI front end...
|
// We don't use these anymore, IndexedAcknowledgement is more suited to the UI front end...
|
||||||
|
@ -205,8 +202,7 @@ class CwtchNotifier {
|
||||||
var currentTotal = contact!.totalMessages;
|
var currentTotal = contact!.totalMessages;
|
||||||
var isAuto = data['Auto'] == "true";
|
var isAuto = data['Auto'] == "true";
|
||||||
String? contenthash = data['ContentHash'];
|
String? contenthash = data['ContentHash'];
|
||||||
var selectedProfile = appState.selectedProfile == data["ProfileOnion"];
|
var selectedConversation = appState.selectedProfile == data["ProfileOnion"] && appState.selectedConversation == identifier;
|
||||||
var selectedConversation = selectedProfile && appState.selectedConversation == identifier;
|
|
||||||
|
|
||||||
// Only bother to do anything if we know about the group and the provided index is greater than our current total...
|
// Only bother to do anything if we know about the group and the provided index is greater than our current total...
|
||||||
if (currentTotal != null && idx >= currentTotal) {
|
if (currentTotal != null && idx >= currentTotal) {
|
||||||
|
@ -220,10 +216,9 @@ class CwtchNotifier {
|
||||||
// For now we perform some minimal checks on the sent timestamp to use to provide a useful ordering for honest contacts
|
// For now we perform some minimal checks on the sent timestamp to use to provide a useful ordering for honest contacts
|
||||||
// and ensure that malicious contacts in groups can only set this timestamp to a value within the range of `last seen message time`
|
// and ensure that malicious contacts in groups can only set this timestamp to a value within the range of `last seen message time`
|
||||||
// and `local now`.
|
// and `local now`.
|
||||||
profileCN.getProfile(data["ProfileOnion"])?.newMessage(identifier, idx, timestampSent, senderHandle, senderImage, isAuto, data["Data"], contenthash, selectedProfile, selectedConversation);
|
profileCN.getProfile(data["ProfileOnion"])?.contactList.newMessage(identifier, idx, timestampSent, senderHandle, senderImage, isAuto, data["Data"], contenthash, selectedConversation);
|
||||||
|
|
||||||
notificationManager.notify("New Message From Group!");
|
notificationManager.notify("New Message From Group!");
|
||||||
appState.notifyProfileUnread();
|
|
||||||
}
|
}
|
||||||
RemoteServerInfoState? server = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(contact.server ?? "");
|
RemoteServerInfoState? server = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(contact.server ?? "");
|
||||||
server?.updateSyncProgressFor(timestampSent);
|
server?.updateSyncProgressFor(timestampSent);
|
||||||
|
|
|
@ -45,6 +45,10 @@ class Flwtch extends StatefulWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FlwtchState createState() => FlwtchState();
|
FlwtchState createState() => FlwtchState();
|
||||||
|
|
||||||
|
String yay() {
|
||||||
|
return "yay!";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FlwtchState extends State<Flwtch> with WindowListener {
|
class FlwtchState extends State<Flwtch> with WindowListener {
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
enum ModalState { none, storageMigration }
|
enum ModalState { none, storageMigration }
|
||||||
|
@ -18,13 +16,6 @@ class AppState extends ChangeNotifier {
|
||||||
bool _disableFilePicker = false;
|
bool _disableFilePicker = false;
|
||||||
bool _focus = true;
|
bool _focus = true;
|
||||||
|
|
||||||
StreamController<bool> _profilesUnreadNotifyControler = StreamController<bool>();
|
|
||||||
late Stream<bool> profilesUnreadNotify;
|
|
||||||
|
|
||||||
AppState() {
|
|
||||||
profilesUnreadNotify = _profilesUnreadNotifyControler.stream.asBroadcastStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetCwtchInit() {
|
void SetCwtchInit() {
|
||||||
cwtchInit = true;
|
cwtchInit = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
@ -91,12 +82,4 @@ class AppState extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isLandscape(BuildContext c) => MediaQuery.of(c).size.width > MediaQuery.of(c).size.height;
|
bool isLandscape(BuildContext c) => MediaQuery.of(c).size.width > MediaQuery.of(c).size.height;
|
||||||
|
|
||||||
void notifyProfileUnread() {
|
|
||||||
_profilesUnreadNotifyControler.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream<bool> getUnreadProfileNotifyStream() {
|
|
||||||
return profilesUnreadNotify;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,14 +120,10 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void recountUnread() {
|
|
||||||
this._unreadMessages = _contacts.contacts.fold(0, (i, c) => i + c.unreadMessages);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a contact from a list. Currently only used when rejecting a group invitation.
|
// Remove a contact from a list. Currently only used when rejecting a group invitation.
|
||||||
// Eventually will also be used for other removals.
|
// Eventually will also be used for other removals.
|
||||||
void removeContact(String handle) {
|
void removeContact(int handle) {
|
||||||
this.contactList.removeContactByHandle(handle);
|
this.contactList.removeContact(handle);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,30 +168,11 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])),
|
lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
unreadMessages += int.parse(contact["numUnread"]);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this._contacts.resort();
|
this._contacts.resort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void newMessage(int identifier, int messageID, DateTime timestamp, String senderHandle, String senderImage, bool isAuto, String data, String? contenthash, bool selectedProfile, bool selectedConversation) {
|
|
||||||
if (!selectedProfile) {
|
|
||||||
unreadMessages++;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
contactList.newMessage(
|
|
||||||
identifier,
|
|
||||||
messageID,
|
|
||||||
timestamp,
|
|
||||||
senderHandle,
|
|
||||||
senderImage,
|
|
||||||
isAuto,
|
|
||||||
data,
|
|
||||||
contenthash,
|
|
||||||
selectedConversation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void downloadInit(String fileKey, int numChunks) {
|
void downloadInit(String fileKey, int numChunks) {
|
||||||
this._downloads[fileKey] = FileDownloadProgress(numChunks, DateTime.now());
|
this._downloads[fileKey] = FileDownloadProgress(numChunks, DateTime.now());
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
|
@ -27,8 +27,4 @@ class ProfileListState extends ChangeNotifier {
|
||||||
_profiles.removeWhere((element) => element.onion == onion);
|
_profiles.removeWhere((element) => element.onion == onion);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
int generateUnreadCount(String selectedProfile) => _profiles.where( (p) => p.onion != selectedProfile ).fold(0, (i, p) => i + p.unreadMessages);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cwtch/main.dart';
|
import 'package:cwtch/main.dart';
|
||||||
import 'package:win_toast/win_toast.dart';
|
import 'package:desktoasts/desktoasts.dart';
|
||||||
import 'package:desktop_notifications/desktop_notifications.dart';
|
import 'package:desktop_notifications/desktop_notifications.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
@ -38,27 +37,44 @@ class LinuxNotificationsManager implements NotificationsManager {
|
||||||
// Windows Notification Manager uses https://pub.dev/packages/desktoasts to implement
|
// Windows Notification Manager uses https://pub.dev/packages/desktoasts to implement
|
||||||
// windows notifications
|
// windows notifications
|
||||||
class WindowsNotificationManager implements NotificationsManager {
|
class WindowsNotificationManager implements NotificationsManager {
|
||||||
|
late ToastService service;
|
||||||
bool active = false;
|
bool active = false;
|
||||||
bool initialized = false;
|
|
||||||
|
|
||||||
WindowsNotificationManager() {
|
WindowsNotificationManager() {
|
||||||
scheduleMicrotask(() async {
|
service = new ToastService(
|
||||||
initialized = await WinToast.instance().initialize(appName: 'cwtch', productName: 'Cwtch', companyName: 'Open Privacy Research Society');
|
appName: 'cwtch',
|
||||||
|
companyName: 'Open Privacy Research Society',
|
||||||
|
productName: 'Cwtch',
|
||||||
|
);
|
||||||
|
|
||||||
|
service.stream.listen((event) {
|
||||||
|
// the user closed the notification of the OS timed it out
|
||||||
|
if (event is ToastDismissed) {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
// clicked
|
||||||
|
if (event is ToastActivated) {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
// if a supplied action was clicked
|
||||||
|
if (event is ToastInteracted) {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> notify(String message) async {
|
Future<void> notify(String message) async {
|
||||||
if (initialized && !globalAppState.focus) {
|
if (!globalAppState.focus) {
|
||||||
if (!active) {
|
if (!active) {
|
||||||
|
// One string of bold text on the first line (title),
|
||||||
|
// one string (subtitle) of regular text wrapped across the second and third lines.
|
||||||
|
Toast toast = new Toast(
|
||||||
|
type: ToastType.text02,
|
||||||
|
title: 'Cwtch',
|
||||||
|
subtitle: message,
|
||||||
|
);
|
||||||
|
service.show(toast);
|
||||||
active = true;
|
active = true;
|
||||||
WinToast.instance().clear();
|
|
||||||
final toast = await WinToast.instance().showToast(type: ToastType.text01, title: message);
|
|
||||||
toast?.eventStream.listen((event) {
|
|
||||||
if (event is ActivatedEvent) {
|
|
||||||
WinToast.instance().bringWindowToFront();
|
|
||||||
}
|
|
||||||
active = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,8 +68,8 @@ class CwtchDark extends OpaqueThemeType {
|
||||||
get portraitBlockedTextColor => lightGrey;
|
get portraitBlockedTextColor => lightGrey;
|
||||||
get portraitContactBadgeColor => hotPink;
|
get portraitContactBadgeColor => hotPink;
|
||||||
get portraitContactBadgeTextColor => whiteishPurple;
|
get portraitContactBadgeTextColor => whiteishPurple;
|
||||||
get portraitProfileBadgeColor => hotPink;
|
get portraitProfileBadgeColor => mauvePurple;
|
||||||
get portraitProfileBadgeTextColor => whiteishPurple;
|
get portraitProfileBadgeTextColor => darkGreyPurple;
|
||||||
get dropShadowColor => mauvePurple;
|
get dropShadowColor => mauvePurple;
|
||||||
get toolbarIconColor => settings; //whiteishPurple;
|
get toolbarIconColor => settings; //whiteishPurple;
|
||||||
get messageFromMeBackgroundColor => userBubble; // mauvePurple;
|
get messageFromMeBackgroundColor => userBubble; // mauvePurple;
|
||||||
|
@ -112,7 +112,7 @@ class CwtchLight extends OpaqueThemeType {
|
||||||
get portraitBlockedTextColor => softGrey;
|
get portraitBlockedTextColor => softGrey;
|
||||||
get portraitContactBadgeColor => accent;
|
get portraitContactBadgeColor => accent;
|
||||||
get portraitContactBadgeTextColor => whitePurple;
|
get portraitContactBadgeTextColor => whitePurple;
|
||||||
get portraitProfileBadgeColor => accent;
|
get portraitProfileBadgeColor => brightPurple;
|
||||||
get portraitProfileBadgeTextColor => whitePurple;
|
get portraitProfileBadgeTextColor => whitePurple;
|
||||||
get dropShadowColor => purple;
|
get dropShadowColor => purple;
|
||||||
get toolbarIconColor => settings; //darkPurple;
|
get toolbarIconColor => settings; //darkPurple;
|
||||||
|
|
|
@ -138,7 +138,6 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
CwtchTextField(
|
CwtchTextField(
|
||||||
testKey: Key("txtAddP2P"),
|
|
||||||
controller: ctrlrContact,
|
controller: ctrlrContact,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == "") {
|
if (value == "") {
|
||||||
|
|
|
@ -76,31 +76,6 @@ class _ContactsViewState extends State<ContactsView> {
|
||||||
endDrawerEnableOpenDragGesture: false,
|
endDrawerEnableOpenDragGesture: false,
|
||||||
drawerEnableOpenDragGesture: false,
|
drawerEnableOpenDragGesture: false,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: Row(children: [
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.arrow_back),
|
|
||||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
|
||||||
onPressed: () {
|
|
||||||
Provider.of<ProfileInfoState>(context, listen: false).recountUnread();
|
|
||||||
Provider.of<AppState>(context, listen: false).selectedProfile = "";
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
StreamBuilder<bool>(
|
|
||||||
stream: Provider.of<AppState>(context).getUnreadProfileNotifyStream(),
|
|
||||||
builder: (BuildContext context, AsyncSnapshot<bool> unreadCountSnapshot) {
|
|
||||||
int unreadCount = Provider.of<ProfileListState>(context).generateUnreadCount(Provider.of<AppState>(context).selectedProfile ?? "") ;
|
|
||||||
|
|
||||||
return Visibility(
|
|
||||||
visible: unreadCount > 0,
|
|
||||||
child: CircleAvatar(
|
|
||||||
radius: 10.0,
|
|
||||||
backgroundColor: Provider.of<Settings>(context).theme.portraitProfileBadgeColor,
|
|
||||||
child: Text(unreadCount > 99 ? "99+" : unreadCount.toString(), style: TextStyle(color: Provider.of<Settings>(context).theme.portraitProfileBadgeTextColor, fontSize: 8.0)),
|
|
||||||
));
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
title: RepaintBoundary(
|
title: RepaintBoundary(
|
||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
ProfileImage(
|
ProfileImage(
|
||||||
|
|
|
@ -107,7 +107,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
||||||
items: themes.keys.map<DropdownMenuItem<String>>((String themeId) {
|
items: themes.keys.map<DropdownMenuItem<String>>((String themeId) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: themeId,
|
value: themeId,
|
||||||
child: Text(getThemeName(context, themeId)), //"ddi_$themeId", key: Key("ddi_$themeId")),
|
child: Text("ddi_$themeId", key: Key("ddi_$themeId")), //getThemeName(context, themeId)),
|
||||||
);
|
);
|
||||||
}).toList()),
|
}).toList()),
|
||||||
leading: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor),
|
leading: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor),
|
||||||
|
|
|
@ -151,7 +151,7 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
||||||
Navigator.of(context).popUntil((route) => route.settings.name == "conversations"); // dismiss dialog
|
Navigator.of(context).popUntil((route) => route.settings.name == "conversations"); // dismiss dialog
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: Icon(CwtchIcons.leave_chat),
|
icon: Icon(Icons.archive),
|
||||||
label: Text(AppLocalizations.of(context)!.archiveConversation),
|
label: Text(AppLocalizations.of(context)!.archiveConversation),
|
||||||
)),
|
)),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
@ -198,8 +198,6 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
||||||
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
||||||
// locally update cache...
|
|
||||||
Provider.of<ContactInfoState>(context, listen: false).isArchived = true;
|
|
||||||
Provider.of<ProfileInfoState>(context, listen: false).contactList.removeContact(identifier);
|
Provider.of<ProfileInfoState>(context, listen: false).contactList.removeContact(identifier);
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.DeleteContact(profileOnion, identifier);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.DeleteContact(profileOnion, identifier);
|
||||||
Future.delayed(Duration(milliseconds: 500), () {
|
Future.delayed(Duration(milliseconds: 500), () {
|
||||||
|
|
|
@ -167,7 +167,7 @@ class _MessageViewState extends State<MessageView> {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [ChangeNotifierProvider.value(value: Provider.of<ContactInfoState>(context))],
|
providers: [ChangeNotifierProvider.value(value: Provider.of<ContactInfoState>(context)), ChangeNotifierProvider.value(value: Provider.of<ProfileInfoState>(context))],
|
||||||
child: PeerSettingsView(),
|
child: PeerSettingsView(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:ui';
|
||||||
import 'package:cwtch/cwtch_icons_icons.dart';
|
import 'package:cwtch/cwtch_icons_icons.dart';
|
||||||
import 'package:cwtch/models/appstate.dart';
|
import 'package:cwtch/models/appstate.dart';
|
||||||
import 'package:cwtch/models/contact.dart';
|
import 'package:cwtch/models/contact.dart';
|
||||||
|
import 'package:cwtch/models/profile.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:cwtch/widgets/buttontextfield.dart';
|
import 'package:cwtch/widgets/buttontextfield.dart';
|
||||||
import 'package:cwtch/widgets/cwtchlabel.dart';
|
import 'package:cwtch/widgets/cwtchlabel.dart';
|
||||||
|
@ -197,30 +198,46 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
);
|
);
|
||||||
}).toList())),
|
}).toList())),
|
||||||
]),
|
]),
|
||||||
Column(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [
|
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
Tooltip(
|
||||||
|
message: AppLocalizations.of(context)!.archiveConversation,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
||||||
|
var handle = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
||||||
|
// locally update cache...
|
||||||
|
Provider.of<ContactInfoState>(context, listen: false).isArchived = true;
|
||||||
|
Provider.of<FlwtchState>(context, listen: false).cwtch.ArchiveConversation(profileOnion, handle);
|
||||||
|
Future.delayed(Duration(milliseconds: 500), () {
|
||||||
|
Provider.of<AppState>(context, listen: false).selectedConversation = null;
|
||||||
|
Navigator.of(context).popUntil((route) => route.settings.name == "conversations"); // dismiss dialog
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.archive),
|
||||||
|
label: Text(AppLocalizations.of(context)!.archiveConversation),
|
||||||
|
)),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
Row(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, children: [
|
Row(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, children: [
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: AppLocalizations.of(context)!.archiveConversation,
|
message: AppLocalizations.of(context)!.leaveGroup,
|
||||||
child: ElevatedButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
showAlertDialog(context);
|
||||||
var handle = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
|
||||||
// locally update cache...
|
|
||||||
Provider.of<ContactInfoState>(context, listen: false).isArchived = true;
|
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.ArchiveConversation(profileOnion, handle);
|
|
||||||
Future.delayed(Duration(milliseconds: 500), () {
|
|
||||||
Provider.of<AppState>(context, listen: false).selectedConversation = null;
|
|
||||||
Navigator.of(context).popUntil((route) => route.settings.name == "conversations"); // dismiss dialog
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
icon: Icon(CwtchIcons.leave_chat),
|
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.transparent)),
|
||||||
label: Text(AppLocalizations.of(context)!.archiveConversation),
|
icon: Icon(CwtchIcons.leave_group),
|
||||||
|
label: Text(
|
||||||
|
AppLocalizations.of(context)!.leaveGroup,
|
||||||
|
style: TextStyle(decoration: TextDecoration.underline),
|
||||||
|
),
|
||||||
))
|
))
|
||||||
])
|
])
|
||||||
]),
|
])
|
||||||
])))));
|
])))));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -247,8 +264,8 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
||||||
var handle = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
var handle = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
||||||
|
Provider.of<ProfileInfoState>(context).removeContact(handle);
|
||||||
// locally update cache...
|
// locally update cache...
|
||||||
Provider.of<ContactInfoState>(context, listen: false).isArchived = true;
|
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.DeleteContact(profileOnion, handle);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.DeleteContact(profileOnion, handle);
|
||||||
Future.delayed(Duration(milliseconds: 500), () {
|
Future.delayed(Duration(milliseconds: 500), () {
|
||||||
Provider.of<AppState>(context, listen: false).selectedConversation = null;
|
Provider.of<AppState>(context, listen: false).selectedConversation = null;
|
||||||
|
|
|
@ -136,7 +136,7 @@ class _ContactRowState extends State<ContactRow> {
|
||||||
ContactInfoState contact = Provider.of<ContactInfoState>(context, listen: false);
|
ContactInfoState contact = Provider.of<ContactInfoState>(context, listen: false);
|
||||||
if (contact.isGroup == true) {
|
if (contact.isGroup == true) {
|
||||||
// FIXME This flow is incorrect. Groups never just show up on the contact list anymore
|
// FIXME This flow is incorrect. Groups never just show up on the contact list anymore
|
||||||
Provider.of<ProfileInfoState>(context, listen: false).removeContact(contact.onion);
|
Provider.of<ProfileInfoState>(context, listen: false).removeContact(contact.identifier);
|
||||||
} else {
|
} else {
|
||||||
Provider.of<FlwtchState>(context, listen: false).cwtch.BlockContact(Provider.of<ContactInfoState>(context, listen: false).profileOnion, contact.identifier);
|
Provider.of<FlwtchState>(context, listen: false).cwtch.BlockContact(Provider.of<ContactInfoState>(context, listen: false).profileOnion, contact.identifier);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,6 @@ class _CwtchFolderPickerState extends State<CwtchFolderPicker> {
|
||||||
print(e);
|
print(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onChanged: widget.onSave,
|
|
||||||
icon: Icon(Icons.folder),
|
icon: Icon(Icons.folder),
|
||||||
tooltip: widget.tooltip,
|
tooltip: widget.tooltip,
|
||||||
)));
|
)));
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:cwtch/models/appstate.dart';
|
import 'package:cwtch/models/appstate.dart';
|
||||||
import 'package:cwtch/models/contactlist.dart';
|
import 'package:cwtch/models/contactlist.dart';
|
||||||
import 'package:cwtch/models/profile.dart';
|
import 'package:cwtch/models/profile.dart';
|
||||||
import 'package:cwtch/models/profilelist.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:cwtch/views/addeditprofileview.dart';
|
import 'package:cwtch/views/addeditprofileview.dart';
|
||||||
|
@ -34,7 +33,7 @@ class _ProfileRowState extends State<ProfileRow> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(6.0), //border size
|
padding: const EdgeInsets.all(6.0), //border size
|
||||||
child: ProfileImage(
|
child: ProfileImage(
|
||||||
badgeCount: profile.unreadMessages,
|
badgeCount: 0,
|
||||||
badgeColor: Provider.of<Settings>(context).theme.portraitProfileBadgeColor,
|
badgeColor: Provider.of<Settings>(context).theme.portraitProfileBadgeColor,
|
||||||
badgeTextColor: Provider.of<Settings>(context).theme.portraitProfileBadgeTextColor,
|
badgeTextColor: Provider.of<Settings>(context).theme.portraitProfileBadgeTextColor,
|
||||||
diameter: 64.0,
|
diameter: 64.0,
|
||||||
|
|
|
@ -8,7 +8,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({required this.controller, this.hintText = "", this.validator, this.autofocus = false, this.onChanged = doNothing, this.number = false, this.multiLine = false, this.key, this.testKey});
|
CwtchTextField({required this.controller, this.hintText = "", this.validator, this.autofocus = false, this.onChanged = doNothing, this.number = false, this.multiLine = false, this.key});
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final String hintText;
|
final String hintText;
|
||||||
final FormFieldValidator? validator;
|
final FormFieldValidator? validator;
|
||||||
|
@ -17,7 +17,6 @@ class CwtchTextField extends StatefulWidget {
|
||||||
final bool multiLine;
|
final bool multiLine;
|
||||||
final bool number;
|
final bool number;
|
||||||
final Key? key;
|
final Key? key;
|
||||||
final Key? testKey;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_CwtchTextFieldState createState() => _CwtchTextFieldState();
|
_CwtchTextFieldState createState() => _CwtchTextFieldState();
|
||||||
|
@ -42,7 +41,6 @@ class _CwtchTextFieldState extends State<CwtchTextField> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Consumer<Settings>(builder: (context, theme, child) {
|
return Consumer<Settings>(builder: (context, theme, child) {
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
key: widget.testKey,
|
|
||||||
controller: widget.controller,
|
controller: widget.controller,
|
||||||
validator: widget.validator,
|
validator: widget.validator,
|
||||||
onChanged: widget.onChanged,
|
onChanged: widget.onChanged,
|
||||||
|
|
Loading…
Reference in New Issue