feat(CommunitiesPortal): Communities Portal first UI approach

Closes #4936
This commit is contained in:
Noelia 2022-05-23 15:11:30 +02:00 committed by Richard Ramos
parent 046aa36565
commit ed39690071
35 changed files with 637 additions and 9 deletions

View File

@ -1,6 +1,10 @@
const CHAT_SECTION_NAME* = "Chat"
const CHAT_SECTION_ICON* = "chat"
const COMMUNITIESPORTAL_SECTION_ID* = "communitiesPortal"
const COMMUNITIESPORTAL_SECTION_NAME* = "Communities Portal"
const COMMUNITIESPORTAL_SECTION_ICON* = "communities"
const WALLET_SECTION_ID* = "wallet"
const WALLET_SECTION_NAME* = "Wallet"
const WALLET_SECTION_ICON* = "wallet"

View File

@ -24,6 +24,8 @@ const LSS_KEY_IS_GIF_WIDGET_ENABLED* = "isGifWidgetEnabled"
const DEFAULT_IS_GIF_WIDGET_ENABLED = true
const LSS_KEY_IS_MULTI_NETWORK_ENABLED* = "isMultiNetworkEnabled"
const DEFAULT_IS_MULTI_NETWORK_ENABLED = false
const LSS_KEY_IS_COMMUNITIES_PORTAL_ENABLED* = "isCommunitiesPortalEnabled"
const DEFAULT_IS_COMMUNITIES_PORTAL_ENABLED = false
const LSS_KEY_IS_TENOR_WARNING_ACCEPTED* = "isTenorWarningAccepted"
const DEFAULT_IS_TENOR_WARNING_ACCEPTED = false
const LSS_KEY_DISPLAY_CHAT_IMAGES* = "displayChatImages"
@ -309,6 +311,18 @@ QtObject:
write = setIsMultiNetworkEnabled
notify = isMultiNetworkEnabledChanged
proc isCommunitiesPortalEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getIsCommunitiesPortalEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_IS_COMMUNITIES_PORTAL_ENABLED, newQVariant(DEFAULT_IS_COMMUNITIES_PORTAL_ENABLED))
proc setIsCommunitiesPortalEnabled*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_IS_COMMUNITIES_PORTAL_ENABLED, newQVariant(value)):
self.isCommunitiesPortalEnabledChanged()
QtProperty[bool] isCommunitiesPortalEnabled:
read = getIsCommunitiesPortalEnabled
write = setIsCommunitiesPortalEnabled
notify = isCommunitiesPortalEnabledChanged
proc isTenorWarningAcceptedChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getIsTenorWarningAccepted*(self: LocalAccountSensitiveSettings): bool {.slot.} =
@ -780,6 +794,7 @@ QtObject:
of LSS_KEY_EXPAND_USERS_LIST: self.expandUsersListChanged()
of LSS_KEY_IS_GIF_WIDGET_ENABLED: self.isGifWidgetEnabledChanged()
of LSS_KEY_IS_MULTI_NETWORK_ENABLED: self.isMultiNetworkEnabledChanged()
of LSS_KEY_IS_COMMUNITIES_PORTAL_ENABLED: self.isCommunitiesPortalEnabledChanged()
of LSS_KEY_IS_TENOR_WARNING_ACCEPTED: self.isTenorWarningAcceptedChanged()
of LSS_KEY_DISPLAY_CHAT_IMAGES: self.displayChatImagesChanged()
of LSS_KEY_RECENT_EMOJIS: self.recentEmojisChanged()

View File

@ -37,6 +37,10 @@ proc init*(self: Controller) =
let args = CommunityArgs(e)
self.delegate.communityAdded(args.community)
self.events.on(SIGNAL_CURATED_COMMUNITY_FOUND) do(e:Args):
let args = CuratedCommunityArgs(e)
self.delegate.curatedCommunityAdded(args.curatedCommunity)
self.events.on(SIGNAL_COMMUNITY_ADDED) do(e:Args):
let args = CommunityArgs(e)
self.delegate.communityAdded(args.community)
@ -52,10 +56,14 @@ proc init*(self: Controller) =
let args = CommunitiesArgs(e)
for community in args.communities:
self.delegate.communityEdited(community)
self.delegate.curatedCommunityEdited(CuratedCommunity(communityId: community.id, available: true, community:community))
proc getAllCommunities*(self: Controller): seq[CommunityDto] =
result = self.communityService.getAllCommunities()
proc getCuratedCommunities*(self: Controller): seq[CuratedCommunity] =
result = self.communityService.getCuratedCommunities()
proc joinCommunity*(self: Controller, communityId: string): string =
self.communityService.joinCommunity(communityId)

