Skip to content

Commit 10a1477

Browse files
author
TeleGhost Dev
committed
Hotfix: Mobile realtime updates, silent notifications, and chat scrolling
1 parent b614077 commit 10a1477

6 files changed

Lines changed: 87 additions & 31 deletions

File tree

android/app/src/main/java/com/teleghost/app/TeleGhostService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class TeleGhostService : Service() {
121121
val channel = NotificationChannel(
122122
CHANNEL_ID,
123123
getString(R.string.notification_channel_name),
124-
NotificationManager.IMPORTANCE_DEFAULT // DEFAULT = visible and persistent
124+
NotificationManager.IMPORTANCE_LOW // LOW = silent but visible in shade
125125
).apply {
126126
description = getString(R.string.notification_channel_description)
127127
setShowBadge(false)

frontend/src/App.svelte

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -779,9 +779,19 @@
779779
},
780780
onUpdateProfile: async (addr) => {
781781
try {
782-
await AppActions.RequestProfileUpdate(addr);
783-
showToast("Запрос на обновление профиля отправлен", "info");
784-
} catch (e) { showToast(e, "error"); }
782+
if (AppActions.RequestProfile) {
783+
await AppActions.RequestProfile(addr);
784+
} else if (AppActions.RequestProfileUpdate) {
785+
// Fallback for older binary if exists
786+
await AppActions.RequestProfileUpdate(addr);
787+
} else {
788+
console.warn("RequestProfile not found in AppActions");
789+
}
790+
showToast('Запрос обновления профиля отправлен', 'info');
791+
} catch(e) {
792+
console.error(e);
793+
showToast('Ошибка обновления профиля', 'error');
794+
}
785795
},
786796
onShowSeed: () => { showSeedModal = true; },
787797
onCheckUpdates: async () => {

frontend/src/android_bridge.js

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,67 @@ function createProxy(methodName) {
4343
}
4444

4545
// Инициализация глобального объекта runtime для Wails Events
46+
// Wails Runtime Events Implementation
4647
window.runtime = {
4748
EventsOn: (eventName, callback) => {
4849
if (!bridge.listeners[eventName]) {
4950
bridge.listeners[eventName] = [];
5051
}
51-
bridge.listeners[eventName].push(callback);
52+
// Wrapper to maintain Wails behavior (maxCallbacks = -1 for infinite)
53+
bridge.listeners[eventName].push({ callback, maxCallbacks: -1 });
54+
return () => window.runtime.EventsOff(eventName, callback);
5255
},
53-
EventsOff: (eventName) => {
54-
delete bridge.listeners[eventName];
56+
EventsOnMultiple: (eventName, callback, maxCallbacks) => {
57+
if (!bridge.listeners[eventName]) {
58+
bridge.listeners[eventName] = [];
59+
}
60+
bridge.listeners[eventName].push({ callback, maxCallbacks });
61+
return () => window.runtime.EventsOff(eventName, callback);
62+
},
63+
EventsOnce: (eventName, callback) => {
64+
return window.runtime.EventsOnMultiple(eventName, callback, 1);
65+
},
66+
EventsOff: (eventName, ...additionalEventNames) => {
67+
const events = [eventName, ...additionalEventNames];
68+
events.forEach(name => {
69+
delete bridge.listeners[name];
70+
});
71+
},
72+
EventsOffAll: () => {
73+
bridge.listeners = {};
5574
},
5675
EventsEmit: (eventName, data) => {
57-
// Локальная эмуляция или отправка на сервер если нужно
58-
console.log("EventsEmit not fully implemented in bridge", eventName, data);
76+
// Broadcast locally to listeners (optimistic UI updates)
77+
if (bridge.listeners[eventName]) {
78+
bridge.listeners[eventName].forEach(listener => {
79+
listener.callback(data);
80+
if (listener.maxCallbacks > 0) {
81+
listener.maxCallbacks--;
82+
}
83+
});
84+
// Cleanup exhausted listeners
85+
bridge.listeners[eventName] = bridge.listeners[eventName].filter(l => l.maxCallbacks !== 0);
86+
}
87+
}
88+
};
89+
90+
// Override bridge listener logic to handle the new object structure
91+
bridge.events.onmessage = (event) => {
92+
try {
93+
const msg = JSON.parse(event.data);
94+
// Expecting msg.event (string) and msg.data (payload)
95+
if (msg.event && bridge.listeners[msg.event]) {
96+
bridge.listeners[msg.event].forEach(listener => {
97+
listener.callback(msg.data);
98+
if (listener.maxCallbacks > 0) {
99+
listener.maxCallbacks--;
100+
}
101+
});
102+
// Cleanup exhausted listeners
103+
bridge.listeners[msg.event] = bridge.listeners[msg.event].filter(l => l.maxCallbacks !== 0);
104+
}
105+
} catch (e) {
106+
console.error("Failed to parse SSE message:", e);
59107
}
60108
};
61109

frontend/src/components/Chat.svelte

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -142,25 +142,12 @@
142142
143143
onMount(() => {
144144
if (containerRef) {
145-
resizeObserver = new ResizeObserver(() => {
146-
if (!containerRef) return;
147-
const distanceToBottom = containerRef.scrollHeight - containerRef.scrollTop - containerRef.clientHeight;
148-
showScrollButton = distanceToBottom > 80;
149-
150-
// Point 5: Auto-scroll to bottom on content changes if we were already at bottom
151-
if (distanceToBottom < 30 && chatReady) {
152-
scrollToBottom();
153-
}
145+
containerRef.addEventListener('scroll', () => {
146+
const distanceToBottom = containerRef.scrollHeight - containerRef.scrollTop - containerRef.clientHeight;
147+
showScrollButton = distanceToBottom > 80;
154148
});
155-
resizeObserver.observe(containerRef);
149+
scrollToBottom(true);
156150
}
157-
158-
scrollToBottom(true);
159-
160-
return () => {
161-
if (pollInterval) clearInterval(pollInterval);
162-
if (resizeObserver) resizeObserver.disconnect();
163-
};
164151
});
165152
166153
// Handle Contact Change & Initialize Loading
@@ -183,8 +170,19 @@
183170
}, 3000);
184171
}
185172
186-
// Handle Messages Update & Image Counting
187-
$: if (messages && currentContactId) {
173+
// Handle Messages Update & Auto-scroll (Point 1)
174+
$: if (messages && currentContactId && containerRef) {
175+
// Check if we are near bottom BEFORE update (to decide if we should auto-scroll)
176+
const distanceToBottom = containerRef.scrollHeight - containerRef.scrollTop - containerRef.clientHeight;
177+
const wasNearBottom = distanceToBottom < 100;
178+
179+
if (wasNearBottom || !initialScrollDone) {
180+
tick().then(() => {
181+
scrollToBottom(!initialScrollDone);
182+
if (!initialScrollDone && chatReady) initialScrollDone = true;
183+
});
184+
}
185+
188186
if (!chatReady) {
189187
// Check for images in new messages
190188
const images = messages.flatMap(m => m.Attachments || []).filter(a => a.MimeType && a.MimeType.startsWith('image/'));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function QuitApp():Promise<void>;
8585

8686
export function RemoveChatFromFolder(arg1:string,arg2:string):Promise<void>;
8787

88-
export function RequestProfileUpdate(arg1:string):Promise<void>;
88+
export function RequestProfile(arg1:string):Promise<void>;
8989

9090
export function SaveFileToLocation(arg1:string,arg2:string):Promise<string>;
9191

frontend/wailsjs/go/main/App.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ export function RemoveChatFromFolder(arg1, arg2) {
166166
return window['go']['main']['App']['RemoveChatFromFolder'](arg1, arg2);
167167
}
168168

169-
export function RequestProfileUpdate(arg1) {
170-
return window['go']['main']['App']['RequestProfileUpdate'](arg1);
169+
export function RequestProfile(arg1) {
170+
return window['go']['main']['App']['RequestProfile'](arg1);
171171
}
172172

173173
export function SaveFileToLocation(arg1, arg2) {

0 commit comments

Comments
 (0)