Compare commits

...

2 Commits

Author SHA1 Message Date
erinn 211e388a7d Merge pull request 'fix contacts sort up on send msg; profile list shows unread;' (#460) from dan/ui:unread into master
the build was successful Details
Reviewed-on: #460
2020-12-17 01:00:56 -08:00
Dan Ballard dc3872fc8a fix contacts sort up on send msg; profile list shows unread; approved
the build was successful Details
contacts sort on approved time
2020-12-17 00:09:28 -08:00
10 changed files with 128 additions and 39 deletions

View File

@ -6,6 +6,8 @@ const Name = "name"
const LastRead = "last-read"
const Picture = "picture"
const ShowBlocked = "show-blocked"
const UnreadMsgCount = "unread-message-count"
const ApprovedTime = "approved-time"
const ProfileTypeV1DefaultPassword = "v1-defaultPassword"
const ProfileTypeV1Password = "v1-userPassword"

View File

@ -64,9 +64,8 @@ func PeerHandler(onion string, uiManager ui.Manager, subscribed chan bool) {
case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetOnion(), hex.EncodeToString([]byte(e.Data[event.Signature])), ts, true)
case event.NewGroup:
group := peer.GetGroup( e.Data[event.GroupID])
group := peer.GetGroup(e.Data[event.GroupID])
if group != nil {
uiManager.AddContact(e.Data[event.GroupID])
}

View File

@ -58,18 +58,18 @@ type GrandCentralDispatcher struct {
_ func(pant int) `signal:"ChangeRootPane"`
_ func(pane int) `signal:"ChangeProfilePane"`
// profile management stuff
_ func() `signal:"Loaded"`
_ func(handle, displayname, image, tag string, online bool) `signal:"AddProfile"`
_ func() `signal:"ErrorLoaded0"`
_ func() `signal:"ResetProfile"`
_ func() `signal:"ResetProfileList"`
_ func(failed bool) `signal:"ChangePasswordResponse"`
_ func(onion string, online bool) `signal:"UpdateProfileNetworkStatus"`
_ func(onion string) `signal:"Notify"`
_ func() `signal:"Loaded"`
_ func(handle, displayname, image, tag string, unread int, online bool) `signal:"AddProfile"`
_ func() `signal:"ErrorLoaded0"`
_ func() `signal:"ResetProfile"`
_ func() `signal:"ResetProfileList"`
_ func(failed bool) `signal:"ChangePasswordResponse"`
_ func(onion string, online bool) `signal:"UpdateProfileNetworkStatus"`
_ func(onion string) `signal:"Notify"`
// Group Creation
_ func(servers []string) `signal:"SupplyPeeredServers"`
_ func() `signal:"requestPeeredServers,auto"`
_ func(servers []string) `signal:"SupplyPeeredServers"`
_ func() `signal:"requestPeeredServers,auto"`
// server management
_ func(handle, displayname, image string, status int, autostart bool, bundle string, messages int, key_types []string, keys []string) `signal:"AddServer"`
@ -85,7 +85,7 @@ type GrandCentralDispatcher struct {
_ func(handle, displayName string) `signal:"UpdateContactDisplayName"`
_ func(handle, image string) `signal:"UpdateContactPicture"`
_ func(handle string, status int, loading bool) `signal:"UpdateContactStatus"`
_ func(handle string) `signal:"IncContactUnreadCount"`
_ func(profile, contact string) `signal:"IncContactMessageCount"`
_ func(handle string) `signal:"RemoveContact"`
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
@ -127,7 +127,7 @@ type GrandCentralDispatcher struct {
_ func(onion string) `signal:"loadMessagesPane,auto"`
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
_ func(name, address string) `signal:"addPeer,auto"`
_ func(address string) `signal:"addGroup,auto"`
_ func(address string) `signal:"addGroup,auto"`
_ func(str string) `signal:"createContact,auto"`
_ func(str string) `signal:"popup,auto"`
_ func(server, groupName string) `signal:"createGroup,auto"`
@ -152,7 +152,7 @@ type GrandCentralDispatcher struct {
_ func() `constructor:"init"`
// legacy overlay model support
_ func(onion string) `signal:"legacyLoadOverlay,auto"`
_ func(onion string) `signal:"legacyLoadOverlay,auto"`
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts int64, ackd bool, error bool) `signal:"AppendMessage"`
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts int64, ackd bool, error bool) `signal:"PrependMessage"`
}
@ -323,7 +323,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string) {
the.Peer.SendMessageToPeer(this.SelectedConversation(), message)
this.TimelineInterface.RequestEIR()
}
this.IncContactMessageCount(this.SelectedProfile(), this.SelectedConversation())
}
func (this *GrandCentralDispatcher) loadMessagesPane(handle string) {
@ -378,7 +378,7 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
func (this *GrandCentralDispatcher) legacyLoadOverlay(handle string) {
// only do this for overlays 2 (bulletin) and 4 (lists)
go this.legacyLoadOverlay_helper(handle, []int{2,4})
go this.legacyLoadOverlay_helper(handle, []int{2, 4})
}
func contains(arr []int, x int) bool {
@ -424,7 +424,7 @@ func (this *GrandCentralDispatcher) legacyLoadOverlay_helper(handle string, over
}
}
} else {// !isGroup
} else { // !isGroup
messages := the.CwtchApp.GetPeer(this.selectedProfile()).GetContact(handle).Timeline.GetMessages()
for i := len(messages) - 1; i >= 0; i-- {
from := messages[i].PeerID
@ -669,6 +669,8 @@ func (this *GrandCentralDispatcher) addPeer(name, address string) {
if name != "" {
the.Peer.SetContactAttribute(address, attr.GetLocalScope(constants.Name), name)
}
the.Peer.SetContactAttribute(address, attr.GetLocalScope(constants.ApprovedTime), strconv.Itoa(int(time.Now().Unix())))
the.Peer.PeerWithOnion(address)
}
@ -700,6 +702,8 @@ func (this *GrandCentralDispatcher) createGroup(server, groupName string) {
the.Peer.SetGroupAttribute(groupID, attr.GetLocalScope(constants.Name), groupName)
the.Peer.JoinServer(server)
the.Peer.SetGroupAttribute(server, attr.GetLocalScope(constants.ApprovedTime), strconv.Itoa(int(time.Now().Unix())))
this.GetUiManager(this.selectedProfile()).AddContact(groupID)
}
@ -711,10 +715,11 @@ func (this *GrandCentralDispatcher) setPeerAuthorization(onion string, authoriza
return
}
this.RemoveContact(onion)
this.GetUiManager(this.selectedProfile()).AddContact(onion)
if model.Authorization(authorization) == model.AuthApproved {
the.Peer.SetContactAttribute(onion, attr.GetLocalScope(constants.ApprovedTime), strconv.Itoa(int(time.Now().Unix())))
the.Peer.PeerWithOnion(onion)
}
this.GetUiManager(this.selectedProfile()).AddContact(onion)
}
func (this *GrandCentralDispatcher) inviteToGroup(onion, groupID string) {
@ -898,6 +903,7 @@ func (this *GrandCentralDispatcher) loadProfile(onion string) {
}
}
}
the.Peer.SetAttribute(attr.GetSettingsScope(constants.UnreadMsgCount), "0")
}
func (this *GrandCentralDispatcher) createProfile(nick string, defaultPass bool, password string) {

View File

@ -11,6 +11,7 @@ import (
"cwtch.im/ui/go/the"
"git.openprivacy.ca/openprivacy/log"
"runtime/debug"
"strconv"
"strings"
"time"
)
@ -190,8 +191,11 @@ func AddProfile(gcd *GrandCentralDispatcher, handle string) {
online, _ := p.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
log.Debugf("AddProfile %v %v %v %v %v\n", handle, nick, picPath, tag, online)
gcd.AddProfile(handle, nick, picPath, tag, online == event.True)
unreadStr, _ := p.GetAttribute(attr.GetSettingsScope(constants.UnreadMsgCount))
unread, _ := strconv.Atoi(unreadStr)
log.Debugf("AddProfile %v %v %v %v %v %v\n", handle, nick, picPath, tag, unread, online)
gcd.AddProfile(handle, nick, picPath, tag, unread, online == event.True)
}
}
@ -241,6 +245,26 @@ func (this *manager) Acknowledge(handle, mID string) {
})
}
func getContactLastMessageTime(contact *model.PublicProfile) int {
time := getLastMessageTime(&contact.Timeline)
if time == 0 {
approvedTimeStr, _ := contact.GetAttribute(attr.GetLocalScope(constants.ApprovedTime))
time, _ = strconv.Atoi(approvedTimeStr)
}
return time
}
func getGroupLastMessageTime(group *model.Group) int {
time := getLastMessageTime(&group.Timeline)
if time == 0 {
approvedTimeStr, _ := group.GetAttribute(attr.GetLocalScope(constants.ApprovedTime))
time, _ = strconv.Atoi(approvedTimeStr)
}
return time
}
func getLastMessageTime(tl *model.Timeline) int {
if len(tl.Messages) == 0 {
return 0
@ -260,7 +284,7 @@ func (this *manager) AddContact(handle string) {
unread := countUnread(group.Timeline.GetMessages(), lastRead)
picture := GetProfilePic(handle)
this.gcd.AddContact(handle, GetNick(handle), picture, unread, int(connections.ConnectionStateToType[group.State]), string(model.AuthApproved), false, getLastMessageTime(&group.Timeline))
this.gcd.AddContact(handle, GetNick(handle), picture, unread, int(connections.ConnectionStateToType[group.State]), string(model.AuthApproved), false, getGroupLastMessageTime(group))
}
return
} else if !isPeer(handle) {
@ -275,7 +299,7 @@ func (this *manager) AddContact(handle string) {
unread := countUnread(contact.Timeline.GetMessages(), lastRead)
picture := GetProfilePic(handle)
this.gcd.AddContact(handle, GetNick(handle), picture, unread, int(connections.ConnectionStateToType[contact.State]), string(contact.Authorization), false, getLastMessageTime(&contact.Timeline))
this.gcd.AddContact(handle, GetNick(handle), picture, unread, int(connections.ConnectionStateToType[contact.State]), string(contact.Authorization), false, getContactLastMessageTime(contact))
}
})
}
@ -303,8 +327,11 @@ func (this *manager) MessageJustAdded() {
func (this *manager) StoreAndNotify(pere peer.CwtchPeer, onion string, messageTxt string, sent time.Time, profileOnion string) {
// Send a New Message from Peer Notification
// Android
this.gcd.AndroidCwtchActivity.SetChannel(onion)
this.gcd.AndroidCwtchActivity.NotificationChanged("New Message from Peer")
// Desktop
this.gcd.Notify(onion)
this.gcd.DoIfProfileElse(this.profile, func() {
this.gcd.DoIfConversationElse(onion, func() {
@ -315,16 +342,16 @@ func (this *manager) StoreAndNotify(pere peer.CwtchPeer, onion string, messageTx
}, func() {
pere.StoreMessage(onion, messageTxt, sent)
})
this.gcd.IncContactUnreadCount(onion)
}, func() {
the.CwtchApp.GetPeer(profileOnion).StoreMessage(onion, messageTxt, sent)
this.incUnreadMsgCount()
})
this.gcd.Notify(onion)
this.gcd.IncContactMessageCount(this.profile, onion)
}
// AddMessage adds a message to the message pane for the supplied conversation if it is active
func (this *manager) AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool) {
this.gcd.DoIfProfile(this.profile, func() {
this.gcd.DoIfProfileElse(this.profile, func() {
this.gcd.DoIfConversation(handle, func() {
updateLastReadTime(handle)
// If the message is not from the user then add it, otherwise, just acknowledge.
@ -335,11 +362,14 @@ func (this *manager) AddMessage(handle string, from string, message string, from
this.gcd.Acknowledged(messageID)
}
})
this.gcd.IncContactUnreadCount(handle)
}, func() {
this.incUnreadMsgCount()
})
if !fromMe {
this.gcd.Notify(handle)
}
this.gcd.IncContactMessageCount(this.profile, handle)
}
func (this *manager) ReloadProfiles() {
@ -381,3 +411,15 @@ func (this *manager) ChangePasswordResponse(error bool) {
func (this *manager) UpdateNetworkStatus(online bool) {
this.gcd.UpdateProfileNetworkStatus(this.profile, online)
}
func (this *manager) incUnreadMsgCount() {
peer := the.CwtchApp.GetPeer(this.profile)
if peer != nil {
unreadMsgCountStr, _ := peer.GetAttribute(attr.GetSettingsScope(constants.UnreadMsgCount))
unreadMsgCount, err := strconv.Atoi(unreadMsgCountStr)
if err != nil {
unreadMsgCount = 0
}
peer.SetAttribute(attr.GetSettingsScope(constants.UnreadMsgCount), strconv.Itoa(unreadMsgCount+1))
}
}

View File

@ -428,7 +428,11 @@ ApplicationWindow {
// Until then I am leaving this here for documentation.
// androidCwtchActivity.channel = onion
// androidCwtchActivity.notification = "Message from " + onion;
// Basic Desktop notification
windowItem.alert(0)
}
}
Component.onCompleted: Mutant.standard.imagePath = gcd.assetPath;

View File

@ -22,12 +22,6 @@ W.Overlay {
target: mm
onRowsInserted: {
if (messagesListView.atYEnd) thymer.running = true
//todo: this won't fire for non-active convos
windowItem.alert(0)
if (gcd.os == "android" && windowItem.activeFocusItem == null) {
androidCwtchActivity.notification = "New Content"
}
}
}

View File

@ -124,7 +124,6 @@ ColumnLayout {
"_status": status,
"_authorization": authorization,
"_loading": loading,
"_loading": loading,
"_lastMsgTs": lastMsgTs,
}
@ -138,7 +137,7 @@ ColumnLayout {
}
}
onIncContactUnreadCount: function(handle) {
/*onIncContactUnreadCount: function(handle) {
var ts = Math.round((new Date()).getTime() / 1000);
for(var i = 0; i < contactsModel.count; i++){
if(contactsModel.get(i)["_handle"] == handle) {
@ -147,6 +146,19 @@ ColumnLayout {
contactsModel.move(i, 0, 1)
}
}
}*/
onIncContactMessageCount: function(profile, handle) {
if (profile == gcd.selectedProfile) {
var ts = Math.round((new Date()).getTime() / 1000);
for(var i = 0; i < contactsModel.count; i++){
if(contactsModel.get(i)["_handle"] == handle) {
var contact = contactsModel.get(i)
contact["_lastMsgTs"] = ts
contactsModel.move(i, 0, 1)
}
}
}
}
onResetProfile: function() {

View File

@ -148,8 +148,8 @@ Opaque.PortraitRow {
}
}
onIncContactUnreadCount: function(_handle) {
if (handle == _handle && gcd.selectedConversation != handle) {
onIncContactMessageCount: function(_profile, _handle) {
if (_profile == gcd.selectedProfile && handle == _handle && gcd.selectedConversation != handle) {
badge++
}
}

View File

@ -36,7 +36,7 @@ ColumnLayout {
Connections { // ADD/REMOVE CONTACT ENTRIES
target: gcd
onAddProfile: function(handle, displayName, image, tag, online) {
onAddProfile: function(handle, displayName, image, tag, unread, online) {
// don't add duplicates
for (var i = 0; i < profilesModel.count; i++) {
@ -61,6 +61,7 @@ ColumnLayout {
_image: image,
_tag: tag,
_online: online,
_unread: unread,
})
}
@ -92,6 +93,7 @@ ColumnLayout {
displayName: _displayName
image: _image
tag: _tag
unread: _unread
Layout.fillWidth: true
profileOnline: _online
rowClicked: function(handle) {

View File

@ -23,6 +23,7 @@ RowLayout {
property var rowClicked: {}
property var editClicked: {}
property bool profileOnline: false
property int unread: 0
Opaque.PortraitRow {
id: prow
@ -44,7 +45,28 @@ RowLayout {
hilightBackgroundColor: prow.badgeColor
}
onClicked: rowClicked(handle)
Opaque.Badge {
id: unreadBadge
visible: unread > 0
color: Theme.portraitContactBadgeColor
size: parent.height/4
anchors.right: parent.right
anchors.rightMargin: 25 * gcd.themeScale
anchors.leftMargin: 1 * gcd.themeScale
anchors.verticalCenter: parent.verticalCenter
content: Label {
id: lblUnread
color: Theme.portraitContactBadgeTextColor
font.pixelSize: Theme.badgeTextSize * gcd.themeScale
font.weight: Font.Bold
text: unread > 99 ? "99+" : unread
}
}
onClicked: { unread = 0; rowClicked(handle) }
function updateStatus() {
if (gcd.torStatus != Const.statusOnline) { // Tor network offline
@ -84,6 +106,12 @@ RowLayout {
prow.updateStatus()
}
}
onIncContactMessageCount: function(_profile, _handle) {
if (_profile == handle) {
unread++
}
}
}
Connections {