View File

@ -16,6 +16,9 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
method setAllCommunities*(self: AccessInterface, communities: seq[CommunityDto]) {.base.} =
raise newException(ValueError, "No implementation available")
method setCuratedCommunities*(self: AccessInterface, curatedCommunities: seq[CommunityDto]) {.base.} =
raise newException(ValueError, "No implementation available")
method getCommunityItem*(self: AccessInterface, community: CommunityDto): SectionItem {.base.} =
raise newException(ValueError, "No implementation available")
@ -82,6 +85,12 @@ method communityEdited*(self: AccessInterface, community: CommunityDto) {.base.}
method communityAdded*(self: AccessInterface, community: CommunityDto) {.base.} =
raise newException(ValueError, "No implementation available")
method curatedCommunityAdded*(self: AccessInterface, community: CuratedCommunity) {.base.} =
raise newException(ValueError, "No implementation available")
method curatedCommunityEdited*(self: AccessInterface, community: CuratedCommunity) {.base.} =
raise newException(ValueError, "No implementation available")
method communityImported*(self: AccessInterface, community: CommunityDto) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -0,0 +1,59 @@
import strformat
type
CuratedCommunityItem* = object
id: string
name: string
description: string
available: bool
icon: string
color: string
members: int
proc initCuratedCommunityItem*(
id: string,
name: string,
description: string,
available: bool,
icon: string,
color: string,
members: int
): CuratedCommunityItem =
result.id = id
result.name = name
result.description = description
result.available = available
result.icon = icon
result.color = color
result.members = members
proc `$`*(self: CuratedCommunityItem): string =
result = fmt"""CuratedCommunityItem(
id: {self.id},
name: {self.name},
description: {self.description},
available: {self.available},
color: {self.color},
members: {self.members}
]"""
proc getId*(self: CuratedCommunityItem): string =
return self.id
proc getName*(self: CuratedCommunityItem): string =
return self.name
proc getDescription*(self: CuratedCommunityItem): string =
return self.description
proc isAvailable*(self: CuratedCommunityItem): bool =
return self.available
proc getIcon*(self: CuratedCommunityItem): string =
return self.icon
proc getMembers*(self: CuratedCommunityItem): int =
return self.members
proc getColor*(self: CuratedCommunityItem): string =
return self.color

View File

@ -0,0 +1,135 @@
import NimQml, Tables
import curated_community_item
type
ModelRole {.pure.} = enum
Id = UserRole + 1
Available
Name
Description
Icon
Featured
Members
Popularity
Color
QtObject:
type CuratedCommunityModel* = ref object of QAbstractListModel
items*: seq[CuratedCommunityItem]
proc setup(self: CuratedCommunityModel) =
self.QAbstractListModel.setup
proc delete(self: CuratedCommunityModel) =
self.items = @[]
self.QAbstractListModel.delete
proc newCuratedCommunityModel*(): CuratedCommunityModel =
new(result, delete)
result.setup
proc countChanged(self: CuratedCommunityModel) {.signal.}
proc setItems*(self: CuratedCommunityModel, items: seq[CuratedCommunityItem]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc getCount(self: CuratedCommunityModel): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: CuratedCommunityModel, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: CuratedCommunityModel): Table[int, string] =
{
ModelRole.Id.int:"id",
ModelRole.Name.int:"name",
ModelRole.Available.int:"available",
ModelRole.Description.int:"description",
ModelRole.Icon.int:"icon",
ModelRole.Featured.int:"featured",
ModelRole.Members.int:"members",
ModelRole.Color.int:"color",
ModelRole.Popularity.int:"popularity"
}.toTable
method data(self: CuratedCommunityModel, index: QModelIndex, role: int): QVariant =
if not index.isValid:
return
if index.row < 0 or index.row >= self.items.len:
return
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.Id:
result = newQVariant(item.getId())
of ModelRole.Name:
result = newQVariant(item.getName())
of ModelRole.Description:
result = newQVariant(item.getDescription())
of ModelRole.Available:
result = newQVariant(item.isAvailable())
of ModelRole.Icon:
result = newQVariant(item.getIcon())
of ModelRole.Members:
result = newQVariant(item.getMembers())
of ModelRole.Color:
result = newQVariant(item.getColor())
of ModelRole.Popularity:
# TODO: replace this with a real value
result = newQVariant(index.row)
of ModelRole.Featured:
# TODO: replace this with a real value
var featured = false
if index.row < 3:
featured = true
result = newQVariant(featured)
proc findIndexById(self: CuratedCommunityModel, id: string): int =
for i in 0 ..< self.items.len:
if(self.items[i].getId() == id):
return i
return -1
proc containsItemWithId*(self: CuratedCommunityModel, id: string): bool =
return self.findIndexById(id) != -1
proc removeItemWithId*(self: CuratedCommunityModel, id: string) =
let ind = self.findIndexById(id)
if(ind == -1):
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, ind, ind)
self.items.delete(ind)
self.endRemoveRows()
self.countChanged()
proc addItem*(self: CuratedCommunityModel, item: CuratedCommunityItem) =
let idx = self.findIndexById(item.getId())
if idx > -1:
let index = self.createIndex(idx, 0, nil)
self.items[idx] = item
self.dataChanged(index, index, @[ModelRole.Name.int,
ModelRole.Available.int,
ModelRole.Description.int,
ModelRole.Icon.int,
ModelRole.Featured.int,
ModelRole.Members.int,
ModelRole.Color.int,
ModelRole.Popularity.int])
else:
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.countChanged()

