From 848308ed04d47f8d96978546e9ad15299efc49dd Mon Sep 17 00:00:00 2001 From: Anthony Laibe Date: Thu, 13 Jan 2022 09:58:42 +0100 Subject: [PATCH] refactor(@desktop): gif section --- src/app/boot/app_controller.nim | 10 +- .../chat_content/input_area/controller.nim | 30 +++- .../input_area/controller_interface.nim | 23 ++- .../input_area/gif_column_model.nim | 54 +++++++ .../chat_content/input_area/module.nim | 32 +++- .../module_access_interface.nim | 24 +++ .../chat_content/input_area/view.nim | 107 ++++++++++++- .../main/chat_section/chat_content/module.nim | 5 +- src/app/modules/main/chat_section/module.nim | 32 ++-- .../module_access_interface.nim | 4 +- src/app/modules/main/controller.nim | 17 +- src/app/modules/main/module.nim | 54 ++++--- .../module_access_interface.nim | 4 +- .../module_controller_delegate_interface.nim | 3 +- src/app_service/service/gif/dto.nim | 40 +++++ src/app_service/service/gif/service.nim | 148 ++++++++++++++++++ .../service/gif/service_interface.nim | 6 + .../service/settings/dto/settings.nim | 6 + src/app_service/service/settings/service.nim | 18 +++ .../service/settings/service_interface.nim | 12 ++ ui/imports/shared/status/StatusGifColumn.qml | 6 +- ui/imports/shared/status/StatusGifPopup.qml | 45 +++--- ui/imports/shared/stores/RootStore.qml | 32 ++++ 23 files changed, 626 insertions(+), 86 deletions(-) create mode 100644 src/app/modules/main/chat_section/chat_content/input_area/gif_column_model.nim create mode 100644 src/app_service/service/gif/dto.nim create mode 100644 src/app_service/service/gif/service.nim create mode 100644 src/app_service/service/gif/service_interface.nim diff --git a/src/app/boot/app_controller.nim b/src/app/boot/app_controller.nim index 7c872c295a..c69a338ce8 100644 --- a/src/app/boot/app_controller.nim +++ b/src/app/boot/app_controller.nim @@ -29,6 +29,7 @@ import ../../app_service/service/activity_center/service as activity_center_serv import ../../app_service/service/saved_address/service as saved_address_service import ../../app_service/service/devices/service as devices_service import ../../app_service/service/mailservers/service as mailservers_service +import ../../app_service/service/gif/service as gif_service import ../modules/startup/module as startup_module import ../modules/main/module as main_module @@ -80,6 +81,7 @@ type devicesService: devices_service.Service mailserversService: mailservers_service.Service nodeService: node_service.Service + gifService: gif_service.Service # Modules startupModule: startup_module.AccessInterface @@ -165,6 +167,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController = result.settingsService, result.nodeConfigurationService, statusFoundation.fleetConfiguration) result.nodeService = node_service.newService(statusFoundation.events, statusFoundation.threadpool, result.settingsService) + result.gifService = gif_service.newService(result.settingsService) # Modules result.startupModule = startup_module.newModule[AppController]( @@ -201,7 +204,8 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController = result.nodeConfigurationService, result.devicesService, result.mailserversService, - result.nodeService + result.nodeService, + result.gifService, ) # Do connections @@ -213,6 +217,7 @@ proc delete*(self: AppController) = self.keychainService.delete self.contactsService.delete self.bookmarkService.delete + self.gifService.delete self.startupModule.delete self.mainModule.delete self.ethService.delete @@ -306,7 +311,8 @@ proc load(self: AppController) = self.contactsService, self.chatService, self.communityService, - self.messageService + self.messageService, + self.gifService, ) proc userLoggedIn*(self: AppController) = diff --git a/src/app/modules/main/chat_section/chat_content/input_area/controller.nim b/src/app/modules/main/chat_section/chat_content/input_area/controller.nim index 5e6c520967..384cba05eb 100644 --- a/src/app/modules/main/chat_section/chat_content/input_area/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/input_area/controller.nim @@ -3,6 +3,8 @@ import io_interface import ../../../../../../app_service/service/community/service as community_service import ../../../../../../app_service/service/chat/service as chat_service +import ../../../../../../app_service/service/gif/service as gif_service +import ../../../../../../app_service/service/gif/dto export controller_interface @@ -14,6 +16,7 @@ type belongsToCommunity: bool communityService: community_service.Service chatService: chat_service.Service + gifService: gif_service.Service proc newController*( delegate: io_interface.AccessInterface, @@ -21,7 +24,8 @@ proc newController*( chatId: string, belongsToCommunity: bool, chatService: chat_service.Service, - communityService: community_service.Service + communityService: community_service.Service, + gifService: gif_service.Service ): Controller = result = Controller() result.delegate = delegate @@ -30,6 +34,7 @@ proc newController*( result.belongsToCommunity = belongsToCommunity result.chatService = chatService result.communityService = communityService + result.gifService = gifService method delete*(self: Controller) = discard @@ -71,4 +76,25 @@ method acceptRequestAddressForTransaction*(self: Controller, messageId: string, self.chatService.acceptRequestAddressForTransaction(messageId, address) method acceptRequestTransaction*(self: Controller, transactionHash: string, messageId: string, signature: string) = - self.chatService.acceptRequestTransaction(transactionHash, messageId, signature) \ No newline at end of file + self.chatService.acceptRequestTransaction(transactionHash, messageId, signature) + +method searchGifs*(self: Controller, query: string): seq[GifDto] = + return self.gifService.search(query) + +method getTrendingsGifs*(self: Controller): seq[GifDto] = + return self.gifService.getTrendings() + +method getRecentsGifs*(self: Controller): seq[GifDto] = + return self.gifService.getRecents() + +method getFavoritesGifs*(self: Controller): seq[GifDto] = + return self.gifService.getFavorites() + +method toggleFavoriteGif*(self: Controller, item: GifDto) = + self.gifService.toggleFavorite(item) + +method addToRecentsGif*(self: Controller, item: GifDto) = + self.gifService.addToRecents(item) + +method isFavorite*(self: Controller, item: GifDto): bool = + return self.gifService.isFavorite(item) \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/input_area/controller_interface.nim b/src/app/modules/main/chat_section/chat_content/input_area/controller_interface.nim index 8f54e25500..0f1b810bd1 100644 --- a/src/app/modules/main/chat_section/chat_content/input_area/controller_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/input_area/controller_interface.nim @@ -1,3 +1,4 @@ +import ../../../../../../app_service/service/gif/dto type AccessInterface* {.pure inheritable.} = ref object of RootObj @@ -38,4 +39,24 @@ method acceptRequestAddressForTransaction*(self: AccessInterface, messageId: str method acceptRequestTransaction*(self: AccessInterface, transactionHash: string, messageId: string, signature: string) {.base.} = raise newException(ValueError, "No implementation available") - \ No newline at end of file + +method searchGifs*(self: AccessInterface, query: string): seq[GifDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method getTrendingsGifs*(self: AccessInterface): seq[GifDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method getRecentsGifs*(self: AccessInterface): seq[GifDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method getFavoritesGifs*(self: AccessInterface): seq[GifDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method toggleFavoriteGif*(self: AccessInterface, item: GifDto) {.base.} = + raise newException(ValueError, "No implementation available") + +method addToRecentsGif*(self: AccessInterface, item: GifDto) {.base.} = + raise newException(ValueError, "No implementation available") + +method isFavorite*(self: AccessInterface, item: GifDto): bool {.base.} = + raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/input_area/gif_column_model.nim b/src/app/modules/main/chat_section/chat_content/input_area/gif_column_model.nim new file mode 100644 index 0000000000..0e72262e6e --- /dev/null +++ b/src/app/modules/main/chat_section/chat_content/input_area/gif_column_model.nim @@ -0,0 +1,54 @@ +import NimQml, Tables, sequtils + +import ../../../../../../app_service/service/gif/dto + +type + GifRoles {.pure.} = enum + Url = UserRole + 1 + Id = UserRole + 2 + Title = UserRole + 3 + TinyUrl = UserRole + 4 + +QtObject: + type + GifColumnModel* = ref object of QAbstractListModel + gifs*: seq[GifDto] + + proc setup(self: GifColumnModel) = self.QAbstractListModel.setup + + proc delete(self: GifColumnModel) = self.QAbstractListModel.delete + + proc newGifColumnModel*(): GifColumnModel = + new(result, delete) + result.gifs = @[] + result.setup() + + proc setNewData*(self: GifColumnModel, gifs: seq[GifDto]) = + self.beginResetModel() + self.gifs = gifs + self.endResetModel() + + method rowCount(self: GifColumnModel, index: QModelIndex = nil): int = + self.gifs.len + + method data(self: GifColumnModel, index: QModelIndex, role: int): QVariant = + if not index.isValid: + return + + if index.row < 0 or index.row >= self.gifs.len: + return + + let gif = self.gifs[index.row] + case role.GifRoles: + of GifRoles.Url: result = newQVariant(gif.url) + of GifRoles.Id: result = newQVariant(gif.id) + of GifRoles.Title: result = newQVariant(gif.title) + of GifRoles.TinyUrl: result = newQVariant(gif.tinyUrl) + + method roleNames(self: GifColumnModel): Table[int, string] = + { + GifRoles.Url.int:"url", + GifRoles.Id.int:"id", + GifRoles.Title.int:"title", + GifRoles.TinyUrl.int:"tinyUrl", + }.toTable \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/input_area/module.nim b/src/app/modules/main/chat_section/chat_content/input_area/module.nim index 81027fc130..62899dfbf9 100644 --- a/src/app/modules/main/chat_section/chat_content/input_area/module.nim +++ b/src/app/modules/main/chat_section/chat_content/input_area/module.nim @@ -6,6 +6,8 @@ import ../../../../../global/global_singleton import ../../../../../../app_service/service/chat/service as chat_service import ../../../../../../app_service/service/community/service as community_service +import ../../../../../../app_service/service/gif/service as gif_service +import ../../../../../../app_service/service/gif/dto export io_interface @@ -23,14 +25,15 @@ proc newModule*( chatId: string, belongsToCommunity: bool, chatService: chat_service.Service, - communityService: community_service.Service + communityService: community_service.Service, + gifService: gif_service.Service, ): Module = result = Module() result.delegate = delegate result.view = view.newView(result) result.viewVariant = newQVariant(result.view) - result.controller = controller.newController(result, sectionId, chatId, belongsToCommunity, chatService, communityService) + result.controller = controller.newController(result, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService) result.moduleLoaded = false method delete*(self: Module) = @@ -39,6 +42,8 @@ method delete*(self: Module) = self.controller.delete method load*(self: Module) = + singletonInstance.engine.setRootContextProperty("chatSectionChatContentInputArea", self.viewVariant) + self.controller.init() self.view.load() @@ -82,4 +87,25 @@ method acceptRequestAddressForTransaction*(self: Module, messageId: string, addr self.controller.acceptRequestAddressForTransaction(messageId, address) method acceptRequestTransaction*(self: Module, transactionHash: string, messageId: string, signature: string) = - self.controller.acceptRequestTransaction(transactionHash, messageId, signature) \ No newline at end of file + self.controller.acceptRequestTransaction(transactionHash, messageId, signature) + +method searchGifs*(self: Module, query: string): seq[GifDto] = + return self.controller.searchGifs(query) + +method getTrendingsGifs*(self: Module): seq[GifDto] = + return self.controller.getTrendingsGifs() + +method getRecentsGifs*(self: Module): seq[GifDto] = + return self.controller.getRecentsGifs() + +method getFavoritesGifs*(self: Module): seq[GifDto] = + return self.controller.getFavoritesGifs() + +method toggleFavoriteGif*(self: Module, item: GifDto) = + self.controller.toggleFavoriteGif(item) + +method addToRecentsGif*(self: Module, item: GifDto) = + self.controller.addToRecentsGif(item) + +method isFavorite*(self: Module, item: GifDto): bool = + return self.controller.isFavorite(item) \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/input_area/private_interfaces/module_access_interface.nim b/src/app/modules/main/chat_section/chat_content/input_area/private_interfaces/module_access_interface.nim index ea9fdb653c..e8408a7495 100644 --- a/src/app/modules/main/chat_section/chat_content/input_area/private_interfaces/module_access_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/input_area/private_interfaces/module_access_interface.nim @@ -1,5 +1,8 @@ import NimQml +import ../../../../../../../app_service/service/gif/dto + + method delete*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") @@ -34,4 +37,25 @@ method acceptRequestAddressForTransaction*(self: AccessInterface, messageId: str raise newException(ValueError, "No implementation available") method acceptRequestTransaction*(self: AccessInterface, transactionHash: string, messageId: string, signature: string) {.base.} = + raise newException(ValueError, "No implementation available") + +method searchGifs*(self: AccessInterface, query: string): seq[GifDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method getTrendingsGifs*(self: AccessInterface): seq[GifDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method getRecentsGifs*(self: AccessInterface): seq[GifDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method getFavoritesGifs*(self: AccessInterface): seq[GifDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method toggleFavoriteGif*(self: AccessInterface, item: GifDto) {.base.} = + raise newException(ValueError, "No implementation available") + +method addToRecentsGif*(self: AccessInterface, item: GifDto) {.base.} = + raise newException(ValueError, "No implementation available") + +method isFavorite*(self: AccessInterface, item: GifDto): bool {.base.} = raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/input_area/view.nim b/src/app/modules/main/chat_section/chat_content/input_area/view.nim index b1cfac1251..16b80bf872 100644 --- a/src/app/modules/main/chat_section/chat_content/input_area/view.nim +++ b/src/app/modules/main/chat_section/chat_content/input_area/view.nim @@ -1,12 +1,17 @@ import NimQml -import model -import io_interface +import ./model +import ./io_interface +import ./gif_column_model +import ../../../../../../app_service/service/gif/dto QtObject: type View* = ref object of QObject delegate: io_interface.AccessInterface model: Model + gifColumnAModel: GifColumnModel + gifColumnBModel: GifColumnModel + gifColumnCModel: GifColumnModel proc delete*(self: View) = self.model.delete @@ -17,6 +22,9 @@ QtObject: result.QObject.setup result.delegate = delegate result.model = newModel() + result.gifColumnAModel = newGifColumnModel() + result.gifColumnBModel = newGifColumnModel() + result.gifColumnCModel = newGifColumnModel() proc load*(self: View) = self.delegate.viewDidLoad() @@ -48,4 +56,97 @@ QtObject: proc acceptRequestTransaction*(self: View, transactionHash: string, messageId: string, signature: string) {.slot.} = self.delegate.acceptRequestTransaction(transactionHash, messageId, signature) - \ No newline at end of file + + proc gifLoaded*(self: View) {.signal.} + + proc getGifColumnA*(self: View): QVariant {.slot.} = + result = newQVariant(self.gifColumnAModel) + + QtProperty[QVariant] gifColumnA: + read = getGifColumnA + notify = gifLoaded + + proc getGifColumnB*(self: View): QVariant {.slot.} = + result = newQVariant(self.gifColumnBModel) + + QtProperty[QVariant] gifColumnB: + read = getGifColumnB + notify = gifLoaded + + proc getGifColumnC*(self: View): QVariant {.slot.} = + result = newQVariant(self.gifColumnCModel) + + QtProperty[QVariant] gifColumnC: + read = getGifColumnC + notify = gifLoaded + + proc updateGifColumns(self: View, data: seq[GifDto]) = + var columnAData: seq[GifDto] = @[] + var columnAHeight = 0 + var columnBData: seq[GifDto] = @[] + var columnBHeight = 0 + var columnCData: seq[GifDto] = @[] + var columnCHeight = 0 + + for item in data: + if columnAHeight <= columnBHeight: + columnAData.add(item) + columnAHeight += item.height + elif columnBHeight <= columnCHeight: + columnBData.add(item) + columnBHeight += item.height + else: + columnCData.add(item) + columnCHeight += item.height + + + self.gifColumnAModel.setNewData(columnAData) + self.gifColumnBModel.setNewData(columnBData) + self.gifColumnCModel.setNewData(columnCData) + self.gifLoaded() + + proc searchGifs*(self: View, query: string) {.slot.} = + let data = self.delegate.searchGifs(query) + self.updateGifColumns(data) + + proc getTrendingsGifs*(self: View) {.slot.} = + let data = self.delegate.getTrendingsGifs() + self.updateGifColumns(data) + + proc getRecentsGifs*(self: View) {.slot.} = + let data = self.delegate.getRecentsGifs() + self.updateGifColumns(data) + + proc getFavoritesGifs*(self: View) {.slot.} = + let data = self.delegate.getFavoritesGifs() + self.updateGifColumns(data) + + proc findGifDto(self: View, id: string): GifDto = + for item in self.gifColumnAModel.gifs: + if item.id == id: + return item + + for item in self.gifColumnBModel.gifs: + if item.id == id: + return item + + for item in self.gifColumnCModel.gifs: + if item.id == id: + return item + + raise newException(ValueError, "Invalid id " & $id) + + proc toggleFavoriteGif*(self: View, id: string, reload: bool = false) {.slot.} = + let gifItem = self.findGifDto(id) + self.delegate.toggleFavoriteGif(gifItem) + + if reload: + self.getFavoritesGifs() + + proc addToRecentsGif*(self: View, id: string) {.slot.} = + let gifItem = self.findGifDto(id) + self.delegate.addToRecentsGif(gifItem) + + proc isFavorite*(self: View, id: string): bool {.slot.} = + let gifItem = self.findGifDto(id) + return self.delegate.isFavorite(gifItem) \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index 6aa8542118..6f42264a32 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -16,6 +16,7 @@ import ../../../../../app_service/service/settings/service_interface as settings import ../../../../../app_service/service/contacts/service as contact_service import ../../../../../app_service/service/chat/service as chat_service import ../../../../../app_service/service/community/service as community_service +import ../../../../../app_service/service/gif/service as gif_service import ../../../../../app_service/service/message/service as message_service export io_interface @@ -37,7 +38,7 @@ type proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, sectionId: string, chatId: string, belongsToCommunity: bool, isUsersListAvailable: bool, settingsService: settings_service.ServiceInterface, contactService: contact_service.Service, chatService: chat_service.Service, - communityService: community_service.Service, messageService: message_service.Service): + communityService: community_service.Service, messageService: message_service.Service, gifService: gif_service.Service): Module = result = Module() result.delegate = delegate @@ -47,7 +48,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitt isUsersListAvailable, settingsService, contactService, chatService, communityService, messageService) result.moduleLoaded = false - result.inputAreaModule = input_area_module.newModule(result, sectionId, chatId, belongsToCommunity, chatService, communityService) + result.inputAreaModule = input_area_module.newModule(result, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService) result.messagesModule = messages_module.newModule(result, events, sectionId, chatId, belongsToCommunity, contactService, communityService, chatService, messageService) result.usersModule = users_module.newModule(result, events, sectionId, chatId, belongsToCommunity, isUsersListAvailable, diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index 8ec3448b65..2ae5687311 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -14,6 +14,7 @@ import ../../../../app_service/service/contacts/service as contact_service import ../../../../app_service/service/chat/service as chat_service import ../../../../app_service/service/community/service as community_service import ../../../../app_service/service/message/service as message_service +import ../../../../app_service/service/gif/service as gif_service export io_interface @@ -39,7 +40,7 @@ proc newModule*( contactService: contact_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service + messageService: message_service.Service, ): Module = result = Module() result.delegate = delegate @@ -73,10 +74,11 @@ proc addSubmodule(self: Module, chatId: string, belongToCommunity: bool, isUsers contactService: contact_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service) = + messageService: message_service.Service, + gifService: gif_service.Service) = self.chatContentModules[chatId] = chat_content_module.newModule(self, events, self.controller.getMySectionId(), chatId, belongToCommunity, isUsersListAvailable, settingsService, contactService, chatService, communityService, - messageService) + messageService, gifService) proc removeSubmodule(self: Module, chatId: string) = if(not self.chatContentModules.contains(chatId)): @@ -88,7 +90,8 @@ proc buildChatUI(self: Module, events: EventEmitter, contactService: contact_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service) = + messageService: message_service.Service, + gifService: gif_service.Service) = let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat] let chats = self.controller.getChatDetailsForChatTypes(types) @@ -110,7 +113,7 @@ proc buildChatUI(self: Module, events: EventEmitter, hasNotification, notificationsCount, c.muted, false, 0) self.view.chatsModel().appendItem(item) self.addSubmodule(c.id, false, isUsersListAvailable, events, settingsService, contactService, chatService, - communityService, messageService) + communityService, messageService, gifService) # make the first Public chat active when load the app if(selectedItemId.len == 0 and c.chatType == ChatType.Public): @@ -123,7 +126,8 @@ proc buildCommunityUI(self: Module, events: EventEmitter, contactService: contact_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service) = + messageService: message_service.Service, + gifService: gif_service.Service) = var selectedItemId = "" var selectedSubItemId = "" let communities = self.controller.getJoinedCommunities() @@ -143,7 +147,7 @@ proc buildCommunityUI(self: Module, events: EventEmitter, chatDto.chatType.int, amIChatAdmin, hasNotification, notificationsCount, chatDto.muted, false, c.position) self.view.chatsModel().appendItem(channelItem) self.addSubmodule(chatDto.id, true, true, events, settingsService, contactService, chatService, communityService, - messageService) + messageService, gifService) # make the first channel which doesn't belong to any category active when load the app if(selectedItemId.len == 0): @@ -173,7 +177,7 @@ proc buildCommunityUI(self: Module, events: EventEmitter, false, c.position) categoryChannels.add(channelItem) self.addSubmodule(chatDto.id, true, true, events, settingsService, contactService, chatService, communityService, - messageService) + messageService, gifService) # in case there is no channels beyond categories, # make the first channel of the first category active when load the app @@ -216,14 +220,15 @@ method load*(self: Module, events: EventEmitter, contactService: contact_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service) = + messageService: message_service.Service, + gifService: gif_service.Service) = self.controller.init() self.view.load() if(self.controller.isCommunity()): - self.buildCommunityUI(events, settingsService, contactService, chatService, communityService, messageService) + self.buildCommunityUI(events, settingsService, contactService, chatService, communityService, messageService, gifService) else: - self.buildChatUI(events, settingsService, contactService, chatService, communityService, messageService) + self.buildChatUI(events, settingsService, contactService, chatService, communityService, messageService, gifService) self.initContactRequestsModel() # we do this only in case of chat section (not in case of communities) for cModule in self.chatContentModules.values: @@ -309,7 +314,8 @@ method addNewChat*( contactService: contact_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service) = + messageService: message_service.Service, + gifService: gif_service.Service) = let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0 let notificationsCount = chatDto.unviewedMentionsCount var chatName = chatDto.name @@ -323,7 +329,7 @@ method addNewChat*( let item = initItem(chatDto.id, chatName, chatImage, isIdenticon, chatDto.color, chatDto.description, chatDto.chatType.int, amIChatAdmin, hasNotification, notificationsCount, chatDto.muted, false, 0) self.addSubmodule(chatDto.id, false, isUsersListAvailable, events, settingsService, contactService, chatService, - communityService, messageService) + communityService, messageService, gifService) self.chatContentModules[chatDto.id].load() self.view.chatsModel().appendItem(item) diff --git a/src/app/modules/main/chat_section/private_interfaces/module_access_interface.nim b/src/app/modules/main/chat_section/private_interfaces/module_access_interface.nim index 3d03a51357..e641a66943 100644 --- a/src/app/modules/main/chat_section/private_interfaces/module_access_interface.nim +++ b/src/app/modules/main/chat_section/private_interfaces/module_access_interface.nim @@ -5,6 +5,7 @@ import ../../../../../app_service/service/contacts/service as contact_service import ../../../../../app_service/service/chat/service as chat_service import ../../../../../app_service/service/community/service as community_service import ../../../../../app_service/service/message/service as message_service +import ../../../../../app_service/service/gif/service as gif_service import ../../../../core/eventemitter @@ -16,7 +17,8 @@ method load*(self: AccessInterface, events: EventEmitter, contactService: contact_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service) {.base.} = + messageService: message_service.Service, + gifService: gif_service.Service) {.base.} = raise newException(ValueError, "No implementation available") method isLoaded*(self: AccessInterface): bool {.base.} = diff --git a/src/app/modules/main/controller.nim b/src/app/modules/main/controller.nim index 2949999a67..d2c78706a4 100644 --- a/src/app/modules/main/controller.nim +++ b/src/app/modules/main/controller.nim @@ -10,6 +10,7 @@ import ../../../app_service/service/chat/service as chat_service import ../../../app_service/service/community/service as community_service import ../../../app_service/service/contacts/service as contacts_service import ../../../app_service/service/message/service as message_service +import ../../../app_service/service/gif/service as gif_service export controller_interface @@ -27,6 +28,7 @@ type communityService: community_service.Service messageService: message_service.Service contactsService: contacts_service.Service + gifService: gif_service.Service activeSectionId: string proc newController*(delegate: io_interface.AccessInterface, @@ -37,7 +39,9 @@ proc newController*(delegate: io_interface.AccessInterface, chatService: chat_service.Service, communityService: community_service.Service, contactsService: contacts_service.Service, - messageService: message_service.Service): + messageService: message_service.Service, + gifService: gif_service.Service, +): Controller = result = Controller() result.delegate = delegate @@ -49,6 +53,7 @@ proc newController*(delegate: io_interface.AccessInterface, result.communityService = communityService result.contactsService = contactsService result.messageService = messageService + result.gifService = gifService method delete*(self: Controller) = discard @@ -83,8 +88,9 @@ method init*(self: Controller) = self.contactsService, self.chatService, self.communityService, - self.messageService - ) + self.messageService, + self.gifService, + ) self.events.on(TOGGLE_SECTION) do(e:Args): let args = ToggleSectionArgs(e) @@ -99,8 +105,9 @@ method init*(self: Controller) = self.contactsService, self.chatService, self.communityService, - self.messageService - ) + self.messageService, + self.gifService, + ) self.events.on(SIGNAL_COMMUNITY_LEFT) do(e:Args): let args = CommunityIdArgs(e) diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 83ffd2fc21..3c40ef5a70 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -41,6 +41,8 @@ import ../../../app_service/service/node/service as node_service import ../../../app_service/service/node_configuration/service_interface as node_configuration_service import ../../../app_service/service/devices/service as devices_service import ../../../app_service/service/mailservers/service as mailservers_service +import ../../../app_service/service/gif/service as gif_service + import ../../core/eventemitter @@ -91,8 +93,9 @@ proc newModule*[T]( nodeConfigurationService: node_configuration_service.ServiceInterface, devicesService: devices_service.Service, mailserversService: mailservers_service.Service, - nodeService: node_service.Service - ): Module[T] = + nodeService: node_service.Service, + gifService: gif_service.Service, +): Module[T] = result = Module[T]() result.delegate = delegate result.view = view.newView(result) @@ -106,7 +109,8 @@ proc newModule*[T]( chatService, communityService, contactsService, - messageService + messageService, + gifService, ) result.moduleLoaded = false @@ -176,14 +180,15 @@ proc createCommunityItem[T](self: Module[T], c: CommunityDto): SectionItem = c.members.map(x => member_item.initItem(x.id, x.roles))) method load*[T]( - self: Module[T], - events: EventEmitter, - settingsService: settings_service.ServiceInterface, - contactsService: contacts_service.Service, - chatService: chat_service.Service, - communityService: community_service.Service, - messageService: message_service.Service - ) = + self: Module[T], + events: EventEmitter, + settingsService: settings_service.ServiceInterface, + contactsService: contacts_service.Service, + chatService: chat_service.Service, + communityService: community_service.Service, + messageService: message_service.Service, + gifService: gif_service.Service, +) = singletonInstance.engine.setRootContextProperty("mainModule", self.viewVariant) self.controller.init() self.view.load() @@ -201,7 +206,7 @@ method load*[T]( contactsService, chatService, communityService, - messageService + messageService, ) var activeSection: SectionItem @@ -310,9 +315,9 @@ method load*[T]( activeSection = profileSettingsSectionItem # Load all sections - self.chatSectionModule.load(events, settingsService, contactsService, chatService, communityService, messageService) + self.chatSectionModule.load(events, settingsService, contactsService, chatService, communityService, messageService, gifService) for cModule in self.communitySectionsModule.values: - cModule.load(events, settingsService, contactsService, chatService, communityService, messageService) + cModule.load(events, settingsService, contactsService, chatService, communityService, messageService, gifService) self.walletSectionModule.load() # self.walletV2SectionModule.load() self.browserSectionModule.load() @@ -489,15 +494,16 @@ method getAppSearchModule*[T](self: Module[T]): QVariant = self.appSearchModule.getModuleAsVariant() method communityJoined*[T]( - self: Module[T], - community: CommunityDto, - events: EventEmitter, - settingsService: settings_service.ServiceInterface, - contactsService: contacts_service.Service, - chatService: chat_service.Service, - communityService: community_service.Service, - messageService: message_service.Service - ) = + self: Module[T], + community: CommunityDto, + events: EventEmitter, + settingsService: settings_service.ServiceInterface, + contactsService: contacts_service.Service, + chatService: chat_service.Service, + communityService: community_service.Service, + messageService: message_service.Service, + gifService: gif_service.Service, +) = self.communitySectionsModule[community.id] = chat_section_module.newModule( self, events, @@ -509,7 +515,7 @@ method communityJoined*[T]( communityService, messageService ) - self.communitySectionsModule[community.id].load(events, settingsService, contactsService, chatService, communityService, messageService) + self.communitySectionsModule[community.id].load(events, settingsService, contactsService, chatService, communityService, messageService, gifService) let communitySectionItem = self.createCommunityItem(community) self.view.addItem(communitySectionItem) diff --git a/src/app/modules/main/private_interfaces/module_access_interface.nim b/src/app/modules/main/private_interfaces/module_access_interface.nim index 454dcee665..80b2947e0f 100644 --- a/src/app/modules/main/private_interfaces/module_access_interface.nim +++ b/src/app/modules/main/private_interfaces/module_access_interface.nim @@ -3,6 +3,7 @@ import ../../../../app_service/service/contacts/service as contacts_service import ../../../../app_service/service/chat/service as chat_service import ../../../../app_service/service/community/service as community_service import ../../../../app_service/service/message/service as message_service +import ../../../../app_service/service/gif/service as gif_service import ../../../core/eventemitter @@ -16,7 +17,8 @@ method load*( contactsService: contacts_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service + messageService: message_service.Service, + gifService: gif_service.Service, ) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/private_interfaces/module_controller_delegate_interface.nim b/src/app/modules/main/private_interfaces/module_controller_delegate_interface.nim index 03c104920c..c34e27ab01 100644 --- a/src/app/modules/main/private_interfaces/module_controller_delegate_interface.nim +++ b/src/app/modules/main/private_interfaces/module_controller_delegate_interface.nim @@ -20,7 +20,8 @@ method communityJoined*(self: AccessInterface, community: CommunityDto, events: contactsService: contacts_service.Service, chatService: chat_service.Service, communityService: community_service.Service, - messageService: message_service.Service) {.base.} = + messageService: message_service.Service, + gifService: gif_service.Service) {.base.} = raise newException(ValueError, "No implementation available") method communityEdited*(self: AccessInterface, community: CommunityDto) {.base.} = diff --git a/src/app_service/service/gif/dto.nim b/src/app_service/service/gif/dto.nim new file mode 100644 index 0000000000..34c4f3154b --- /dev/null +++ b/src/app_service/service/gif/dto.nim @@ -0,0 +1,40 @@ +import json, strformat + +type + GifDto* = object + id*: string + title*: string + url*: string + tinyUrl*: string + height*: int + isFavorite*: bool + +proc tenorToGifDto*(jsonMsg: JsonNode): GifDto = + return GifDto( + id: jsonMsg{"id"}.getStr, + title: jsonMsg{"title"}.getStr, + url: jsonMsg{"media"}[0]["gif"]["url"].getStr, + tinyUrl: jsonMsg{"media"}[0]["tinygif"]["url"].getStr, + height: jsonMsg{"media"}[0]["gif"]["dims"][1].getInt + ) + +proc settingToGifDto*(jsonMsg: JsonNode): GifDto = + return GifDto( + id: jsonMsg{"id"}.getStr, + title: jsonMsg{"title"}.getStr, + url: jsonMsg{"url"}.getStr, + tinyUrl: jsonMsg{"tinyUrl"}.getStr, + height: jsonMsg{"height"}.getInt + ) + +proc toJsonNode*(self: GifDto): JsonNode = + result = %* { + "id": self.id, + "title": self.title, + "url": self.url, + "tinyUrl": self.tinyUrl, + "height": self.height + } + +proc `$`*(self: GifDto): string = + return fmt"GifDto(id:{self.id}, title:{self.title}, url:{self.url}, tinyUrl:{self.tinyUrl}, height:{self.height})" diff --git a/src/app_service/service/gif/service.nim b/src/app_service/service/gif/service.nim new file mode 100644 index 0000000000..4156a1b8c6 --- /dev/null +++ b/src/app_service/service/gif/service.nim @@ -0,0 +1,148 @@ +import httpclient +import json +import strformat +import os +import uri +import chronicles +import sequtils + +import ../settings/service_interface as settings_service +import ./dto +import ./service_interface + +logScope: + topics = "gif-service" + +const MAX_RECENT = 50 +# set via `nim c` param `-d:TENOR_API_KEY:[api_key]`; should be set in CI/release builds +const TENOR_API_KEY {.strdefine.} = "" +let TENOR_API_KEY_ENV = $getEnv("TENOR_API_KEY") + +let TENOR_API_KEY_RESOLVED = + if TENOR_API_KEY_ENV != "": + TENOR_API_KEY_ENV + else: + TENOR_API_KEY + +const baseUrl = "https://g.tenor.com/v1/" +let defaultParams = fmt("&media_filter=minimal&limit=50&key={TENOR_API_KEY_RESOLVED}") + +type + Service* = ref object of service_interface.ServiceInterface + settingsService: settings_service.ServiceInterface + client: HttpClient + favorites: seq[GifDto] + recents: seq[GifDto] + favoritesLoaded: bool + recentsLoaded: bool + +method delete*(self: Service) = + discard + +proc newService*(settingsService: settings_service.ServiceInterface): Service = + result = Service() + result.settingsService = settingsService + result.client = newHttpClient() + result.favorites = @[] + result.recents = @[] + +proc setFavoriteGifs(self: Service, gifDtos: seq[GifDto]) = + let node = %*{"items": map(gifDtos, toJsonNode)} + discard self.settingsService.saveGifFavorites(node) + +proc setRecentGifs(self: Service, gifDtos: seq[GifDto]) = + let node = %*{"items": map(gifDtos, toJsonNode)} + discard self.settingsService.saveGifRecents(node) + +proc getContentWithRetry(self: Service, path: string, maxRetry: int = 3): string = + var currentRetry = 0 + while true: + try: + let content = self.client.getContent(fmt("{baseUrl}{path}{defaultParams}")) + return content + except Exception as e: + currentRetry += 1 + error "could not query tenor API", msg=e.msg + + if currentRetry >= maxRetry: + raise + + sleep(100 * currentRetry) + +proc tenorQuery(self: Service, path: string): seq[GifDto] = + try: + let content = self.getContentWithRetry(path) + let doc = content.parseJson() + + var items: seq[GifDto] = @[] + for json in doc["results"]: + items.add(tenorToGifDto(json)) + + return items + except: + return @[] + +proc search*(self: Service, query: string): seq[GifDto] = + return self.tenorQuery(fmt("search?q={encodeUrl(query)}")) + +proc getTrendings*(self: Service): seq[GifDto] = + return self.tenorQuery("trending?") + +proc getFavorites*(self: Service): seq[GifDto] = + if not self.favoritesLoaded: + self.favoritesLoaded = true + let node = self.settingsService.getGifFavorites() + self.favorites = map(node{"items"}.getElems(), settingToGifDto) + + return self.favorites + +proc getRecents*(self: Service): seq[GifDto] = + if not self.recentsLoaded: + self.recentsLoaded = true + let node = self.settingsService.getGifRecents() + self.recents = map(node{"items"}.getElems(), settingToGifDto) + + return self.recents + +proc isFavorite*(self: Service, gifDto: GifDto): bool = + for favorite in self.getFavorites(): + if favorite.id == gifDto.id: + return true + + return false + +proc toggleFavorite*(self: Service, gifDto: GifDto) = + var newFavorites: seq[GifDto] = @[] + var found = false + + for favoriteGif in self.getFavorites(): + if favoriteGif.id == gifDto.id: + found = true + continue + + newFavorites.add(favoriteGif) + + if not found: + newFavorites.add(gifDto) + + self.favorites = newFavorites + self.setFavoriteGifs(newFavorites) + +proc addToRecents*(self: Service, gifDto: GifDto) = + let recents = self.getRecents() + var newRecents: seq[GifDto] = @[gifDto] + var idx = 0 + + while idx < MAX_RECENT - 1: + if idx >= recents.len: + break + + if recents[idx].id == gifDto.id: + idx += 1 + continue + + newRecents.add(recents[idx]) + idx += 1 + + self.recents = newRecents + self.setRecentGifs(newRecents) \ No newline at end of file diff --git a/src/app_service/service/gif/service_interface.nim b/src/app_service/service/gif/service_interface.nim new file mode 100644 index 0000000000..ec1d335eb5 --- /dev/null +++ b/src/app_service/service/gif/service_interface.nim @@ -0,0 +1,6 @@ +type + ServiceInterface* {.pure inheritable.} = ref object of RootObj + ## Abstract class for this service access. + +method delete*(self: ServiceInterface) {.base.} = + raise newException(ValueError, "No implementation available") diff --git a/src/app_service/service/settings/dto/settings.nim b/src/app_service/service/settings/dto/settings.nim index eb95e9bc1e..e08379b4af 100644 --- a/src/app_service/service/settings/dto/settings.nim +++ b/src/app_service/service/settings/dto/settings.nim @@ -41,6 +41,8 @@ const KEY_FLEET* = "fleet" const KEY_NODE_CONFIG* = "node-config" const KEY_WAKU_BLOOM_FILTER_MODE* = "waku-bloom-filter-mode" const KEY_AUTO_MESSAGE_ENABLED* = "auto-message-enabled?" +const KEY_GIF_FAVORITES* = "gifs/favorite-gifs" +const KEY_GIF_RECENTS* = "gifs/recent-gifs" type UpstreamConfig* = object Enabled*: bool @@ -112,6 +114,8 @@ type recentStickerHashes*: seq[string] installedStickerPacks*: Table[int, StickerPackDto] autoMessageEnabled*: bool + gifRecents*: JsonNode + gifFavorites*: JsonNode proc toUpstreamConfig*(jsonObj: JsonNode): UpstreamConfig = discard jsonObj.getProp("Enabled", result.Enabled) @@ -208,6 +212,8 @@ proc toSettingsDto*(jsonObj: JsonNode): SettingsDto = discard jsonObj.getProp(KEY_TELEMETRY_SERVER_URL, result.telemetryServerUrl) discard jsonObj.getProp(KEY_FLEET, result.fleet) discard jsonObj.getProp(KEY_AUTO_MESSAGE_ENABLED, result.autoMessageEnabled) + discard jsonObj.getProp(KEY_GIF_RECENTS, result.gifRecents) + discard jsonObj.getProp(KEY_GIF_FAVORITES, result.gifFavorites) var pinnedMailserverObj: JsonNode if(jsonObj.getProp(KEY_PINNED_MAILSERVERS, pinnedMailserverObj)): diff --git a/src/app_service/service/settings/service.nim b/src/app_service/service/settings/service.nim index 165704739f..13521bfc27 100644 --- a/src/app_service/service/settings/service.nim +++ b/src/app_service/service/settings/service.nim @@ -449,3 +449,21 @@ method autoMessageEnabled*(self: Service): bool = method getWakuBloomFilterMode*(self: Service): bool = return self.settings.wakuBloomFilterMode + +method getGifRecents*(self: Service): JsonNode = + return self.settings.gifRecents + +method getGifFavorites*(self: Service): JsonNode = + return self.settings.gifFavorites + +method saveGifRecents*(self: Service, value: JsonNode): bool = + if(self.saveSetting(KEY_GIF_RECENTS, value)): + self.settings.gifRecents = value + return true + return false + +method saveGifFavorites*(self: Service, value: JsonNode): bool = + if(self.saveSetting(KEY_GIF_FAVORITES, value)): + self.settings.gifFavorites = value + return true + return false \ No newline at end of file diff --git a/src/app_service/service/settings/service_interface.nim b/src/app_service/service/settings/service_interface.nim index a46b2afd79..fb468da8d4 100644 --- a/src/app_service/service/settings/service_interface.nim +++ b/src/app_service/service/settings/service_interface.nim @@ -258,4 +258,16 @@ method autoMessageEnabled*(self: ServiceInterface): bool {.base.} = raise newException(ValueError, "No implementation available") method getWakuBloomFilterMode*(self: ServiceInterface): bool {.base.} = + raise newException(ValueError, "No implementation available") + +method getGifRecents*(self: ServiceInterface): JsonNode {.base.} = + raise newException(ValueError, "No implementation available") + +method getGifFavorites*(self: ServiceInterface): JsonNode {.base.} = + raise newException(ValueError, "No implementation available") + +method saveGifRecents*(self: ServiceInterface, value: JsonNode): bool {.base.} = + raise newException(ValueError, "No implementation available") + +method saveGifFavorites*(self: ServiceInterface, value: JsonNode): bool {.base.} = raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/ui/imports/shared/status/StatusGifColumn.qml b/ui/imports/shared/status/StatusGifColumn.qml index 8577106a54..22e2f630bd 100644 --- a/ui/imports/shared/status/StatusGifColumn.qml +++ b/ui/imports/shared/status/StatusGifColumn.qml @@ -15,6 +15,7 @@ Column { spacing: 8 property alias gifList: repeater property var gifWidth: 0 + property var store property var gifSelected: function () {} property var toggleFavorite: function () {} property string lastHoveredId @@ -51,7 +52,7 @@ Column { StatusBaseButton { id: starButton - property bool favorite: model.isFavorite + property bool favorite: RootStore.isFavorite(model.id) type: StatusFlatRoundButton.Type.Secondary textColor: hovered || favorite ? Style.current.yellow : Style.current.secondaryText @@ -110,8 +111,7 @@ Column { hoverEnabled: true onClicked: function (event) { root.gifSelected(event, model.url) - // Not Refactored Yet -// RootStore.chatsModelInst.gif.addToRecents(model.id) + root.store.addToRecentsGif(model.id) } } } diff --git a/ui/imports/shared/status/StatusGifPopup.qml b/ui/imports/shared/status/StatusGifPopup.qml index b6bb7e67cf..9c31544c5e 100644 --- a/ui/imports/shared/status/StatusGifPopup.qml +++ b/ui/imports/shared/status/StatusGifPopup.qml @@ -22,24 +22,22 @@ Popup { id: popup property var gifSelected: function () {} property var searchGif: Backpressure.debounce(searchBox, 500, function (query) { - // Not Refactored Yet -// RootStore.chatsModelInst.gif.search(query) + RootStore.searchGifs(query) }); property var toggleCategory: function(newCategory) { previousCategory = currentCategory currentCategory = newCategory searchBox.text = "" - // Not Refactored Yet -// if (currentCategory === StatusGifPopup.Category.Trending) { -// RootStore.chatsModelInst.gif.getTrendings() -// } else if(currentCategory === StatusGifPopup.Category.Favorite) { -// RootStore.chatsModelInst.gif.getFavorites() -// } else if(currentCategory === StatusGifPopup.Category.Recent) { -// RootStore.chatsModelInst.gif.getRecents() -// } + if (currentCategory === StatusGifPopup.Category.Trending) { + RootStore.getTrendingsGifs() + } else if(currentCategory === StatusGifPopup.Category.Favorite) { + RootStore.getFavoritesGifs() + } else if(currentCategory === StatusGifPopup.Category.Recent) { + RootStore.getRecentsGifs() + } } property var toggleFavorite: function(item) { -// RootStore.chatsModelInst.gif.toggleFavorite(item.id, currentCategory === StatusGifPopup.Category.Favorite) + RootStore.toggleFavoriteGif(item.id, currentCategory === StatusGifPopup.Category.Favorite) } property alias searchString: searchBox.text property int currentCategory: StatusGifPopup.Category.Trending @@ -68,7 +66,7 @@ Popup { searchBox.text = "" searchBox.forceActiveFocus(Qt.MouseFocusReason) if (RootStore.isTenorWarningAccepted) { -// RootStore.chatsModelInst.gif.getTrendings() + RootStore.getTrendingsGifs() } else { confirmationPopup.open() } @@ -162,9 +160,7 @@ Popup { const headerTextHeight = searchBox.text === "" ? headerText.height : 0 return 400 - gifHeader.height - headerTextHeight } - // Not Refactored Yet - sourceComponent: empty -// sourceComponent: RootStore.chatsModelInst.gif.columnA.rowCount() == 0 ? empty : gifItems + sourceComponent: RootStore.gifColumnA.rowCount() == 0 ? empty : gifItems } Row { @@ -262,8 +258,7 @@ Popup { text: qsTr("Enable") onClicked: { RootStore.setIsTenorWarningAccepted(true); - // Not Refactored Yet -// RootStore.chatsModelInst.gif.getTrendings() + RootStore.getTrendingsGifs() confirmationPopup.close() } } @@ -303,8 +298,8 @@ Popup { visible: currentCategory === StatusGifPopup.Category.Trending || currentCategory === StatusGifPopup.Category.Search onClicked: { if (searchBox.text === "") { - // Not Refactored Yet -// RootStore.chatsModelInst.gif.getTrendings() + RootStore.getTrendingsGifs() + return } @@ -335,36 +330,36 @@ Popup { property string lastHoveredId StatusGifColumn { - // Not Refactored Yet -// gifList.model: RootStore.chatsModelInst.gif.columnA + gifList.model: RootStore.gifColumnA gifWidth: (popup.width / 3) - Style.current.padding gifSelected: popup.gifSelected toggleFavorite: popup.toggleFavorite lastHoveredId: gifs.lastHoveredId + store: RootStore onGifHovered: { gifs.lastHoveredId = id } } StatusGifColumn { - // Not Refactored Yet -// gifList.model: RootStore.chatsModelInst.gif.columnB + gifList.model: RootStore.gifColumnB gifWidth: (popup.width / 3) - Style.current.padding gifSelected: popup.gifSelected toggleFavorite: popup.toggleFavorite lastHoveredId: gifs.lastHoveredId + store: RootStore onGifHovered: { gifs.lastHoveredId = id } } StatusGifColumn { - // Not Refactored Yet -// gifList.model: RootStore.chatsModelInst.gif.columnC + gifList.model: RootStore.gifColumnC gifWidth: (popup.width / 3) - Style.current.padding gifSelected: popup.gifSelected toggleFavorite: popup.toggleFavorite lastHoveredId: gifs.lastHoveredId + store: RootStore onGifHovered: { gifs.lastHoveredId = id } diff --git a/ui/imports/shared/stores/RootStore.qml b/ui/imports/shared/stores/RootStore.qml index a3d1c803cc..172f2f7fbb 100644 --- a/ui/imports/shared/stores/RootStore.qml +++ b/ui/imports/shared/stores/RootStore.qml @@ -72,4 +72,36 @@ QtObject { function copyToClipboard(textToCopy) { // chatsModelInst.copyToClipboard(textToCopy) } + + property var gifColumnA: chatSectionChatContentInputArea.gifColumnA + property var gifColumnB: chatSectionChatContentInputArea.gifColumnB + property var gifColumnC: chatSectionChatContentInputArea.gifColumnC + + function searchGifs(query) { + chatSectionChatContentInputArea.searchGifs(query) + } + + function getTrendingsGifs() { + chatSectionChatContentInputArea.getTrendingsGifs() + } + + function getRecentsGifs() { + chatSectionChatContentInputArea.getRecentsGifs() + } + + function getFavoritesGifs() { + return chatSectionChatContentInputArea.getFavoritesGifs() + } + + function isFavorite(id) { + return chatSectionChatContentInputArea.isFavorite(id) + } + + function toggleFavoriteGif(id, reload) { + chatSectionChatContentInputArea.toggleFavoriteGif(id, reload) + } + + function addToRecentsGif(id) { + chatSectionChatContentInputArea.addToRecentsGif(id) + } }