FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat: добавлены системные уведомления и счетчик непрочитанных сообщений · NullCoreDeveloper/TeleGhost@e267564 · GitHub

This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit e267564

Browse files
TeleGhost Dev
committed
feat: добавлены системные уведомления и счетчик непрочитанных сообщений
1 parent 46963df commit e267564

11 files changed

Lines changed: 352 additions & 4 deletions

File tree

‎app_messages.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ func (a *App) onMessageReceived(msg *core.Message, senderPubKey, senderAddr stri
280280
"IsOutgoing": msg.IsOutgoing,
281281
"ContentType": msg.ContentType,
282282
})
283+
284+
// Отправляем системное уведомление, если окно скрыто
285+
if !msg.IsOutgoing && contact != nil {
286+
go a.sendNotification(contact.Nickname, msg.Content, msg.ContentType)
287+
go a.updateUnreadCount()
288+
}
283289
}
284290

285291
// SendText отправляет текстовое сообщение

‎app_notifications.go‎

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/gen2brain/beeep"
8+
"github.com/wailsapp/wails/v2/pkg/runtime"
9+
)
10+
11+
// sendNotification отправляет системное уведомление
12+
func (a *App) sendNotification(senderName, content, contentType string) {
13+
if a.ctx == nil {
14+
return
15+
}
16+
17+
// Проверяем, скрыто ли окно
18+
// Если окно видимо, не показываем системное уведомление
19+
if a.trayManager != nil && a.trayManager.isVisible {
20+
return
21+
}
22+
23+
title := fmt.Sprintf("TeleGhost - %s", senderName)
24+
message := content
25+
26+
// Для разных типов контента формируем разные сообщения
27+
switch contentType {
28+
case "file_offer":
29+
message = "📎 Отправил(а) файл"
30+
case "mixed":
31+
if content == "" {
32+
message = "📷 Отправил(а) изображение"
33+
} else {
34+
message = fmt.Sprintf("📷 %s", content)
35+
}
36+
case "text":
37+
// Ограничиваем длину сообщения для уведомления
38+
if len(message) > 100 {
39+
message = message[:97] + "..."
40+
}
41+
}
42+
43+
// Отправляем системное уведомление
44+
err := beeep.Notify(title, message, "")
45+
if err != nil {
46+
log.Printf("[Notifications] Failed to send notification: %v", err)
47+
}
48+
}
49+
50+
// updateUnreadCount обновляет счетчик непрочитанных сообщений
51+
func (a *App) updateUnreadCount() {
52+
if a.repo == nil || a.ctx == nil {
53+
return
54+
}
55+
56+
// Получаем количество непрочитанных сообщений
57+
unreadCount, err := a.repo.GetUnreadCount(a.ctx)
58+
if err != nil {
59+
log.Printf("[Notifications] Failed to get unread count: %v", err)
60+
return
61+
}
62+
63+
// Обновляем заголовок в трее
64+
if a.trayManager != nil {
65+
a.trayManager.updateUnreadCount(unreadCount)
66+
}
67+
68+
// Отправляем событие во фронтенд
69+
runtime.EventsEmit(a.ctx, "unread_count", unreadCount)
70+
}
71+
72+
// GetUnreadCount возвращает количество непрочитанных сообщений
73+
func (a *App) GetUnreadCount() (int, error) {
74+
if a.repo == nil {
75+
return 0, fmt.Errorf("repository not initialized")
76+
}
77+
return a.repo.GetUnreadCount(a.ctx)
78+
}
79+
80+
// MarkChatAsRead помечает все сообщения в чате как прочитанные
81+
func (a *App) MarkChatAsRead(chatID string) error {
82+
if a.repo == nil {
83+
return fmt.Errorf("repository not initialized")
84+
}
85+
86+
err := a.repo.MarkChatAsRead(a.ctx, chatID)
87+
if err != nil {
88+
return err
89+
}
90+
91+
// Обновляем счетчик
92+
go a.updateUnreadCount()
93+
return nil
94+
}

