新增聊天功能
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"time"
|
||||
"work_cation/cfg"
|
||||
"work_cation/global"
|
||||
"work_cation/models"
|
||||
"work_cation/repo"
|
||||
"work_cation/service"
|
||||
)
|
||||
|
||||
type ChatView struct {
|
||||
usersChat map[string]*ChatUserInfo
|
||||
}
|
||||
|
||||
type ChatUserInfo struct {
|
||||
models.Users
|
||||
messages []models.ChatMessage
|
||||
shows *fyne.Container
|
||||
scroll *container.Scroll
|
||||
}
|
||||
|
||||
var chat = &ChatView{usersChat: make(map[string]*ChatUserInfo)}
|
||||
|
||||
func ListenChat() {
|
||||
go func() {
|
||||
for {
|
||||
message := <-global.Send.SendChan
|
||||
userInfo := chat.usersChat[message.User.ID]
|
||||
if userInfo == nil {
|
||||
userInfo = &ChatUserInfo{}
|
||||
chat.usersChat[message.User.ID] = userInfo
|
||||
}
|
||||
userInfo.messages = append(userInfo.messages, message.ChatMessage)
|
||||
userInfo.Users = message.User.Users
|
||||
if userInfo.shows == nil {
|
||||
OpenChat(message.User.Users)
|
||||
} else {
|
||||
userInfo.shows.Add(itemMessage(message.ChatMessage))
|
||||
userInfo.scroll.ScrollToBottom()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func OpenChat(user models.Users) {
|
||||
userInfo := chat.usersChat[user.ID]
|
||||
if userInfo == nil {
|
||||
userInfo = &ChatUserInfo{}
|
||||
chat.usersChat[user.ID] = userInfo
|
||||
}
|
||||
if userInfo.shows == nil {
|
||||
w := fyne.CurrentApp().NewWindow(user.Name)
|
||||
w.CenterOnScreen()
|
||||
w.Resize(fyne.NewSize(500, 300))
|
||||
list := container.NewVBox()
|
||||
for _, item := range userInfo.messages {
|
||||
list.Add(itemMessage(item))
|
||||
}
|
||||
scroll := container.NewScroll(list)
|
||||
userInfo.scroll = scroll
|
||||
scroll.ScrollToBottom()
|
||||
// 发送表单
|
||||
en := widget.NewEntry()
|
||||
formBase := &widget.Form{
|
||||
SubmitText: "发送",
|
||||
OnSubmit: func() {
|
||||
if en.Text == "" {
|
||||
return
|
||||
}
|
||||
online := service.Zeroconf.GetOnline(user.ID)
|
||||
if online == nil {
|
||||
online = &models.Online{ID: user.ID, Ip: user.Ip, Port: cfg.T.ServerAddr}
|
||||
}
|
||||
msg, err := service.Client.Chat(online, en.Text)
|
||||
if err != nil || msg != "ok" {
|
||||
dialog.ShowInformation("发送失败", err.Error(), w)
|
||||
return
|
||||
}
|
||||
chatItem := models.ChatMessage{
|
||||
User: *repo.User.GetUserInfo(global.DB),
|
||||
Time: time.Now(),
|
||||
Text: en.Text,
|
||||
}
|
||||
userInfo.messages = append(userInfo.messages, chatItem)
|
||||
list.Add(itemMessage(chatItem))
|
||||
en.SetText("")
|
||||
scroll.ScrollToBottom()
|
||||
}}
|
||||
|
||||
formBase.AppendItem(&widget.FormItem{Text: "", Widget: en})
|
||||
w.SetContent(container.NewBorder(nil, formBase, nil, nil, scroll))
|
||||
userInfo.shows = list
|
||||
w.SetOnClosed(func() {
|
||||
userInfo.shows = nil
|
||||
userInfo.scroll = nil
|
||||
})
|
||||
w.Show()
|
||||
}
|
||||
userInfo.scroll.ScrollToBottom()
|
||||
}
|
||||
|
||||
func itemMessage(msg models.ChatMessage) fyne.CanvasObject {
|
||||
my := repo.User.GetUserInfo(global.DB)
|
||||
var card *widget.Card
|
||||
if msg.User.ID != my.ID {
|
||||
card = widget.NewCard("",
|
||||
fmt.Sprintf("%s %s", msg.Time.Format(time.DateTime),
|
||||
msg.User.Name), widget.NewLabel(msg.Text))
|
||||
} else {
|
||||
|
||||
title := fmt.Sprintf("%s %s", msg.Time.Format(time.DateTime), "我")
|
||||
card = widget.NewCard("", "",
|
||||
container.NewVBox(
|
||||
widget.NewLabelWithStyle(title, fyne.TextAlignTrailing, fyne.TextStyle{}),
|
||||
widget.NewLabelWithStyle(msg.Text, fyne.TextAlignTrailing, fyne.TextStyle{})))
|
||||
|
||||
}
|
||||
return card
|
||||
}
|
||||
+6
-5
@@ -17,15 +17,16 @@ type Tutorial struct {
|
||||
var (
|
||||
// Tutorials 定义每个教程的元数据
|
||||
Tutorials = map[string]Tutorial{
|
||||
"welcome": {"主页", "", mainUserViews, true},
|
||||
"canvas": {"我的", "", allCardsViews, true},
|
||||
"create": {"新建", "", allCreateCards, true},
|
||||
"otherUsers": {"同事", "", otherUser, true},
|
||||
"welcome": {"主页", "", mainUserViews, true},
|
||||
"canvas": {"我的", "", allCardsViews, true},
|
||||
"create": {"新建", "", allCreateCards, true},
|
||||
"otherUsers": {"同事", "", otherUser, true},
|
||||
"followUsers": {"关注", "", followUsers, true},
|
||||
}
|
||||
|
||||
// TutorialIndex 定义我们的教程应该如何在索引树中布局
|
||||
TutorialIndex = map[string][]string{
|
||||
"": {"welcome", "canvas", "otherUsers", "create"},
|
||||
"": {"welcome", "canvas", "followUsers", "otherUsers", "create"},
|
||||
//"collections": {"list", "table", "tree"},
|
||||
//"containers": {"apptabs", "border", "box", "center", "doctabs", "grid", "scroll", "split"},
|
||||
//"widgets": {"accordion", "button", "card", "entry", "form", "input", "progress", "text", "toolbar"}, 58 * 3 + 106 = 280
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"slices"
|
||||
"work_cation/cfg"
|
||||
"work_cation/global"
|
||||
"work_cation/models"
|
||||
"work_cation/repo"
|
||||
"work_cation/service"
|
||||
)
|
||||
|
||||
func followUsers(w fyne.Window) fyne.CanvasObject {
|
||||
gridWrap := container.NewGridWrap(fyne.NewSize(200, 190))
|
||||
|
||||
findService, err := service.Zeroconf.FindService()
|
||||
if err != nil {
|
||||
return widget.NewLabel(err.Error())
|
||||
}
|
||||
users, err := repo.UserFollow.All(global.DB)
|
||||
if err != nil {
|
||||
return widget.NewLabel(err.Error())
|
||||
}
|
||||
slices.SortFunc(users, func(a, b models.UserFollows) int {
|
||||
return b.Sort - a.Sort
|
||||
})
|
||||
for _, user := range users {
|
||||
index := slices.IndexFunc(findService, indexOnline2User(user.ID))
|
||||
var onlineCopy *models.Online
|
||||
if index != -1 {
|
||||
onlineCopy = &findService[index]
|
||||
}
|
||||
var baseCardV fyne.CanvasObject
|
||||
del := func() { gridWrap.Remove(baseCardV) }
|
||||
var userCopy = user
|
||||
baseCardV, err = itemFollowUserView(w, onlineCopy, &userCopy, del)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
gridWrap.Add(baseCardV)
|
||||
}
|
||||
|
||||
scroll := container.NewScroll(gridWrap)
|
||||
return container.NewBorder(nil, nil, nil, nil, scroll)
|
||||
}
|
||||
|
||||
func indexOnline2User(id string) func(models.Online) bool {
|
||||
return func(item models.Online) bool {
|
||||
return item.ID == id
|
||||
}
|
||||
}
|
||||
|
||||
func itemFollowUserView(w fyne.Window, data *models.Online, user *models.UserFollows, del func()) (fyne.CanvasObject, error) {
|
||||
|
||||
onlineShow := widget.NewLabel("离线")
|
||||
|
||||
go func() {
|
||||
defer func() { _ = recover() }()
|
||||
if data == nil {
|
||||
data = &models.Online{ID: user.ID, Ip: user.Ip, Port: cfg.T.ServerAddr}
|
||||
}
|
||||
newUser, err := service.Client.GetUser(data)
|
||||
if err != nil {
|
||||
data = nil
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
onlineShow.SetText("在线")
|
||||
}
|
||||
if err == nil && newUser.Name != user.Name {
|
||||
// 更新用户信息
|
||||
repo.UserFollow.UnFollow(global.DB, user)
|
||||
repo.UserFollow.Follow(global.DB, &models.UserFollows{Users: *newUser})
|
||||
}
|
||||
}()
|
||||
|
||||
followButton := widget.NewButton("取消关注", func() {
|
||||
err := repo.UserFollow.UnFollow(global.DB, user)
|
||||
if err != nil {
|
||||
dialog.ShowInformation("取消失败", err.Error(), w)
|
||||
return
|
||||
}
|
||||
dialog.ShowInformation("", "取消成功", w)
|
||||
del()
|
||||
})
|
||||
showErrButton := widget.NewButton("查看主页", func() {
|
||||
if data == nil {
|
||||
dialog.ShowInformation("查看失败", "用户未在线", w)
|
||||
return
|
||||
}
|
||||
otherUserIndexWin(&user.Users, data)
|
||||
})
|
||||
maishuiButton := widget.NewButton("聊天", func() {
|
||||
//if data == nil {
|
||||
// dialog.ShowInformation("查看失败", "用户未在线", w)
|
||||
// return
|
||||
//}
|
||||
OpenChat(user.Users)
|
||||
})
|
||||
|
||||
card := widget.NewCard(user.Name, user.Ip, container.NewVBox(onlineShow,
|
||||
container.NewHBox(showErrButton, followButton),
|
||||
maishuiButton))
|
||||
return card, nil
|
||||
}
|
||||
@@ -75,6 +75,7 @@ func itemOnlineUserView(w fyne.Window, data *models.Online) (fyne.CanvasObject,
|
||||
showErrButton := widget.NewButton("查看主页", func() {
|
||||
otherUserIndexWin(user, data)
|
||||
})
|
||||
|
||||
card := widget.NewCard(user.Name, user.Ip, container.NewVBox(followLabel, showErrButton, followButton))
|
||||
return card, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user