mirror of
https://github.com/status-im/status-desktop.git
synced 2025-03-04 08:20:58 +00:00
feat:(@desktop/channels): loading state when switching channels/chats
This commit is contained in:
parent
5479880cde
commit
b580f0a810
@ -212,6 +212,12 @@ proc init*(self: Controller) =
|
||||
if (community.id == self.sectionId):
|
||||
self.delegate.updateCommunityDetails(community)
|
||||
|
||||
self.events.on(SIGNAL_MESSAGE_FIRST_UNSEEN) do(e: Args):
|
||||
let args = MessageFirstUnseen(e)
|
||||
if (args.chatId != self.chatId):
|
||||
return
|
||||
self.delegate.onFirstUnseenMessageId(args.messageId)
|
||||
|
||||
proc getMySectionId*(self: Controller): string =
|
||||
return self.sectionId
|
||||
|
||||
@ -280,8 +286,8 @@ proc setSearchedMessageId*(self: Controller, searchedMessageId: string) =
|
||||
proc clearSearchedMessageId*(self: Controller) =
|
||||
self.setSearchedMessageId("")
|
||||
|
||||
proc getFirstUnseenMessageId*(self: Controller): string =
|
||||
self.messageService.getFirstUnseenMessageIdFor(self.chatId)
|
||||
proc getAsyncFirstUnseenMessageId*(self: Controller) =
|
||||
self.messageService.getAsyncFirstUnseenMessageId(self.chatId)
|
||||
|
||||
proc getLoadingMessagesPerPageFactor*(self: Controller): int =
|
||||
return self.loadingMessagesPerPageFactor
|
||||
|
@ -153,11 +153,11 @@ method resendChatMessage*(self: AccessInterface, messageId: string): string =
|
||||
method resetNewMessagesMarker*(self: AccessInterface) =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method scrollToNewMessagesMarker*(self: AccessInterface) =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method markAllMessagesRead*(self: AccessInterface) =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method updateCommunityDetails*(self: AccessInterface, community: CommunityDto) =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onFirstUnseenMessageId*(self: AccessInterface, messageId: string) =
|
||||
raise newException(ValueError, "No implementation available")
|
@ -681,16 +681,12 @@ method resendChatMessage*(self: Module, messageId: string): string =
|
||||
return self.controller.resendChatMessage(messageId)
|
||||
|
||||
method resetNewMessagesMarker*(self: Module) =
|
||||
self.view.model().setFirstUnseenMessageId(self.controller.getFirstUnseenMessageId())
|
||||
self.view.model().resetNewMessagesMarker()
|
||||
self.controller.getAsyncFirstUnseenMessageId()
|
||||
|
||||
method removeNewMessagesMarker*(self: Module) =
|
||||
self.view.model().setFirstUnseenMessageId("")
|
||||
self.view.model().resetNewMessagesMarker()
|
||||
|
||||
method scrollToNewMessagesMarker*(self: Module) =
|
||||
self.scrollToMessage(self.view.model().getFirstUnseenMessageId())
|
||||
|
||||
method markAllMessagesRead*(self: Module) =
|
||||
self.view.model().markAllAsSeen()
|
||||
|
||||
@ -721,3 +717,11 @@ proc updateItemsByAlbum(self: Module, items: var seq[Item], message: MessageDto)
|
||||
items[i] = item
|
||||
return true
|
||||
return false
|
||||
|
||||
method onFirstUnseenMessageId*(self: Module, messageId: string) =
|
||||
self.view.model().setFirstUnseenMessageId(messageId)
|
||||
self.view.model().resetNewMessagesMarker()
|
||||
let index = self.view.model().findIndexForMessageId(messageId)
|
||||
if (index != -1):
|
||||
self.view.emitScrollToFirstUnreadMessageSignal(index)
|
||||
self.view.setFirstUnseenMessageLoaded(true)
|
||||
|
@ -17,6 +17,7 @@ QtObject:
|
||||
chatColor: string
|
||||
chatIcon: string
|
||||
chatType: int
|
||||
firstUnseenMessageLoaded: bool
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.model.delete
|
||||
@ -233,4 +234,19 @@ QtObject:
|
||||
|
||||
proc setChatType*(self: View, value: int) =
|
||||
self.chatType = value
|
||||
self.chatTypeChanged()
|
||||
self.chatTypeChanged()
|
||||
|
||||
proc firstUnseenMessageLoadedChanged*(self: View) {.signal.}
|
||||
proc getFirstUnseenMessageLoaded*(self: View): bool {.slot.} =
|
||||
return self.firstUnseenMessageLoaded
|
||||
proc setFirstUnseenMessageLoaded*(self: View, value: bool) =
|
||||
self.firstUnseenMessageLoaded = value
|
||||
self.firstUnseenMessageLoadedChanged()
|
||||
|
||||
QtProperty[bool] firstUnseenMessageLoaded:
|
||||
read = getFirstUnseenMessageLoaded
|
||||
notify = firstUnseenMessageLoadedChanged
|
||||
|
||||
proc scrollToFirstUnreadMessage(self: View, messageIndex: int) {.signal.}
|
||||
proc emitScrollToFirstUnreadMessageSignal*(self: View, messageIndex: int) =
|
||||
self.scrollToFirstUnreadMessage(messageIndex)
|
@ -387,7 +387,6 @@ method contactTrustStatusChanged*(self: Module, publicKey: string, isUntrustwort
|
||||
|
||||
method onMadeActive*(self: Module) =
|
||||
self.messagesModule.resetNewMessagesMarker()
|
||||
self.messagesModule.scrollToNewMessagesMarker()
|
||||
self.view.setActive()
|
||||
|
||||
method onMadeInactive*(self: Module) =
|
||||
|
@ -233,4 +233,36 @@ const asyncGetLinkPreviewDataTask: Task = proc(argEncoded: string) {.gcsafe, nim
|
||||
previewData["links"].add(responseJson)
|
||||
|
||||
let tpl: tuple[previewData: JsonNode, uuid: string] = (previewData, arg.uuid)
|
||||
arg.finish(tpl)
|
||||
arg.finish(tpl)
|
||||
|
||||
#################################################
|
||||
# Async get first unseen message id
|
||||
#################################################
|
||||
type
|
||||
AsyncGetFirstUnseenMessageIdForTaskArg = ref object of QObjectTaskArg
|
||||
chatId: string
|
||||
|
||||
const asyncGetFirstUnseenMessageIdForTaskArg: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[AsyncGetFirstUnseenMessageIdForTaskArg](argEncoded)
|
||||
|
||||
let responseJson = %*{
|
||||
"messageId": "",
|
||||
"chatId": arg.chatId,
|
||||
"error": ""
|
||||
}
|
||||
|
||||
try:
|
||||
let response = status_go.firstUnseenMessageID(arg.chatId)
|
||||
|
||||
if(not response.error.isNil):
|
||||
error "error getFirstUnseenMessageIdFor: ", errDescription = response.error.message
|
||||
responseJson["error"] = %response.error.message
|
||||
else:
|
||||
responseJson["messageId"] = %response.result.getStr()
|
||||
|
||||
except Exception as e:
|
||||
error "error: ", procName = "getFirstUnseenMessageIdFor", errName = e.name,
|
||||
errDesription = e.msg, chatId=arg.chatId
|
||||
responseJson["error"] = %e.msg
|
||||
|
||||
arg.finish(responseJson)
|
@ -40,6 +40,7 @@ const WEEK_AS_MILLISECONDS = initDuration(seconds = 60*60*24*7).inMilliSeconds
|
||||
|
||||
# Signals which may be emitted by this service:
|
||||
const SIGNAL_MESSAGES_LOADED* = "messagesLoaded"
|
||||
const SIGNAL_MESSAGE_FIRST_UNSEEN* = "messageFirstUnseen"
|
||||
const SIGNAL_NEW_MESSAGE_RECEIVED* = "newMessageReceived"
|
||||
const SIGNAL_MESSAGE_PINNED* = "messagePinned"
|
||||
const SIGNAL_MESSAGE_UNPINNED* = "messageUnpinned"
|
||||
@ -117,6 +118,10 @@ type
|
||||
ReloadMessagesArgs* = ref object of Args
|
||||
communityId*: string
|
||||
|
||||
MessageFirstUnseen* = ref object of Args
|
||||
chatId*: string
|
||||
messageId*: string
|
||||
|
||||
QtObject:
|
||||
type Service* = ref object of QObject
|
||||
events: EventEmitter
|
||||
@ -188,9 +193,6 @@ QtObject:
|
||||
let pinnedMsgCursorValue = if (pinnedMsgCursor.isFetchable()): pinnedMsgCursor.getValue() else: CURSOR_VALUE_IGNORE
|
||||
|
||||
if(msgCursorValue == CURSOR_VALUE_IGNORE and pinnedMsgCursorValue == CURSOR_VALUE_IGNORE):
|
||||
# it's important to emit signal in case we are not fetching messages, so we can update the view appropriatelly.
|
||||
let data = MessagesLoadedArgs(chatId: chatId)
|
||||
self.events.emit(SIGNAL_MESSAGES_LOADED, data)
|
||||
return
|
||||
|
||||
if(msgCursorValue != CURSOR_VALUE_IGNORE):
|
||||
@ -386,7 +388,6 @@ QtObject:
|
||||
let responseObj = response.parseJson
|
||||
if (responseObj.kind != JObject):
|
||||
info "load more messages response is not a json object"
|
||||
|
||||
# notify view, this is important
|
||||
self.events.emit(SIGNAL_MESSAGES_LOADED, MessagesLoadedArgs())
|
||||
return
|
||||
@ -654,18 +655,37 @@ QtObject:
|
||||
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc getFirstUnseenMessageIdFor*(self: Service, chatId: string): string =
|
||||
proc getAsyncFirstUnseenMessageId*(self: Service, chatId: string) =
|
||||
let arg = AsyncGetFirstUnseenMessageIdForTaskArg(
|
||||
tptr: cast[ByteAddress](asyncGetFirstUnseenMessageIdForTaskArg),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onGetFirstUnseenMessageIdFor",
|
||||
chatId: chatId,
|
||||
)
|
||||
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc onGetFirstUnseenMessageIdFor*(self: Service, response: string) {.slot.} =
|
||||
try:
|
||||
let response = status_go.firstUnseenMessageID(chatId)
|
||||
let responseObj = response.parseJson
|
||||
|
||||
if(not response.error.isNil):
|
||||
error "error getFirstUnseenMessageIdFor: ", errDescription = response.error.message
|
||||
var error: string
|
||||
discard responseObj.getProp("error", error)
|
||||
|
||||
result = response.result.getStr()
|
||||
var chatId: string
|
||||
discard responseObj.getProp("chatId", chatId)
|
||||
|
||||
var messageId = ""
|
||||
|
||||
if(error.len > 0):
|
||||
error "error: ", procName="onGetFirstUnseenMessageIdFor", errDescription=error
|
||||
else:
|
||||
discard responseObj.getProp("messageId", messageId)
|
||||
|
||||
self.events.emit(SIGNAL_MESSAGE_FIRST_UNSEEN, MessageFirstUnseen(chatId: chatId, messageId: messageId))
|
||||
|
||||
except Exception as e:
|
||||
error "error: ", procName = "getFirstUnseenMessageIdFor", errName = e.name,
|
||||
errDesription = e.msg
|
||||
error "error: ", procName="onGetFirstUnseenMessageIdFor", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc onAsyncGetLinkPreviewData*(self: Service, response: string) {.slot.} =
|
||||
let responseObj = response.parseJson
|
||||
|
@ -83,6 +83,13 @@ Item {
|
||||
chatLogView.itemAtIndex(messageIndex).startMessageFoundAnimation()
|
||||
}
|
||||
|
||||
function onScrollToFirstUnreadMessage(messageIndex) {
|
||||
if (d.isMostRecentMessageInViewport) {
|
||||
chatLogView.positionViewAtIndex(messageIndex, ListView.Center)
|
||||
chatLogView.itemAtIndex(messageIndex).startMessageFoundAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
function onMessageSearchOngoingChanged() {
|
||||
d.markAllMessagesReadIfMostRecentMessageIsInViewport()
|
||||
}
|
||||
@ -145,8 +152,27 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loadingMessagesView
|
||||
|
||||
readonly property bool show: !messageStore.messageModule.firstUnseenMessageLoaded ||
|
||||
!messageStore.messageModule.initialMessagesLoaded
|
||||
active: show
|
||||
visible: show
|
||||
anchors.top: loadingMessagesIndicator.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
sourceComponent:
|
||||
MessagesLoadingView {
|
||||
anchors.margins: 16
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
||||
StatusListView {
|
||||
id: chatLogView
|
||||
visible: !loadingMessagesView.visible
|
||||
objectName: "chatLogView"
|
||||
anchors.top: loadingMessagesIndicator.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
@ -270,7 +296,7 @@ Item {
|
||||
quotedMessageAuthorDetailsEnsVerified: model.quotedMessageAuthorEnsVerified
|
||||
quotedMessageAuthorDetailsIsContact: model.quotedMessageAuthorIsContact
|
||||
quotedMessageAuthorDetailsColorHash: model.quotedMessageAuthorColorHash
|
||||
|
||||
|
||||
gapFrom: model.gapFrom
|
||||
gapTo: model.gapTo
|
||||
|
||||
|
65
ui/app/AppLayouts/Chat/views/MessagesLoadingView.qml
Normal file
65
ui/app/AppLayouts/Chat/views/MessagesLoadingView.qml
Normal file
@ -0,0 +1,65 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Components 0.1
|
||||
|
||||
ListView {
|
||||
spacing: 20
|
||||
interactive: false
|
||||
clip: true
|
||||
|
||||
model: ListModel {
|
||||
Component.onCompleted: {
|
||||
var numElements = 20
|
||||
for (var i = 1; i < numElements; ++i) {
|
||||
if (i % 5 === 0)
|
||||
append({ "isImage": true, "thirdLine": false })
|
||||
else if (i % 3 === 0)
|
||||
append({ "isImage": false, "thirdLine": true })
|
||||
else
|
||||
append({ "isImage": false, "thirdLine": false })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
|
||||
implicitHeight: layoutContent.implicitHeight
|
||||
implicitWidth: layoutContent.implicitWidth
|
||||
|
||||
RowLayout {
|
||||
id: layoutContent
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
|
||||
LoadingComponent {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
radius: width / 2
|
||||
height: 44
|
||||
width: 44
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 4
|
||||
LoadingComponent {
|
||||
radius: 4
|
||||
height: 20
|
||||
width: 124
|
||||
}
|
||||
LoadingComponent {
|
||||
radius: 16
|
||||
height: model.isImage ? 194 : 18
|
||||
width: model.isImage ? 147 : 335
|
||||
}
|
||||
LoadingComponent {
|
||||
visible: thirdLine
|
||||
radius: 4
|
||||
height: 18
|
||||
width: 215
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user