‎frontend/src/App.svelte‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
let networkStatus = 'offline';
2727
let myDestination = '';
2828
let currentUserInfo = null;
29+
let unreadCount = 0;
2930
3031
// Sidebar/Contacts State
3132
let contacts = [];
@@ -145,6 +146,10 @@
145146
console.log("[App] Received contact_updated event, reloading contacts...");
146147
loadContacts();
147148
});
149+
150+
EventsOn("unread_count", (count) => {
151+
unreadCount = count;
152+
});
148153
});
149154
150155
async function loadMyInfo() {
@@ -160,6 +165,11 @@
160165
try {
161166
selectedProfile = await AppActions.GetCurrentProfile();
162167
} catch(e) { console.warn('GetCurrentProfile failed:', e); }
168+
169+
// Load unread count
170+
try {
171+
unreadCount = await AppActions.GetUnreadCount();
172+
} catch(e) { console.warn('GetUnreadCount failed:', e); }
163173
}
164174
165175
async function loadContacts() {
@@ -260,6 +270,11 @@
260270
}
261271
262272
async function loadMessages(contactId) {
273+
const contact = contacts.find(c => c.ID === contactId);
274+
if (contact && contact.ChatID) {
275+
// Помечаем чат как прочитанный
276+
await AppActions.MarkChatAsRead(contact.ChatID);
277+
}
263278
messages = await AppActions.GetMessages(contactId, 50, 0);
264279
scrollToBottom();
265280
}
@@ -671,6 +686,7 @@
671686
<Sidebar
672687
{isMobile} {contacts} {folders} {activeFolderId} {searchQuery}
673688
{networkStatus} {showSettings} {sidebarWidth} {isResizing} {selectedContact}
689+
{unreadCount}
674690
{...sidebarHandlers}
675691
/>
676692
{:else if $mobileView === 'chat' && selectedContact}
@@ -713,6 +729,7 @@
713729
<Sidebar
714730
{isMobile} {contacts} {folders} {activeFolderId} {searchQuery}
715731
{networkStatus} {showSettings} {sidebarWidth} {isResizing} {selectedContact}
732+
{unreadCount}
716733
{...sidebarHandlers}
717734
/>
718735

