profile level unread notifications and in profile other profile unread notifications

This commit is contained in:
Dan Ballard 2022-01-25 17:37:51 -05:00
parent ca03ddbc53
commit a82ade8663
8 changed files with 80 additions and 11 deletions

View File

@ -65,8 +65,8 @@ android {
release { release {
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
// signingConfig signingConfigs.debug signingConfig signingConfigs.debug
signingConfig signingConfigs.release // signingConfig signingConfigs.release
} }
} }

View File

@ -8,6 +8,7 @@ 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';
@ -145,9 +146,10 @@ 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 selectedConversation = appState.selectedProfile == data["ProfileOnion"] && appState.selectedConversation == identifier; var selectedProfile = appState.selectedProfile == data["ProfileOnion"];
var selectedConversation = selectedProfile && appState.selectedConversation == identifier;
profileCN.getProfile(data["ProfileOnion"])?.contactList.newMessage( profileCN.getProfile(data["ProfileOnion"])?.newMessage(
identifier, identifier,
messageID, messageID,
timestamp, timestamp,
@ -156,9 +158,10 @@ 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...
@ -198,7 +201,8 @@ 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 selectedConversation = appState.selectedProfile == data["ProfileOnion"] && appState.selectedConversation == identifier; var selectedProfile = appState.selectedProfile == data["ProfileOnion"];
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) {
@ -212,9 +216,10 @@ 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"])?.contactList.newMessage(identifier, idx, timestampSent, senderHandle, senderImage, isAuto, data["Data"], contenthash, selectedConversation); profileCN.getProfile(data["ProfileOnion"])?.newMessage(identifier, idx, timestampSent, senderHandle, senderImage, isAuto, data["Data"], contenthash, selectedProfile, 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);

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
enum ModalState { none, storageMigration } enum ModalState { none, storageMigration }
@ -16,6 +18,13 @@ 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();
@ -82,4 +91,12 @@ 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;
}
} }

View File

@ -173,6 +173,24 @@ class ProfileInfoState extends ChangeNotifier {
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();

View File

@ -27,4 +27,8 @@ 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);
} }

View File

@ -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 => mauvePurple; get portraitProfileBadgeColor => hotPink;
get portraitProfileBadgeTextColor => darkGreyPurple; get portraitProfileBadgeTextColor => whiteishPurple;
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 => brightPurple; get portraitProfileBadgeColor => accent;
get portraitProfileBadgeTextColor => whitePurple; get portraitProfileBadgeTextColor => whitePurple;
get dropShadowColor => purple; get dropShadowColor => purple;
get toolbarIconColor => settings; //darkPurple; get toolbarIconColor => settings; //darkPurple;

View File

@ -76,6 +76,30 @@ 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<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(

View File

@ -33,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: 0, badgeCount: profile.unreadMessages,
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,
@ -83,6 +83,7 @@ class _ProfileRowState extends State<ProfileRow> {
} }
void _pushContactList(ProfileInfoState profile, bool isLandscape) { void _pushContactList(ProfileInfoState profile, bool isLandscape) {
Provider.of<ProfileInfoState>(context, listen: false).unreadMessages = 0;
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute<void>( MaterialPageRoute<void>(
settings: RouteSettings(name: "conversations"), settings: RouteSettings(name: "conversations"),