View File

@ -3,6 +3,8 @@ import NimQml, json, sequtils, sugar
import ./io_interface
import ../io_interface as delegate_interface
import ./view, ./controller
import ./models/curated_community_item
import ./models/curated_community_model
import ../../shared_models/section_item
import ../../shared_models/[user_item, user_model, section_model]
import ../../../global/global_singleton
@ -29,6 +31,7 @@ type
# Forward declaration
method setAllCommunities*(self: Module, communities: seq[CommunityDto])
method setCuratedCommunities*(self: Module, curatedCommunities: seq[CuratedCommunity])
proc newModule*(
delegate: delegate_interface.AccessInterface,
@ -64,6 +67,7 @@ method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.setAllCommunities(self.controller.getAllCommunities())
self.setCuratedCommunities(self.controller.getCuratedCommunities())
self.delegate.communitiesModuleDidLoad()
@ -104,6 +108,16 @@ method getCommunityItem(self: Module, c: CommunityDto): SectionItem =
historyArchiveSupportEnabled = c.settings.historyArchiveSupportEnabled
)
method getCuratedCommunityItem(self: Module, c: CuratedCommunity): CuratedCommunityItem =
return initCuratedCommunityItem(
c.communityId,
c.community.name,
c.community.description,
c.available,
c.community.images.thumbnail,
c.community.color,
len(c.community.members))
method setAllCommunities*(self: Module, communities: seq[CommunityDto]) =
for community in communities:
self.view.addItem(self.getCommunityItem(community))
@ -118,6 +132,16 @@ method communityEdited*(self: Module, community: CommunityDto) =
self.view.model().editItem(self.getCommunityItem(community))
self.view.communityChanged(community.id)
method setCuratedCommunities*(self: Module, curatedCommunities: seq[CuratedCommunity]) =
for community in curatedCommunities:
self.view.curatedCommunitiesModel().addItem(self.getCuratedCommunityItem(community))
method curatedCommunityAdded*(self: Module, community: CuratedCommunity) =
self.view.curatedCommunitiesModel().addItem(self.getCuratedCommunityItem(community))
method curatedCommunityEdited*(self: Module, community: CuratedCommunity) =
self.view.curatedCommunitiesModel().addItem(self.getCuratedCommunityItem(community))
method requestAdded*(self: Module) =
# TODO to model or view
discard

View File

@ -4,6 +4,8 @@ import ./io_interface
import ../../shared_models/section_model
import ../../shared_models/section_item
import ../../shared_models/active_section
import ./models/curated_community_item
import ./models/curated_community_model
QtObject:
type
@ -12,11 +14,15 @@ QtObject:
model: SectionModel
modelVariant: QVariant
observedItem: ActiveSection
curatedCommunitiesModel: CuratedCommunityModel
curatedCommunitiesModelVariant: QVariant
proc delete*(self: View) =
self.model.delete
self.modelVariant.delete
self.observedItem.delete
self.curatedCommunitiesModel.delete
self.curatedCommunitiesModelVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
@ -25,6 +31,8 @@ QtObject:
result.delegate = delegate
result.model = newModel()
result.modelVariant = newQVariant(result.model)
result.curatedCommunitiesModel = newCuratedCommunityModel()
result.curatedCommunitiesModelVariant = newQVariant(result.curatedCommunitiesModel)
result.observedItem = newActiveSection()
proc load*(self: View) =
@ -46,6 +54,15 @@ QtObject:
QtProperty[QVariant] model:
read = getModel
proc curatedCommunitiesModel*(self: View): CuratedCommunityModel =
result = self.curatedCommunitiesModel
proc getCuratedCommunitiesModel(self: View): QVariant {.slot.} =
return self.curatedCommunitiesModelVariant
QtProperty[QVariant] curatedCommunities:
read = getCuratedCommunitiesModel
proc observedItemChanged*(self:View) {.signal.}
proc getObservedItem(self: View): QVariant {.slot.} =