‎frontend/src/components/Sidebar.svelte‎

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
export let sidebarWidth;
1414
export let isResizing;
1515
export let selectedContact;
16+
export let unreadCount = 0;
1617
1718
export let onSelectContact;
1819
export let onContextMenu;
@@ -86,6 +87,9 @@
8687
on:keydown={(e) => (e.key === 'Enter' || e.key === ' ') && onToggleSettings()}
8788
>
8889
<div class="icon-svg">{@html Icons.Menu}</div>
90+
{#if unreadCount > 0}
91+
<div class="unread-badge">{unreadCount > 99 ? '99+' : unreadCount}</div>
92+
{/if}
8993
</div>
9094
9195
<div class="folders-list">
@@ -186,8 +190,11 @@
186190
<div class="mobile-sidebar">
187191
<!-- Mobile Header -->
188192
<div class="mobile-header">
189-
<button class="mobile-menu-btn" on:click={onToggleSettings}>
193+
<button class="mobile-menu-btn" on:click={onToggleSettings} style="position: relative;">
190194
<div class="icon-svg">{@html Icons.Menu}</div>
195+
{#if unreadCount > 0}
196+
<div class="unread-badge mobile-badge">{unreadCount > 99 ? '99+' : unreadCount}</div>
197+
{/if}
191198
</button>
192199
<h1 class="mobile-title">TeleGhost</h1>
193200
<div class="mobile-network-dot" style="background: {getStatusColor(networkStatus)}" title={getStatusText(networkStatus)}></div>
@@ -293,12 +300,46 @@
293300
margin-bottom: 20px;
294301
color: var(--text-secondary);
295302
transition: all 0.2s;
303+
position: relative;
296304
}
297305
.rail-button:hover, .rail-button.active {
298306
background: rgba(255,255,255,0.1);
299307
color: white;
300308
}
301309
310+
.unread-badge {
311+
position: absolute;
312+
top: -4px;
313+
right: -4px;
314+
background: #ff4757;
315+
color: white;
316+
font-size: 10px;
317+
font-weight: 700;
318+
min-width: 18px;
319+
height: 18px;
320+
border-radius: 9px;
321+
display: flex;
322+
align-items: center;
323+
justify-content: center;
324+
padding: 0 4px;
325+
box-shadow: 0 2px 8px rgba(255, 71, 87, 0.4);
326+
animation: badge-pulse 2s ease-in-out infinite;
327+
}
328+
329+
.mobile-badge {
330+
top: 2px;
331+
right: 2px;
332+
font-size: 9px;
333+
min-width: 16px;
334+
height: 16px;
335+
border-radius: 8px;
336+
}
337+
338+
@keyframes badge-pulse {
339+
0%, 100% { transform: scale(1); }
340+
50% { transform: scale(1.1); }
341+
}
342+
302343
.folder-item {
303344
display: flex;
304345
flex-direction: column;

‎frontend/wailsjs/go/main/App.d.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,16 @@ export function GetNetworkStatus():Promise<string>;
6262

6363
export function GetRouterSettings():Promise<main.RouterSettings>;
6464

65+
export function GetUnreadCount():Promise<number>;
66+
6567
export function ListProfiles():Promise<Array<profiles.ProfileMetadata>>;
6668

6769
export function Login(arg1:string):Promise<void>;
6870

6971
export function Logout():Promise<void>;
7072

73+
export function MarkChatAsRead(arg1:string):Promise<void>;
74+
7175
export function OpenFile(arg1:string):Promise<void>;
7276

7377
export function QuitApp():Promise<void>;

‎frontend/wailsjs/go/main/App.js‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ export function GetRouterSettings() {
118118
return window['go']['main']['App']['GetRouterSettings']();
119119
}
120120

121+
export function GetUnreadCount() {
122+
return window['go']['main']['App']['GetUnreadCount']();
123+
}
124+
121125
export function ListProfiles() {
122126
return window['go']['main']['App']['ListProfiles']();
123127
}
@@ -130,6 +134,10 @@ export function Logout() {
130134
return window['go']['main']['App']['Logout']();
131135
}
132136

137+
export function MarkChatAsRead(arg1) {
138+
return window['go']['main']['App']['MarkChatAsRead'](arg1);
139+
}
140+
133141
export function OpenFile(arg1) {
134142
return window['go']['main']['App']['OpenFile'](arg1);
135143
}

‎go.mod‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.24.0
44

55
require (
66
fyne.io/systray v1.12.0
7+
github.com/gen2brain/beeep v0.11.2
78
github.com/go-i2p/i2pkeys v0.0.0-20241108200332-e4f5ccdff8c4
89
github.com/go-i2p/sam3 v0.33.92
910
github.com/google/uuid v1.6.0
@@ -18,10 +19,13 @@ require (
1819
)
1920

2021
require (
22+
git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect
2123
github.com/bep/debounce v1.2.1 // indirect
24+
github.com/esiqveland/notify v0.13.3 // indirect
2225
github.com/go-ole/go-ole v1.3.0 // indirect
2326
github.com/godbus/dbus/v5 v5.1.0 // indirect
2427
github.com/gorilla/websocket v1.5.3 // indirect
28+
github.com/jackmordaunt/icns/v3 v3.0.1 // indirect
2529
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
2630
github.com/labstack/echo/v4 v4.13.3 // indirect
2731
github.com/labstack/gommon v0.4.2 // indirect
@@ -35,7 +39,10 @@ require (
3539
github.com/pkg/errors v0.9.1 // indirect
3640
github.com/rivo/uniseg v0.4.7 // indirect
3741
github.com/samber/lo v1.49.1 // indirect
42+
github.com/sergeymakinen/go-bmp v1.0.0 // indirect
43+
github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
3844
github.com/sirupsen/logrus v1.9.3 // indirect
45+
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
3946
github.com/tkrajina/go-reflector v0.5.8 // indirect
4047
github.com/valyala/bytebufferpool v1.0.0 // indirect
4148
github.com/valyala/fasttemplate v1.2.2 // indirect

‎go.sum‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
fyne.io/systray v1.12.0 h1:CA1Kk0e2zwFlxtc02L3QFSiIbxJ/P0n582YrZHT7aTM=
22
fyne.io/systray v1.12.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
3+
git.sr.ht/~jackmordaunt/go-toast v1.1.2 h1:/yrfI55LRt1M7H1vkaw+NaH1+L1CDxrqDltwm5euVuE=
4+
git.sr.ht/~jackmordaunt/go-toast v1.1.2/go.mod h1:jA4OqHKTQ4AFBdwrSnwnskUIIS3HYzlJSgdzCKqfavo=
35
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
46
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
57
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
68
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
79
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10+
github.com/esiqveland/notify v0.13.3 h1:QCMw6o1n+6rl+oLUfg8P1IIDSFsDEb2WlXvVvIJbI/o=
11+
github.com/esiqveland/notify v0.13.3/go.mod h1:hesw/IRYTO0x99u1JPweAl4+5mwXJibQVUcP0Iu5ORE=
12+
github.com/gen2brain/beeep v0.11.2 h1:+KfiKQBbQCuhfJFPANZuJ+oxsSKAYNe88hIpJuyKWDA=
13+
github.com/gen2brain/beeep v0.11.2/go.mod h1:jQVvuwnLuwOcdctHn/uyh8horSBNJ8uGb9Cn2W4tvoc=
814
github.com/go-i2p/i2pkeys v0.0.0-20241108200332-e4f5ccdff8c4 h1:LRjaRCzg1ieGKZjELlaIg06Fx04RHzQLsWMYp1H6PQ4=
915
github.com/go-i2p/i2pkeys v0.0.0-20241108200332-e4f5ccdff8c4/go.mod h1:m5TlHjPZrU5KbTd7Lr+I2rljyC6aJ88HdkeMQXV0U0E=
1016
github.com/go-i2p/sam3 v0.33.92 h1:TVpi4GH7Yc7nZBiE1QxLjcZfnC4fI/80zxQz1Rk36BA=
@@ -19,6 +25,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
1925
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
2026
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
2127
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
28+
github.com/jackmordaunt/icns/v3 v3.0.1 h1:xxot6aNuGrU+lNgxz5I5H0qSeCjNKp8uTXB1j8D4S3o=
29+
github.com/jackmordaunt/icns/v3 v3.0.1/go.mod h1:5sHL59nqTd2ynTnowxB/MDQFhKNqkK8X687uKNygaSQ=
2230
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
2331
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
2432
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
@@ -58,14 +66,25 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
5866
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
5967
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
6068
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
69+
github.com/sergeymakinen/go-bmp v1.0.0 h1:SdGTzp9WvCV0A1V0mBeaS7kQAwNLdVJbmHlqNWq0R+M=
70+
github.com/sergeymakinen/go-bmp v1.0.0/go.mod h1:/mxlAQZRLxSvJFNIEGGLBE/m40f3ZnUifpgVDlcUIEY=
71+
github.com/sergeymakinen/go-ico v1.0.0-beta.0 h1:m5qKH7uPKLdrygMWxbamVn+tl2HfiA3K6MFJw4GfZvQ=
72+
github.com/sergeymakinen/go-ico v1.0.0-beta.0/go.mod h1:wQ47mTczswBO5F0NoDt7O0IXgnV4Xy3ojrroMQzyhUk=
6173
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
6274
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
6375
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
6476
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
6577
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
78+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
79+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
6680
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
81+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
82+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
83+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
6784
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
6885
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
86+
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
87+
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
6988
github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
7089
github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
7190
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL