Merge pull request 'properly handle NewPeer event as per qt ui' (#5) from newPeer into trunk
Reviewed-on: #5
This commit is contained in:
commit
69ba341c82
|
@ -0,0 +1,23 @@
|
|||
package constants
|
||||
|
||||
const SchemaVersion = "schemaVersion"
|
||||
|
||||
const Name = "name"
|
||||
const LastRead = "last-read"
|
||||
const Picture = "picture"
|
||||
const ShowBlocked = "show-blocked"
|
||||
|
||||
const ProfileTypeV1DefaultPassword = "v1-defaultPassword"
|
||||
const ProfileTypeV1Password = "v1-userPassword"
|
||||
|
||||
// PeerOnline stores state on if the peer believes it is online
|
||||
const PeerOnline = "peer-online"
|
||||
|
||||
const StateProfilePane = "state-profile-pane"
|
||||
const StateSelectedConversation = "state-selected-conversation"
|
||||
const StateSelectedProfileTime = "state-selected-profile-time"
|
||||
|
||||
// Settings
|
||||
const BlockUnknownPeersSetting = "blockunknownpeers"
|
||||
const LocaleSetting = "locale"
|
||||
const ZoomSetting = "zoom"
|
|
@ -0,0 +1,26 @@
|
|||
package constants
|
||||
|
||||
import "cwtch.im/cwtch/event"
|
||||
|
||||
// The server manager defines its own events, most should be self-explanatory:
|
||||
const (
|
||||
NewServer = event.Type("NewServer")
|
||||
|
||||
// Force a UI update
|
||||
ListServers = event.Type("ListServers")
|
||||
|
||||
// Takes an Onion, used to toggle off/on Server availability
|
||||
StartServer = event.Type("StartServer")
|
||||
StopServer = event.Type("StopServer")
|
||||
|
||||
// Takes an Onion and a AutoStartEnabled boolean
|
||||
AutoStart = event.Type("AutoStart")
|
||||
|
||||
// Get the status of a particular server (takes an Onion)
|
||||
CheckServerStatus = event.Type("CheckServerStatus")
|
||||
ServerStatusUpdate = event.Type("ServerStatusUpdate")
|
||||
)
|
||||
|
||||
const (
|
||||
AutoStartEnabled = event.Field("AutoStartEnabled")
|
||||
)
|
79
lib.go
79
lib.go
|
@ -1,5 +1,5 @@
|
|||
package cwtch
|
||||
//package main
|
||||
//package cwtch
|
||||
package main
|
||||
|
||||
import "C"
|
||||
import (
|
||||
|
@ -7,8 +7,13 @@ import (
|
|||
"cwtch.im/cwtch/app"
|
||||
"cwtch.im/cwtch/event"
|
||||
"cwtch.im/cwtch/peer"
|
||||
"cwtch.im/cwtch/model/attr"
|
||||
"cwtch.im/cwtch/app/plugins"
|
||||
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.openprivacy.ca/flutter/libcwtch-go/constants"
|
||||
"git.openprivacy.ca/flutter/libcwtch-go/utils"
|
||||
|
||||
"encoding/base64"
|
||||
"git.openprivacy.ca/openprivacy/connectivity/tor"
|
||||
|
@ -22,6 +27,7 @@ import (
|
|||
|
||||
var application app.Application
|
||||
var appBusQueue event.Queue
|
||||
var profileRepaintQueue event.Queue
|
||||
var acnQueue event.Queue
|
||||
var contactEventsQueue event.Queue
|
||||
|
||||
|
@ -81,6 +87,10 @@ func StartCwtch(appDir string, torPath string) {
|
|||
event.NewGetValMessageFromPeer,
|
||||
event.PeerStateChange,
|
||||
}
|
||||
|
||||
profileRepaintQueue = event.NewQueue()
|
||||
newApp.GetPrimaryBus().Subscribe(event.NewPeer, profileRepaintQueue)
|
||||
|
||||
newApp.LoadProfiles("be gay do crime")
|
||||
newApp.LaunchPeers()
|
||||
application = newApp
|
||||
|
@ -101,8 +111,8 @@ func ACNEvents() string {
|
|||
}
|
||||
}
|
||||
|
||||
//export c_AppBusEvent
|
||||
func c_AppBusEvent() *C.char {
|
||||
//export c_GetAppBusEvent
|
||||
func c_GetAppBusEvent() *C.char {
|
||||
return C.CString(GetAppBusEvent())
|
||||
}
|
||||
|
||||
|
@ -111,13 +121,62 @@ func c_AppBusEvent() *C.char {
|
|||
func GetAppBusEvent() string {
|
||||
e := appBusQueue.Next()
|
||||
if e.EventType == event.NewPeer {
|
||||
e.Data[event.ProfileName] = "orb Quen"
|
||||
e.Data[event.Path] = "profiles/044-witch.png"
|
||||
//e.Data[event.ProfileName] = "orb Quen"
|
||||
//e.Data[event.Path] = "profiles/044-witch.png"
|
||||
onion := e.Data[event.Identity]
|
||||
profile := application.GetPeer(e.Data[event.Identity])
|
||||
|
||||
if e.Data[event.Created] == event.True {
|
||||
profile.SetAttribute(attr.GetPublicScope(constants.Name), profile.GetName())
|
||||
profile.SetAttribute(attr.GetPublicScope(constants.Picture), utils.ImageToString(utils.NewImage(utils.RandomProfileImage(onion), utils.TypeImageDistro)))
|
||||
}
|
||||
if e.Data[event.Status] != event.StorageRunning || e.Data[event.Created] == event.True {
|
||||
profile.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
|
||||
application.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
|
||||
application.AddPeerPlugin(onion, plugins.NETWORKCHECK)
|
||||
}
|
||||
|
||||
nick, exists := profile.GetAttribute(attr.GetPublicScope(constants.Name))
|
||||
if !exists {
|
||||
nick = onion
|
||||
}
|
||||
|
||||
picVal, ok := profile.GetAttribute(attr.GetPublicScope(constants.Picture))
|
||||
if !ok {
|
||||
picVal = utils.ImageToString(utils.NewImage(utils.RandomProfileImage(onion), utils.TypeImageDistro))
|
||||
}
|
||||
pic, err := utils.StringToImage(picVal)
|
||||
if err != nil {
|
||||
pic = utils.NewImage(utils.RandomProfileImage(onion), utils.TypeImageDistro)
|
||||
}
|
||||
picPath := utils.GetPicturePath(pic)
|
||||
|
||||
//tag, _ := profile.GetAttribute(app.AttributeTag)
|
||||
|
||||
online, _ := profile.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
|
||||
|
||||
e.Data[constants.Name] = nick
|
||||
e.Data[constants.Picture] = picPath
|
||||
e.Data["Online"] = online
|
||||
}
|
||||
ba, _ := json.Marshal(e)
|
||||
return string(ba)
|
||||
}
|
||||
|
||||
//export c_GetProfileRepaintEvent
|
||||
func c_GetProfileRepaintEvent() int8 {
|
||||
if GetProfileRepaintEvent() {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func GetProfileRepaintEvent() bool {
|
||||
<- acnQueue.OutChan()
|
||||
return true
|
||||
}
|
||||
|
||||
type Profile struct {
|
||||
Name string `json:"name"`
|
||||
Onion string `json:"onion"`
|
||||
|
@ -157,7 +216,7 @@ func c_GetContacts(onion_ptr *C.char, onion_len C.int) *C.char {
|
|||
return C.CString(GetContacts(C.GoStringN(onion_ptr, onion_len)))
|
||||
}
|
||||
|
||||
func GetContacts(onion string)string {
|
||||
func GetContacts(onion string) string {
|
||||
log.Infof("Get Contacts for %v", onion)
|
||||
mypeer := application.GetPeer(onion)
|
||||
|
||||
|
@ -220,10 +279,10 @@ func ContactEvents() string {
|
|||
}
|
||||
|
||||
//export c_NumMessages
|
||||
func c_NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n C.int) {
|
||||
func c_NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n int) {
|
||||
profile := C.GoStringN(profile_ptr, profile_len)
|
||||
handle := C.GoStringN(handle_ptr, handle_len)
|
||||
return C.int(NumMessages(profile, handle))
|
||||
return (NumMessages(profile, handle))
|
||||
}
|
||||
|
||||
func NumMessages(profile, handle string) (n int) {
|
||||
|
@ -261,4 +320,4 @@ func GetMessages(profile, handle string, start, end int) string {
|
|||
}
|
||||
|
||||
// Leave as is, needed by ffi
|
||||
//func main() {}
|
||||
func main() {}
|
|
@ -0,0 +1,34 @@
|
|||
package utils
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// Image types we support
|
||||
const (
|
||||
// TypeImageDistro is a reletive path to any of the distributed images in cwtch/ui in the assets folder
|
||||
TypeImageDistro = "distro"
|
||||
// TypeImageComposition will be an face image composed of a recipe of parts like faceType, eyeType, etc
|
||||
TypeImageComposition = "composition"
|
||||
)
|
||||
|
||||
type image struct {
|
||||
Val string
|
||||
T string
|
||||
}
|
||||
|
||||
func NewImage(val, t string) *image {
|
||||
return &image{val, t}
|
||||
}
|
||||
|
||||
func StringToImage(str string) (*image, error) {
|
||||
var img image
|
||||
err := json.Unmarshal([]byte(str), &img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &img, nil
|
||||
}
|
||||
|
||||
func ImageToString(img *image) string {
|
||||
bytes, _ := json.Marshal(img)
|
||||
return string(bytes)
|
||||
}
|
|
@ -0,0 +1,388 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"cwtch.im/cwtch/model"
|
||||
"cwtch.im/cwtch/model/attr"
|
||||
"cwtch.im/cwtch/peer"
|
||||
"git.openprivacy.ca/flutter/libcwtch-go/constants"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PeerHelper struct {
|
||||
peer peer.CwtchPeer
|
||||
}
|
||||
|
||||
func NewPeerHelper(profile peer.CwtchPeer) *PeerHelper {
|
||||
return &PeerHelper{profile}
|
||||
}
|
||||
|
||||
func (p *PeerHelper) IsGroup( id string) bool {
|
||||
return len(id) == 32 && !p.IsServer(id)
|
||||
}
|
||||
|
||||
func (p *PeerHelper) IsPeer(id string) bool {
|
||||
return len(id) == 56 && !p.IsServer(id)
|
||||
}
|
||||
|
||||
// Check if the id is associated with a contact with a KeyTypeServerOnion attribute (which indicates that this
|
||||
// is a server, not a regular contact or a group
|
||||
func (p *PeerHelper) IsServer(id string) bool {
|
||||
_, ok := p.peer.GetContactAttribute(id, string(model.KeyTypeServerOnion))
|
||||
return ok
|
||||
}
|
||||
|
||||
/*
|
||||
func getOrDefault(id, key string, defaultVal string) string {
|
||||
var val string
|
||||
var ok bool
|
||||
if IsGroup(id) {
|
||||
val, ok = the.Peer.GetGroupAttribute(id, key)
|
||||
} else {
|
||||
val, ok = the.Peer.GetContactAttribute(id, key)
|
||||
}
|
||||
if ok {
|
||||
return val
|
||||
} else {
|
||||
return defaultVal
|
||||
}
|
||||
}*/
|
||||
|
||||
func (p *PeerHelper) GetWithSetDefault(id string, key string, defaultVal string) string {
|
||||
var val string
|
||||
var ok bool
|
||||
if p.IsGroup(id) {
|
||||
val, ok = p.peer.GetGroupAttribute(id, key)
|
||||
} else {
|
||||
val, ok = p.peer.GetContactAttribute(id, key)
|
||||
}
|
||||
if !ok {
|
||||
val = defaultVal
|
||||
if p.IsGroup(id) {
|
||||
p.peer.SetGroupAttribute(id, key, defaultVal)
|
||||
} else {
|
||||
p.peer.SetContactAttribute(id, key, defaultVal)
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (p *PeerHelper) GetNick(id string) string {
|
||||
if p.IsGroup(id) {
|
||||
nick, exists := p.peer.GetGroupAttribute(id, attr.GetLocalScope(constants.Name))
|
||||
if !exists || nick == "" || nick == id {
|
||||
nick, exists = p.peer.GetGroupAttribute(id, attr.GetPeerScope(constants.Name))
|
||||
if !exists {
|
||||
nick = "[" + id + "]"
|
||||
}
|
||||
}
|
||||
return nick
|
||||
} else {
|
||||
nick, exists := p.peer.GetContactAttribute(id, attr.GetLocalScope(constants.Name))
|
||||
if !exists || nick == "" || nick == id {
|
||||
nick, exists = p.peer.GetContactAttribute(id, attr.GetPeerScope(constants.Name))
|
||||
if !exists {
|
||||
nick = "[" + id + "]"
|
||||
}
|
||||
}
|
||||
return nick
|
||||
}
|
||||
}
|
||||
|
||||
// InitLastReadTime checks and gets the Attributable's LastRead time or sets it to now
|
||||
func (p *PeerHelper) InitLastReadTime(id string) time.Time {
|
||||
nowStr, _ := time.Now().MarshalText()
|
||||
lastReadAttr := p.GetWithSetDefault(id, attr.GetLocalScope(constants.LastRead), string(nowStr))
|
||||
var lastRead time.Time
|
||||
lastRead.UnmarshalText([]byte(lastReadAttr))
|
||||
return lastRead
|
||||
}
|
||||
|
||||
// GetProfilePic returns a string path to an image to display for hte given peer/group id
|
||||
func (p *PeerHelper) GetProfilePic(id string) string {
|
||||
if p.IsGroup(id) {
|
||||
if picVal, exists := p.peer.GetGroupAttribute(id, attr.GetLocalScope(constants.Picture)); exists {
|
||||
pic, err := StringToImage(picVal)
|
||||
if err == nil {
|
||||
return GetPicturePath(pic)
|
||||
}
|
||||
}
|
||||
if picVal, exists := p.peer.GetGroupAttribute(id, attr.GetPeerScope(constants.Picture)); exists {
|
||||
pic, err := StringToImage(picVal)
|
||||
if err == nil {
|
||||
return GetPicturePath(pic)
|
||||
}
|
||||
}
|
||||
return GetPicturePath(NewImage(RandomGroupImage(id), TypeImageDistro))
|
||||
|
||||
} else {
|
||||
if picVal, exists := p.peer.GetContactAttribute(id, attr.GetLocalScope(constants.Picture)); exists {
|
||||
pic, err := StringToImage(picVal)
|
||||
if err == nil {
|
||||
return GetPicturePath(pic)
|
||||
}
|
||||
}
|
||||
if picVal, exists := p.peer.GetContactAttribute(id, attr.GetPeerScope(constants.Picture)); exists {
|
||||
pic, err := StringToImage(picVal)
|
||||
if err == nil {
|
||||
return GetPicturePath(pic)
|
||||
}
|
||||
}
|
||||
return RandomProfileImage(id)
|
||||
}
|
||||
}
|
||||
|
||||
// a lot of pics were stored full path + uri. remove all this to the relative path in images/
|
||||
// fix for storing full paths introduced 2019.12
|
||||
func profilePicRelativize(filename string) string {
|
||||
parts := strings.Split(filename, "qml/images")
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
|
||||
func GetPicturePath(pic *image) string {
|
||||
switch pic.T {
|
||||
case TypeImageDistro:
|
||||
return profilePicRelativize(pic.Val)
|
||||
default:
|
||||
log.Errorf("Unhandled profile picture type of %v\n", pic.T)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PeerHelper) updateLastReadTime(id string) {
|
||||
lastRead, _ := time.Now().MarshalText()
|
||||
if p.IsGroup(id) {
|
||||
p.peer.SetGroupAttribute(id, attr.GetLocalScope(constants.LastRead), string(lastRead))
|
||||
} else {
|
||||
p.peer.SetContactAttribute(id, attr.GetLocalScope(constants.LastRead), string(lastRead))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PeerHelper) CountUnread(messages []model.Message, lastRead time.Time) int {
|
||||
count := 0
|
||||
for i := len(messages) - 1; i >= 0; i-- {
|
||||
if messages[i].Timestamp.After(lastRead) || messages[i].Timestamp.Equal(lastRead) {
|
||||
count++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
/*
|
||||
// AddProfile adds a new profile to the UI
|
||||
func AddProfile(gcd *GrandCentralDispatcher, handle string) {
|
||||
p := the.CwtchApp.GetPeer(handle)
|
||||
if p != nil {
|
||||
nick, exists := p.GetAttribute(attr.GetPublicScope(constants.Name))
|
||||
if !exists {
|
||||
nick = handle
|
||||
}
|
||||
|
||||
picVal, ok := p.GetAttribute(attr.GetPublicScope(constants.Picture))
|
||||
if !ok {
|
||||
picVal = ImageToString(NewImage(RandomProfileImage(handle), TypeImageDistro))
|
||||
}
|
||||
pic, err := StringToImage(picVal)
|
||||
if err != nil {
|
||||
pic = NewImage(RandomProfileImage(handle), TypeImageDistro)
|
||||
}
|
||||
picPath := getPicturePath(pic)
|
||||
|
||||
tag, _ := p.GetAttribute(app.AttributeTag)
|
||||
|
||||
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)
|
||||
}
|
||||
}*/
|
||||
/*
|
||||
type manager struct {
|
||||
gcd *GrandCentralDispatcher
|
||||
profile string
|
||||
}
|
||||
|
||||
// Manager is a middleware helper for entities like peer event listeners wishing to trigger ui changes (via the gcd)
|
||||
// each manager is for one profile/peer
|
||||
// manager takes minimal arguments and builds the full struct of data (usually pulled from a cwtch peer) required to call the GCD to perform the ui action
|
||||
// manager also performs call filtering based on UI state: users of manager can safely always call it on events and not have to worry about weather the relevant ui is active
|
||||
// ie: you can always safely call AddMessage even if in the ui a different profile is selected. manager will check with gcd, and if the correct conditions are not met, it will not call on gcd to update the ui incorrectly
|
||||
type Manager interface {
|
||||
Acknowledge(handle, mID string)
|
||||
AddContact(Handle string)
|
||||
AddSendMessageError(peer string, signature string, err string)
|
||||
AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool)
|
||||
|
||||
ReloadProfiles()
|
||||
|
||||
UpdateContactDisplayName(handle string)
|
||||
UpdateContactPicture(handle string)
|
||||
UpdateContactStatus(handle string, status int, loading bool)
|
||||
UpdateContactAttribute(handle, key, value string)
|
||||
|
||||
ChangePasswordResponse(error bool)
|
||||
|
||||
AboutToAddMessage()
|
||||
MessageJustAdded()
|
||||
StoreAndNotify(peer.CwtchPeer, string, string, time.Time, string)
|
||||
|
||||
UpdateNetworkStatus(online bool)
|
||||
}
|
||||
|
||||
// NewManager returns a new Manager interface for a profile to the gcd
|
||||
func NewManager(profile string, gcd *GrandCentralDispatcher) Manager {
|
||||
return &manager{gcd: gcd, profile: profile}
|
||||
}
|
||||
|
||||
// Acknowledge acknowledges the given message id in the UI
|
||||
func (this *manager) Acknowledge(handle, mID string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.DoIfConversation(handle, func() {
|
||||
this.gcd.PeerAckAlert(mID)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func getLastMessageTime(tl *model.Timeline) int {
|
||||
if len(tl.Messages) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return int(tl.Messages[len(tl.Messages)-1].Timestamp.Unix())
|
||||
}
|
||||
|
||||
// AddContact adds a new contact to the ui for this manager's profile
|
||||
func (this *manager) AddContact(handle string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
|
||||
if IsGroup(handle) {
|
||||
group := the.Peer.GetGroup(handle)
|
||||
if group != nil {
|
||||
lastRead := InitLastReadTime(group.GroupID)
|
||||
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))
|
||||
}
|
||||
return
|
||||
} else if !IsPeer(handle) {
|
||||
log.Errorf("sorry, unable to handle AddContact(%v)", handle)
|
||||
debug.PrintStack()
|
||||
return
|
||||
}
|
||||
|
||||
contact := the.Peer.GetContact(handle)
|
||||
if contact != nil {
|
||||
lastRead := InitLastReadTime(contact.Onion)
|
||||
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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddSendMessageError adds an error not and icon to a message in a conversation in the ui for the message identified by the peer/sig combo
|
||||
func (this *manager) AddSendMessageError(peer string, signature string, err string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.DoIfConversation(peer, func() {
|
||||
log.Debugf("Received Error Sending Message: %v", err)
|
||||
// FIXME: Sometimes, for the first Peer message we send our error beats our message to the UI
|
||||
time.Sleep(time.Second * 1)
|
||||
this.gcd.GroupSendError(signature, err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (this *manager) AboutToAddMessage() {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
|
||||
}
|
||||
|
||||
func (this *manager) MessageJustAdded() {
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
}
|
||||
|
||||
func (this *manager) StoreAndNotify(pere peer.CwtchPeer, onion string, messageTxt string, sent time.Time, profileOnion string) {
|
||||
|
||||
// Send a New Message from Peer Notification
|
||||
this.gcd.AndroidCwtchActivity.SetChannel(onion)
|
||||
this.gcd.AndroidCwtchActivity.NotificationChanged("New Message from Peer")
|
||||
|
||||
this.gcd.DoIfProfileElse(this.profile, func() {
|
||||
this.gcd.DoIfConversationElse(onion, func() {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
|
||||
pere.StoreMessage(onion, messageTxt, sent)
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
updateLastReadTime(onion)
|
||||
}, func() {
|
||||
pere.StoreMessage(onion, messageTxt, sent)
|
||||
})
|
||||
this.gcd.IncContactUnreadCount(onion)
|
||||
}, func() {
|
||||
the.CwtchApp.GetPeer(profileOnion).StoreMessage(onion, messageTxt, sent)
|
||||
})
|
||||
this.gcd.Notify(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.DoIfConversation(handle, func() {
|
||||
updateLastReadTime(handle)
|
||||
// If the message is not from the user then add it, otherwise, just acknowledge.
|
||||
if !fromMe || !Acknowledged {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num() - 1)
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
} else {
|
||||
this.gcd.Acknowledged(messageID)
|
||||
}
|
||||
})
|
||||
this.gcd.IncContactUnreadCount(handle)
|
||||
})
|
||||
if !fromMe {
|
||||
this.gcd.Notify(handle)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *manager) ReloadProfiles() {
|
||||
this.gcd.reloadProfileList()
|
||||
}
|
||||
|
||||
// UpdateContactDisplayName updates a contact's display name in the contact list and conversations
|
||||
func (this *manager) UpdateContactDisplayName(handle string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.UpdateContactDisplayName(handle, GetNick(handle))
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateContactPicture updates a contact's picture in the contact list and conversations
|
||||
func (this *manager) UpdateContactPicture(handle string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.UpdateContactPicture(handle, GetProfilePic(handle))
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateContactStatus updates a contact's status in the ui
|
||||
func (this *manager) UpdateContactStatus(handle string, status int, loading bool) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.UpdateContactStatus(handle, status, loading)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateContactAttribute update's a contacts attribute in the ui
|
||||
func (this *manager) UpdateContactAttribute(handle, key, value string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.UpdateContactAttribute(handle, key, value)
|
||||
})
|
||||
}
|
||||
|
||||
func (this *manager) ChangePasswordResponse(error bool) {
|
||||
this.gcd.ChangePasswordResponse(error)
|
||||
}
|
||||
|
||||
func (this *manager) UpdateNetworkStatus(online bool) {
|
||||
this.gcd.UpdateProfileNetworkStatus(this.profile, online)
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,29 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"encoding/hex"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// temporary until we do real picture selection
|
||||
func RandomProfileImage(onion string) string {
|
||||
choices := []string{"001-centaur", "002-kraken", "003-dinosaur", "004-tree-1", "005-hand", "006-echidna", "007-robot", "008-mushroom", "009-harpy", "010-phoenix", "011-dragon-1", "012-devil", "013-troll", "014-alien", "015-minotaur", "016-madre-monte", "017-satyr", "018-karakasakozou", "019-pirate", "020-werewolf", "021-scarecrow", "022-valkyrie", "023-curupira", "024-loch-ness-monster", "025-tree", "026-cerberus", "027-gryphon", "028-mermaid", "029-vampire", "030-goblin", "031-yeti", "032-leprechaun", "033-medusa", "034-chimera", "035-elf", "036-hydra", "037-cyclops", "038-pegasus", "039-narwhal", "040-woodcutter", "041-zombie", "042-dragon", "043-frankenstein", "044-witch", "045-fairy", "046-genie", "047-pinocchio", "048-ghost", "049-wizard", "050-unicorn"}
|
||||
barr, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
|
||||
if err != nil || len(barr) != 35 {
|
||||
log.Errorf("error: %v %v %v\n", onion, err, barr)
|
||||
return "extra/openprivacy.png"
|
||||
}
|
||||
return "profiles/" + choices[int(barr[33])%len(choices)] + ".png"
|
||||
}
|
||||
|
||||
func RandomGroupImage(handle string) string {
|
||||
choices := []string{"001-borobudur", "002-opera-house", "003-burj-al-arab", "004-chrysler", "005-acropolis", "006-empire-state-building", "007-temple", "008-indonesia-1", "009-new-zealand", "010-notre-dame", "011-space-needle", "012-seoul", "013-mosque", "014-milan", "015-statue", "016-pyramid", "017-cologne", "018-brandenburg-gate", "019-berlin-cathedral", "020-hungarian-parliament", "021-buckingham", "022-thailand", "023-independence", "024-angkor-wat", "025-vaticano", "026-christ-the-redeemer", "027-colosseum", "028-golden-gate-bridge", "029-sphinx", "030-statue-of-liberty", "031-cradle-of-humankind", "032-istanbul", "033-london-eye", "034-sagrada-familia", "035-tower-bridge", "036-burj-khalifa", "037-washington", "038-big-ben", "039-stonehenge", "040-white-house", "041-ahu-tongariki", "042-capitol", "043-eiffel-tower", "044-church-of-the-savior-on-spilled-blood", "045-arc-de-triomphe", "046-windmill", "047-louvre", "048-torii-gate", "049-petronas", "050-matsumoto-castle", "051-fuji", "052-temple-of-heaven", "053-pagoda", "054-chichen-itza", "055-forbidden-city", "056-merlion", "057-great-wall-of-china", "058-taj-mahal", "059-pisa", "060-indonesia"}
|
||||
barr, err := hex.DecodeString(handle)
|
||||
if err != nil || len(barr) == 0 {
|
||||
log.Errorf("error: %v %v %v\n", handle, err, barr)
|
||||
return "extra/openprivacy.png"
|
||||
}
|
||||
return "servers/" + choices[int(barr[0])%len(choices)] + ".png"
|
||||
}
|
Loading…
Reference in New Issue