View File

@ -286,6 +286,21 @@ method load*[T](
self.channelGroupModules[channelGroup.id].load(channelGroup, events, settingsService,
contactsService, chatService, communityService, messageService, gifService, mailserversService)
# Communities Portal Section
let communitiesPortalSectionItem = initItem(conf.COMMUNITIESPORTAL_SECTION_ID, SectionType.CommunitiesPortal, conf.COMMUNITIESPORTAL_SECTION_NAME,
amISectionAdmin = false,
description = "",
image = "",
conf.COMMUNITIESPORTAL_SECTION_ICON,
color = "",
hasNotification = false,
notificationsCount = 0,
active = false,
enabled = singletonInstance.localAccountSensitiveSettings.getIsCommunitiesPortalEnabled())
self.view.model().addItem(communitiesPortalSectionItem)
if(activeSectionId == communitiesPortalSectionItem.id):
activeSection = communitiesPortalSectionItem
# Wallet Section
let walletSectionItem = initItem(conf.WALLET_SECTION_ID, SectionType.Wallet, conf.WALLET_SECTION_NAME,
amISectionAdmin = false,
@ -359,6 +374,7 @@ method load*[T](
self.nodeSectionModule.load()
# Load wallet last as it triggers events that are listened by other modules
self.walletSectionModule.load()
#self.communitiesPortalSectionModule.load()
# Set active section on app start
self.setActiveSection(activeSection)
@ -371,6 +387,9 @@ proc checkIfModuleDidLoad [T](self: Module[T]) =
if(not cModule.isLoaded()):
return
# if (not self.communitiesPortalSectionModule.isLoaded()):
# return
if (not self.walletSectionModule.isLoaded()):
return
@ -419,6 +438,9 @@ method activityCenterDidLoad*[T](self: Module[T]) =
method communitiesModuleDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()
#method communitiesPortalSectionDidLoad*[T](self: Module[T]) =
# self.checkIfModuleDidLoad()
method walletSectionDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()
@ -490,6 +512,10 @@ proc setSectionAvailability[T](self: Module[T], sectionType: SectionType, availa
self.view.model().disableSection(sectionType)
method toggleSection*[T](self: Module[T], sectionType: SectionType) =
#if (sectionType == SectionType.CommunitiesPortal):
# let enabled = true #singletonInstance.localAccountSensitiveSettings.getIsCommunitiesPortalEnabled()
# self.setSectionAvailability(sectionType, not enabled)
# singletonInstance.localAccountSensitiveSettings.setIsWalletEnabled(not enabled)
if (sectionType == SectionType.Wallet):
let enabled = singletonInstance.localAccountSensitiveSettings.getIsWalletEnabled()
self.setSectionAvailability(sectionType, not enabled)
@ -506,6 +532,10 @@ method toggleSection*[T](self: Module[T], sectionType: SectionType) =
let enabled = singletonInstance.localAccountSensitiveSettings.getNodeManagementEnabled()
self.setSectionAvailability(sectionType, not enabled)
singletonInstance.localAccountSensitiveSettings.setNodeManagementEnabled(not enabled)
elif (sectionType == SectionType.CommunitiesPortal):
let enabled = singletonInstance.localAccountSensitiveSettings.getIsCommunitiesPortalEnabled()
self.setSectionAvailability(sectionType, not enabled)
singletonInstance.localAccountSensitiveSettings.setIsCommunitiesPortalEnabled(not enabled)
method setUserStatus*[T](self: Module[T], status: bool) =
self.controller.setUserStatus(status)

View File

@ -160,6 +160,9 @@ proc addCustomNetwork*(self: Controller, network: settings_service.Network) =
self.delegate.onCustomNetworkAdded(network)
proc toggleCommunitiesPortalSection*(self: Controller) =
self.events.emit(TOGGLE_SECTION, ToggleSectionArgs(sectionType: SectionType.CommunitiesPortal))
proc toggleWalletSection*(self: Controller) =
self.events.emit(TOGGLE_SECTION, ToggleSectionArgs(sectionType: SectionType.Wallet))

View File

@ -99,6 +99,9 @@ method addCustomNetwork*(self: AccessInterface, name: string, endpoint: string,
{.slot.} =
raise newException(ValueError, "No implementation available")
method toggleCommunitiesPortalSection*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method toggleWalletSection*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -156,6 +156,9 @@ method toggleBrowserSection*(self: Module) =
method toggleCommunitySection*(self: Module) =
self.controller.toggleCommunitySection()
method toggleCommunitiesPortalSection*(self: Module) =
self.controller.toggleCommunitiesPortalSection()
method toggleNodeManagementSection*(self: Module) =
self.controller.toggleNodeManagementSection()

View File

@ -169,3 +169,6 @@ QtObject:
proc enableDeveloperFeatures*(self: View) {.slot.} =
self.delegate.enableDeveloperFeatures()
proc toggleCommunitiesPortalSection*(self: View) {.slot.} =
self.delegate.toggleCommunitiesPortalSection()

View File

@ -5,11 +5,12 @@ import ../main/communities/models/[pending_request_item, pending_request_model]
type
SectionType* {.pure.} = enum
Chat = 0
Community,
Community,
Wallet,
Browser,
ProfileSettings,
NodeManagement
NodeManagement,
CommunitiesPortal
type
SectionItem* = object

View File

@ -66,6 +66,11 @@ type CommunityDto* = object
settings*: CommunitySettingsDto
adminSettings*: CommunityAdminSettingsDto
type CuratedCommunity* = object
available*: bool
communityId*: string
community*: CommunityDto
proc toCommunityAdminSettingsDto*(jsonObj: JsonNode): CommunityAdminSettingsDto =
result = CommunityAdminSettingsDto()
discard jsonObj.getProp("pinMessageAllMembersEnabled", result.pinMessageAllMembersEnabled)
@ -133,6 +138,21 @@ proc parseCommunities*(response: RpcResponse[JsonNode]): seq[CommunityDto] =
result = map(response.result.getElems(),
proc(x: JsonNode): CommunityDto = x.toCommunityDto())
proc parseCuratedCommunities*(response: RpcResponse[JsonNode]): seq[CuratedCommunity] =
if (response.result["communities"].kind == JObject):
for (communityId, communityJson) in response.result["communities"].pairs():
result.add(CuratedCommunity(
available: true,
communityId: communityId,
community: communityJson.toCommunityDto()
))
if (response.result["unknownCommunities"].kind == JArray):
for communityId in response.result["unknownCommunities"].items():
result.add(CuratedCOmmunity(
available: false,
communityId: communityId.getStr()
))
proc contains(arrayToSearch: seq[int], searched: int): bool =
for element in arrayToSearch:
if element == searched:

View File

@ -25,6 +25,9 @@ type
community*: CommunityDto
error*: string
fromUserAction*: bool
CuratedCommunityArgs* = ref object of Args
curatedCommunity*: CuratedCommunity
CommunitiesArgs* = ref object of Args
communities*: seq[CommunityDto]
@ -84,6 +87,7 @@ const SIGNAL_COMMUNITY_CATEGORY_REORDERED* = "communityCategoryReordered"
const SIGNAL_COMMUNITY_MEMBER_APPROVED* = "communityMemberApproved"
const SIGNAL_COMMUNITY_MEMBER_REMOVED* = "communityMemberRemoved"
const SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY* = "newRequestToJoinCommunity"
const SIGNAL_CURATED_COMMUNITY_FOUND* = "curatedCommunityFound"
QtObject:
type
@ -92,12 +96,14 @@ QtObject:
events: EventEmitter
chatService: chat_service.Service
joinedCommunities: Table[string, CommunityDto] # [community_id, CommunityDto]
curatedCommunities: Table[string, CuratedCommunity] # [community_id, CuratedCommunity]
allCommunities: Table[string, CommunityDto] # [community_id, CommunityDto]
myCommunityRequests*: seq[CommunityMembershipRequestDto]
# Forward declaration
proc loadAllCommunities(self: Service): seq[CommunityDto]
proc loadJoinedComunities(self: Service): seq[CommunityDto]
proc loadCuratedCommunities(self: Service): seq[CuratedCommunity]
proc loadCommunitiesSettings(self: Service): seq[CommunitySettingsDto]
proc loadMyPendingRequestsToJoin*(self: Service)
proc handleCommunityUpdates(self: Service, communities: seq[CommunityDto], updatedChats: seq[ChatDto])
@ -116,6 +122,7 @@ QtObject:
result.threadpool = threadpool
result.chatService = chatService
result.joinedCommunities = initTable[string, CommunityDto]()
result.curatedCommunities = initTable[string, CuratedCommunity]()
result.allCommunities = initTable[string, CommunityDto]()
result.myCommunityRequests = @[]
@ -125,6 +132,13 @@ QtObject:
self.allCommunities[receivedData.community.id] = receivedData.community
self.events.emit(SIGNAL_COMMUNITY_DATA_IMPORTED, CommunityArgs(community: receivedData.community))
if self.curatedCommunities.contains(receivedData.community.id) and not self.curatedCommunities[receivedData.community.id].available:
let curatedCommunity = CuratedCommunity(available: true,
communityId: receivedData.community.id,
community: receivedData.community)
self.curatedCommunities[receivedData.community.id] = curatedCommunity
self.events.emit(SIGNAL_CURATED_COMMUNITY_FOUND, CuratedCommunityArgs(curatedCommunity: curatedCommunity))
self.events.on(SignalType.Message.event) do(e: Args):
var receivedData = MessageSignal(e)
@ -197,6 +211,10 @@ QtObject:
# add or update community
self.allCommunities[community.id] = community
if(self.curatedCommunities.hasKey(community.id)):
self.curatedCommunities[community.id].available = true
self.curatedCommunities[community.id].community = community
if(not self.joinedCommunities.hasKey(community.id)):
if (community.joined and community.isMember):
self.joinedCommunities[community.id] = community
@ -300,6 +318,10 @@ QtObject:
if (community.admin):
self.joinedCommunities[community.id].pendingRequestsToJoin = self.pendingRequestsToJoinForCommunity(community.id)
let curatedCommunities = self.loadCuratedCommunities()
for curatedCommunity in curatedCommunities:
self.curatedCommunities[curatedCommunity.communityId] = curatedCommunity
let allCommunities = self.loadAllCommunities()
for community in allCommunities:
self.allCommunities[community.id] = community
@ -326,6 +348,10 @@ QtObject:
let response = status_go.getJoinedComunities()
return parseCommunities(response)
proc loadCuratedCommunities(self: Service): seq[CuratedCommunity] =
let response = status_go.getCuratedCommunities()
return parseCuratedCommunities(response)
proc loadCommunitiesSettings(self: Service): seq[CommunitySettingsDto] =
let response = status_go.getCommunitiesSettings()
return parseCommunitiesSettings(response)
@ -336,6 +362,9 @@ QtObject:
proc getAllCommunities*(self: Service): seq[CommunityDto] =
return toSeq(self.allCommunities.values)
proc getCuratedCommunities*(self: Service): seq[CuratedCommunity] =
return toSeq(self.curatedCommunities.values)
proc getCommunityById*(self: Service, communityId: string): CommunityDto =
if(not self.joinedCommunities.hasKey(communityId)):
error "error: requested community doesn't exists"

View File

@ -10,6 +10,10 @@ proc getJoinedComunities*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* []
result = callPrivateRPC("joinedCommunities".prefix, payload)
proc getCuratedCommunities*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* []
result = callPrivateRPC("curatedCommunities".prefix, payload)
proc getAllCommunities*(): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("communities".prefix)

@ -1 +1 @@
Subproject commit a4d0c1366256d4e552990bde63734b7ceea0ad80
Subproject commit da22cde5e6d8c70de806b607fefc84e286f062d4

View File

@ -0,0 +1,189 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import utils 1.0
import "stores"
ScrollView {
id: root
property CommunitiesStore communitiesStore: CommunitiesStore {}
QtObject {
id: d
property ListModel tagsModel: root.communitiesStore.tagsModel
property string searchText: ""
property int layoutVMargin: 70
property int layoutHMargin: 64
property int titlePixelSize: 28
property int subtitlePixelSize: 17
function navigateToCommunity(communityId) {
console.warn("TODO: Navigate to community ID: " + communityId)
}
}
contentHeight: column.height + d.layoutVMargin
contentWidth: column.width + d.layoutHMargin
clip: true
ColumnLayout {
id: column
spacing: 18
StatusBaseText {
Layout.topMargin: d.layoutVMargin
Layout.leftMargin: d.layoutHMargin
text: qsTr("Find community")
font.weight: Font.Bold
font.pixelSize: d.titlePixelSize
color: Theme.palette.directColor1
}
RowLayout {
width: 230/*Card Width by design*/ * featuredGrid.columns + 2 * featuredGrid.rowSpacing
spacing: 24
StatusBaseInput {
id: searcher
enabled: false // Out of scope
Layout.leftMargin: d.layoutHMargin
height: 36 // by design
width: 351 // by design
placeholderText: qsTr("Search")
text: d.searchText
icon.name: "search"
onTextChanged: {
console.warn("TODO: Community Cards searcher algorithm.")
// 1. Filter Community Cards by title, description or tags category.
// 2. Once some filter is applyed, update main tags row only showing the tags that are part of the categories of the filtered Community Cards.
}
}
// Just a row filler to fit design
Item { Layout.fillWidth: true }
StatusButton {
id: importBtn
text: qsTr("Import Community")
enabled: false // Out of scope
}
StatusButton {
id: createBtn
text: qsTr("Creat New Community")
enabled: false // Out of scope
}
}
// Tags definition - Now hidden - Out of scope
// TODO: Replace by `StatusListItemTagRow`
Row {
visible: false//d.tagsModel.count > 0 --> out of scope
Layout.leftMargin: d.layoutHMargin
Layout.rightMargin: d.layoutHMargin
width: 1234 // by design
spacing: Style.current.halfPadding
Repeater {
model: d.tagsModel
delegate: StatusListItemTag {
border.color: Theme.palette.baseColor2
color: "transparent"
height: 32
radius: 36
closeButtonVisible: false
icon.emoji: model.emoji
icon.height: 32
icon.width: icon.height
icon.color: "transparent"
icon.isLetterIdenticon: true
title: model.name
titleText.font.pixelSize: 15
titleText.color: Theme.palette.primaryColor1
}
}
// TODO: Add next button
// ...
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Featured")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
GridLayout {
id: featuredGrid
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: Style.current.padding
rowSpacing: Style.current.padding
Repeater {
model: root.communitiesStore.curatedCommunitiesModel
delegate: StatusCommunityCard {
visible: model.featured
locale: communitiesStore.locale
communityId: model.id
loaded: model.available
logo: model.icon
name: model.name
description: model.description
members: model.members
popularity: model.popularity
// <out of scope> categories: model.categories
onClicked: { d.navigateToCommunity(communityId) }
}
}
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Popular")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
GridLayout {
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: Style.current.padding
rowSpacing: Style.current.padding
Repeater {
model: root.communitiesStore.curatedCommunitiesModel
delegate: StatusCommunityCard {
visible: !model.featured
locale: communitiesStore.locale
communityId: model.id
loaded: model.available
logo: model.icon
name: model.name
description: model.description
members: model.members
popularity: model.popularity
// <out of scope> categories: model.categories
onClicked: { d.navigateToCommunity(communityId) }
}
}
}
}
}

View File

@ -0,0 +1 @@
CommunitiesPortalLayout 1.0 CommunitiesPortalLayout.qml

View File

@ -0,0 +1,31 @@
import QtQuick 2.13
import QtQml.Models 2.2
QtObject {
id: root
property var communitiesModuleInst: communitiesModule
property var curatedCommunitiesModel: root.communitiesModuleInst.curatedCommunities
property var locale: localAppSettings.locale
// TODO: Could the backend provide directly 2 filtered models??
//property var featuredCommunitiesModel: root.communitiesModuleInst.curatedFeaturedCommunities
//property var popularCommunitiesModel: root.communitiesModuleInst.curatedPopularCommunities
property ListModel tagsModel: ListModel {}//root.notionsTagsModel
// TO DO: Complete list can be added in backend or here: https://www.notion.so/Category-tags-339b2e699e7c4d36ab0608ab00b99111
property ListModel notionsTagsModel : ListModel {
ListElement { name: "gaming"; emoji: "🎮"}
ListElement { name: "art"; emoji: "🖼️️"}
ListElement { name: "crypto"; emoji: "💸"}
ListElement { name: "nsfw"; emoji: "🍆"}
ListElement { name: "markets"; emoji: "💎"}
ListElement { name: "defi"; emoji: "📈"}
ListElement { name: "travel"; emoji: "🚁"}
ListElement { name: "web3"; emoji: "🗺"}
ListElement { name: "sport"; emoji: "🎾"}
ListElement { name: "food"; emoji: "🥑"}
ListElement { name: "enviroment"; emoji: "☠️"}
ListElement { name: "privacy"; emoji: "👻"}
}
}

View File

@ -35,6 +35,7 @@ QtObject {
readonly property string keycard: "keycard"
readonly property string multiNetwork: "multiNetwork"
readonly property string communityHistoryArchiveSupport: "communityHistoryArchiveSupport"
readonly property string communitiesPortal: "communitiesPortal"
}
function setGlobalNetworkId() {
@ -130,6 +131,9 @@ QtObject {
else if (feature === experimentalFeatures.communities) {
advancedModule.toggleCommunitySection()
}
else if (feature === experimentalFeatures.communitiesPortal) {
advancedModule.toggleCommunitiesPortalSection()
}
else if (feature === experimentalFeatures.communityHistoryArchiveSupport) {
// toggle history archive support
advancedModule.toggleCommunityHistoryArchiveSupport()
@ -152,5 +156,6 @@ QtObject {
else if (feature === experimentalFeatures.multiNetwork) {
localAccountSensitiveSettings.isMultiNetworkEnabled = !localAccountSensitiveSettings.isMultiNetworkEnabled
}
}
}

View File

@ -245,6 +245,24 @@ SettingsContentBase {
}
}
// TODO: replace with StatusQ component
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
text: qsTr("Communities Portal")
isSwitch: true
switchChecked: localAccountSensitiveSettings.isCommunitiesPortalEnabled
onClicked: {
if (localAccountSensitiveSettings.isCommunitiesPortalEnabled) {
root.advancedStore.toggleExperimentalFeature(root.advancedStore.experimentalFeatures.communitiesPortal)
} else {
confirmationPopup.experimentalFeature = root.advancedStore.experimentalFeatures.communitiesPortal
confirmationPopup.open()
}
}
}
StatusSectionHeadline {
anchors.left: parent.left
anchors.right: parent.right

View File

@ -54,6 +54,8 @@ QtObject {
property bool isMultiNetworkEnabled: localAccountSensitiveSettings.isMultiNetworkEnabled
property bool isCommunitiesPortalEnabled: localAccountSensitiveSettings.isCommunitiesPortalEnabled
property var savedAddressesModel: walletSectionSavedAddresses.model
function getEtherscanLink() {

View File

@ -13,6 +13,7 @@ import AppLayouts.Chat 1.0
import AppLayouts.Chat.popups 1.0
import AppLayouts.Profile 1.0
import AppLayouts.Profile.popups 1.0
import AppLayouts.CommunitiesPortal 1.0
import utils 1.0
import shared 1.0
@ -477,6 +478,9 @@ Item {
" or section id: ", mainModule.activeSection.id)
return Constants.appViewStackIndex.community
}
else if(mainModule.activeSection.sectionType === Constants.appSection.communitiesPortal) {
return Constants.appViewStackIndex.communitiesPortal
}
else if(mainModule.activeSection.sectionType === Constants.appSection.wallet) {
return Constants.appViewStackIndex.wallet
}
@ -541,6 +545,13 @@ Item {
}
}
CommunitiesPortalLayout {
id: communitiesPortalLayoutContainer
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
}
WalletLayout {
id: walletLayoutContainer
Layout.fillWidth: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -24,6 +24,7 @@ QtObject {
property bool isGifWidgetEnabled: !!accountSensitiveSettings ? accountSensitiveSettings.isGifWidgetEnabled : false
property bool isTenorWarningAccepted: !!accountSensitiveSettings ? accountSensitiveSettings.isTenorWarningAccepted : false
property bool displayChatImages: !!accountSensitiveSettings ? accountSensitiveSettings.displayChatImages : false
property bool isCommunitiesPortalEnabled: !!accountSensitiveSettings ? accountSensitiveSettings.isCommunitiesPortalEnabled : false
property string locale: !!appSettings ? appSettings.locale : ""
// property string signingPhrase: !!walletModelInst ? walletModelInst.utilsView.signingPhrase : ""

View File

@ -18,15 +18,17 @@ QtObject {
readonly property int browser: 3
readonly property int profile: 4
readonly property int node: 5
readonly property int communitiesPortal: 6
}
readonly property QtObject appViewStackIndex: QtObject {
readonly property int chat: 0
readonly property int community: 7 // any stack layout children with the index 7 or higher is community
readonly property int wallet: 1
readonly property int browser: 2
readonly property int profile: 3
readonly property int node: 4
readonly property int communitiesPortal: 1
readonly property int wallet: 2
readonly property int browser: 3
readonly property int profile: 4
readonly property int node: 5
}
readonly property QtObject settingsSubsection: QtObject {

View File

@ -31,6 +31,7 @@ SOURCES = *.qml \
app/AppLayouts/Chat/ChatColumn/ChatComponents/*.qml \
app/AppLayouts/Chat/ChatColumn/MessageComponents/*.qml \
app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/*.qml \
app/AppLayouts/CommunitiesPortalLayout/*.qml \
app/AppLayouts/Chat/ContactsColumn/*.qml \
app/AppLayouts/Chat/components/*.qml \
app/AppLayouts/Node/*.qml \
@ -46,7 +47,7 @@ SOURCES = *.qml \
app/AppLayouts/Wallet/*.qml \
app/AppLayouts/Wallet/components/*.qml \
app/AppLayouts/Wallet/components/collectiblesComponents/*.qml \
app/AppLayouts/Wallet/data/Currencies.qml \
app/AppLayouts/Wallet/data/Currencies.qml \
}
TRANSLATIONS += \

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 63e58ba0354448b67449053b4599b2974d398a11
Subproject commit c3b0582cc93cbfda03623df8b4f6875552335909