Warning, /network/tokodon/src/content/ui/main.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu> 0002 // SPDX-FileCopyrightText: 2020 Han Young <hanyoung@protonmail.com> 0003 // SPDX-FileCopyrightText: 2020 Devin Lin <espidev@gmail.com> 0004 // SPDX-License-Identifier: GPL-3.0-only 0005 0006 import QtQuick 2.15 0007 import org.kde.kirigami 2.19 as Kirigami 0008 import QtQuick.Controls 2.15 as QQC2 0009 import QtQuick.Layouts 1.15 0010 import QtQml.Models 2.15 0011 import org.kde.kmasto 1.0 0012 import org.kde.kirigamiaddons.delegates 1.0 as Delegates 0013 0014 import "./StatusComposer" 0015 import "./StatusDelegate" 0016 0017 Kirigami.ApplicationWindow { 0018 id: appwindow 0019 0020 property bool isShowingFullScreenImage: false 0021 0022 minimumWidth: Kirigami.Units.gridUnit * 15 0023 minimumHeight: Kirigami.Units.gridUnit * 20 0024 0025 pageStack { 0026 defaultColumnWidth: appwindow.width 0027 0028 globalToolBar { 0029 canContainHandles: true 0030 style: Kirigami.ApplicationHeaderStyle.ToolBar 0031 showNavigationButtons: if (applicationWindow().pageStack.currentIndex > 0 0032 || applicationWindow().pageStack.currentIndex > 0) { 0033 Kirigami.ApplicationHeaderStyle.ShowBackButton 0034 } else { 0035 0 0036 } 0037 } 0038 } 0039 0040 function startupAccountCheck() { 0041 if (AccountManager.hasAccounts) { 0042 pageStack.push(mainTimeline, { 0043 name: 'home', 0044 }); 0045 } else { 0046 pageStack.push('qrc:/content/ui/LoginPage.qml'); 0047 } 0048 } 0049 0050 Component.onCompleted: { 0051 if (AccountManager.isReady) { 0052 startupAccountCheck(); 0053 } 0054 } 0055 0056 Connections { 0057 target: AccountManager 0058 0059 function onAccountSelected() { 0060 pageStack.pop(pageStack.get(0)) 0061 } 0062 0063 function onAccountRemoved() { 0064 if (!AccountManager.hasAccounts) { 0065 pageStack.replace('qrc:/content/ui/LoginPage.qml'); 0066 globalDrawer.drawerOpen = false 0067 } 0068 } 0069 0070 function onAccountsReloaded() { 0071 pageStack.replace(mainTimeline, { 0072 name: "home" 0073 }); 0074 } 0075 0076 function onAccountsReady() { 0077 appwindow.startupAccountCheck(); 0078 } 0079 } 0080 0081 Connections { 0082 target: Controller 0083 0084 function onOpenPost(id) { 0085 Navigation.openThread(id) 0086 } 0087 0088 function onOpenAccount(id) { 0089 Navigation.openAccount(id) 0090 } 0091 } 0092 0093 Connections { 0094 target: Navigation 0095 0096 function onOpenStatusComposer() { 0097 pageStack.layers.push("./StatusComposer/StatusComposer.qml", { 0098 purpose: StatusComposer.New 0099 }); 0100 } 0101 0102 function onReplyTo(inReplyTo, mentions, visibility, authorIdentity, post) { 0103 if (!mentions.includes(`@${authorIdentity.account}`)) { 0104 mentions.push(`@${authorIdentity.account}`); 0105 } 0106 pageStack.layers.push("./StatusComposer/StatusComposer.qml", { 0107 purpose: StatusComposer.Reply, 0108 inReplyTo: inReplyTo, 0109 mentions: mentions, 0110 visibility: visibility, 0111 previewPost: post 0112 }); 0113 } 0114 0115 function onOpenThread(postId) { 0116 if (!pageStack.currentItem.postId || pageStack.currentItem.postId !== postId) { 0117 pageStack.push("qrc:/content/ui/ThreadPage.qml", { 0118 postId: postId, 0119 }); 0120 } 0121 } 0122 0123 function onOpenAccount(accountId) { 0124 if (!pageStack.currentItem.accountId || pageStack.currentItem.accountId !== accountId) { 0125 pageStack.push('qrc:/content/ui/AccountInfo.qml', { 0126 accountId: accountId, 0127 }); 0128 } 0129 } 0130 0131 function onOpenTag(tag) { 0132 pageStack.push(tagModelComponent, { 0133 hashtag: tag, 0134 }) 0135 } 0136 } 0137 0138 globalDrawer: Kirigami.OverlayDrawer { 0139 id: drawer 0140 enabled: AccountManager.hasAccounts && AccountManager.isReady 0141 edge: Qt.application.layoutDirection === Qt.RightToLeft ? Qt.RightEdge : Qt.LeftEdge 0142 modal: !enabled || Kirigami.Settings.isMobile || Kirigami.Settings.tabletMode || (applicationWindow().width < Kirigami.Units.gridUnit * 50 && !collapsed) // Only modal when not collapsed, otherwise collapsed won't show. 0143 z: modal ? Math.round(position * 10000000) : 100 0144 drawerOpen: !Kirigami.Settings.isMobile && enabled 0145 width: Kirigami.Units.gridUnit * 16 0146 Behavior on width { 0147 NumberAnimation { 0148 duration: Kirigami.Units.longDuration 0149 easing.type: Easing.InOutQuad 0150 } 0151 } 0152 Kirigami.Theme.colorSet: Kirigami.Theme.View 0153 Kirigami.Theme.inherit: false 0154 0155 handleClosedIcon.source: modal ? null : "sidebar-expand-left" 0156 handleOpenIcon.source: modal ? null : "sidebar-collapse-left" 0157 handleVisible: modal && !isShowingFullScreenImage && enabled 0158 onModalChanged: drawerOpen = !modal; 0159 0160 leftPadding: 0 0161 rightPadding: 0 0162 topPadding: 0 0163 bottomPadding: 0 0164 0165 contentItem: ColumnLayout { 0166 spacing: 0 0167 0168 QQC2.ToolBar { 0169 Layout.fillWidth: true 0170 Layout.preferredHeight: pageStack.globalToolBar.preferredHeight 0171 Layout.bottomMargin: Kirigami.Units.smallSpacing / 2 0172 0173 leftPadding: 3 0174 rightPadding: 3 0175 topPadding: 3 0176 bottomPadding: 3 0177 0178 visible: !Kirigami.Settings.isMobile 0179 0180 contentItem: SearchField {} 0181 } 0182 0183 UserInfo { 0184 Layout.fillWidth: true 0185 } 0186 0187 Kirigami.Separator { 0188 Layout.fillWidth: true 0189 Layout.margins: Kirigami.Units.smallSpacing 0190 } 0191 0192 QQC2.ButtonGroup { 0193 id: pageButtonGroup 0194 } 0195 0196 Repeater { 0197 model: [homeAction, notificationAction, searchAction, followRequestAction, localTimelineAction, globalTimelineAction, exploreAction, conversationAction, favouritesAction, bookmarksAction] 0198 Delegates.RoundedItemDelegate { 0199 required property var modelData 0200 QQC2.ButtonGroup.group: pageButtonGroup 0201 0202 padding: Kirigami.Units.largeSpacing 0203 action: modelData 0204 Layout.fillWidth: true 0205 visible: modelData.visible 0206 } 0207 } 0208 0209 Item { 0210 Layout.fillHeight: true 0211 } 0212 0213 Delegates.RoundedItemDelegate { 0214 icon.name: "lock" 0215 onClicked: pageStack.pushDialogLayer('qrc:/content/ui/ModerationTools/ModerationToolPage.qml', {}, { title: i18n("Moderation Tools") }) 0216 text: i18nc("@action:button", "Open Moderation Tools") 0217 visible: AccountManager.selectedAccount && (AccountManager.selectedAccount.identity.permission & AdminAccountInfo.ManageUsers) 0218 padding: Kirigami.Units.largeSpacing 0219 0220 Layout.fillWidth: true 0221 } 0222 0223 Delegates.RoundedItemDelegate { 0224 icon.name: "settings-configure" 0225 onClicked: pageStack.pushDialogLayer('qrc:/content/ui/Settings/SettingsPage.qml', {}, { title: i18n("Configure") }) 0226 text: i18n("Open settings") 0227 padding: Kirigami.Units.largeSpacing 0228 0229 Layout.fillWidth: true 0230 } 0231 } 0232 } 0233 0234 property Kirigami.Action homeAction: Kirigami.Action { 0235 icon.name: "go-home-large" 0236 text: i18n("Home") 0237 checkable: true 0238 checked: true 0239 onTriggered: { 0240 pageStack.clear(); 0241 pageStack.push(mainTimeline, { 0242 name: "home" 0243 }); 0244 checked = true; 0245 if (Kirigami.Settings.isMobile || drawer.modal) { 0246 drawer.drawerOpen = false; 0247 } 0248 } 0249 } 0250 property Kirigami.Action notificationAction: Kirigami.Action { 0251 icon.name: "notifications" 0252 text: i18n("Notifications") 0253 checkable: true 0254 onTriggered: { 0255 pageStack.clear(); 0256 pageStack.push(notificationTimeline); 0257 checked = true; 0258 if (Kirigami.Settings.isMobile || drawer.modal) { 0259 drawer.drawerOpen = false; 0260 } 0261 } 0262 } 0263 property Kirigami.Action followRequestAction: Kirigami.Action { 0264 icon.name: "list-add-user" 0265 text: i18n("Follow Requests") 0266 checkable: true 0267 visible: AccountManager.hasAccounts && AccountManager.selectedAccount && AccountManager.selectedAccount.hasFollowRequests 0268 onTriggered: { 0269 pageStack.clear(); 0270 pageStack.push(socialGraphComponent, { 0271 name: "request" 0272 }); 0273 checked = true; 0274 if (Kirigami.Settings.isMobile || drawer.modal) { 0275 drawer.drawerOpen = false; 0276 } 0277 } 0278 } 0279 property Kirigami.Action localTimelineAction: Kirigami.Action { 0280 icon.name: "system-users" 0281 text: i18n("Local") 0282 checkable: true 0283 onTriggered: { 0284 pageStack.clear(); 0285 pageStack.push(mainTimeline, { 0286 name: "public", 0287 }); 0288 checked = true; 0289 if (Kirigami.Settings.isMobile || drawer.modal) { 0290 drawer.drawerOpen = false; 0291 } 0292 } 0293 } 0294 property Kirigami.Action globalTimelineAction: Kirigami.Action { 0295 icon.name: "kstars_xplanet" 0296 text: i18n("Global") 0297 checkable: true 0298 onTriggered: { 0299 pageStack.clear(); 0300 pageStack.push(mainTimeline, { 0301 name: "federated", 0302 }); 0303 checked = true; 0304 if (Kirigami.Settings.isMobile || drawer.modal) { 0305 drawer.drawerOpen = false; 0306 } 0307 } 0308 } 0309 0310 property Kirigami.Action conversationAction: Kirigami.Action { 0311 icon.name: "tokodon-chat-reply" 0312 text: i18n("Conversation") 0313 checkable: true 0314 onTriggered: { 0315 pageStack.clear(); 0316 pageStack.push("qrc:/content/ui/ConversationPage.qml"); 0317 checked = true; 0318 if (Kirigami.Settings.isMobile || drawer.modal) { 0319 drawer.drawerOpen = false; 0320 } 0321 } 0322 } 0323 0324 property Kirigami.Action favouritesAction: Kirigami.Action { 0325 icon.name: "favorite" 0326 text: i18n("Favourites") 0327 checkable: true 0328 onTriggered: { 0329 pageStack.clear(); 0330 pageStack.push(mainTimeline, { 0331 name: "favourites", 0332 }); 0333 checked = true; 0334 if (Kirigami.Settings.isMobile || drawer.modal) { 0335 drawer.drawerOpen = false; 0336 } 0337 } 0338 } 0339 0340 property Kirigami.Action bookmarksAction: Kirigami.Action { 0341 icon.name: "bookmarks" 0342 text: i18n("Bookmarks") 0343 checkable: true 0344 onTriggered: { 0345 pageStack.clear(); 0346 pageStack.push(mainTimeline, { 0347 name: "bookmarks", 0348 }); 0349 checked = true; 0350 if (Kirigami.Settings.isMobile || drawer.modal) { 0351 drawer.drawerOpen = false; 0352 } 0353 } 0354 } 0355 0356 property Kirigami.Action exploreAction: Kirigami.Action { 0357 icon.name: "kstars_planets" 0358 text: i18n("Explore") 0359 checkable: true 0360 onTriggered: { 0361 pageStack.clear(); 0362 pageStack.push(exploreTimeline); 0363 checked = true; 0364 if (Kirigami.Settings.isMobile || drawer.modal) { 0365 drawer.drawerOpen = false; 0366 } 0367 } 0368 } 0369 0370 property Kirigami.Action searchAction: Kirigami.Action { 0371 icon.name: "search" 0372 text: i18n("Search") 0373 checkable: true 0374 visible: Kirigami.Settings.isMobile 0375 onTriggered: { 0376 pageStack.clear(); 0377 pageStack.push("qrc:/content/ui/SearchPage.qml"); 0378 checked = true; 0379 if (Kirigami.Settings.isMobile) { 0380 drawer.drawerOpen = false; 0381 } 0382 } 0383 } 0384 0385 property Kirigami.NavigationTabBar tabBar: Kirigami.NavigationTabBar { 0386 // Make sure we take in count drawer width 0387 visible: pageStack.layers.depth <= 1 && AccountManager.hasAccounts && !appwindow.wideScreen 0388 actions: [homeAction, notificationAction, localTimelineAction, globalTimelineAction] 0389 } 0390 0391 footer: Kirigami.Settings.isMobile ? tabBar : null 0392 0393 contextDrawer: Kirigami.ContextDrawer { 0394 id: contextDrawer 0395 } 0396 0397 Component { 0398 id: mainTimeline 0399 TimelinePage { 0400 id: timelinePage 0401 property string name 0402 model: MainTimelineModel { 0403 id: timelineModel 0404 name: timelinePage.name 0405 } 0406 } 0407 } 0408 0409 Component { 0410 id: socialGraphComponent 0411 SocialGraphPage { 0412 id: socialGraphPage 0413 property alias name: socialGraphModel.name 0414 property alias accountId: socialGraphModel.accountId 0415 model: SocialGraphModel { 0416 id: socialGraphModel 0417 name: socialGraphPage.name 0418 accountId: socialGraphPage.accountId 0419 } 0420 } 0421 } 0422 0423 Component { 0424 id: notificationTimeline 0425 NotificationPage { } 0426 } 0427 0428 Component { 0429 id: exploreTimeline 0430 ExplorePage { } 0431 } 0432 0433 property Item hoverLinkIndicator: QQC2.Control { 0434 parent: overlay.parent 0435 property alias text: linkText.text 0436 opacity: text.length > 0 ? 1 : 0 0437 visible: !Kirigami.Settings.isMobile && !text.startsWith("hashtag:") && !text.startsWith("account:") 0438 0439 z: 999990 0440 x: 0 0441 y: parent.height - implicitHeight 0442 contentItem: QQC2.Label { 0443 id: linkText 0444 } 0445 Kirigami.Theme.colorSet: Kirigami.Theme.View 0446 background: Rectangle { 0447 color: Kirigami.Theme.backgroundColor 0448 } 0449 } 0450 0451 Component { 0452 id: tagModelComponent 0453 TimelinePage { 0454 id: tagPage 0455 property string hashtag 0456 model: TagsTimelineModel { 0457 hashtag: tagPage.hashtag 0458 } 0459 } 0460 } 0461 0462 Timer { 0463 id: followRequestTimer 0464 running: AccountManager.hasAccounts 0465 interval: 1800000 // 30 minutes 0466 onTriggered: if (AccountManager.hasAccounts && AccountManager.selectedAccount) { 0467 AccountManager.selectedAccount.checkForFollowRequests(); 0468 } 0469 } 0470 0471 Rectangle { 0472 anchors.fill: parent 0473 visible: !AccountManager.isReady 0474 color: Kirigami.Theme.backgroundColor 0475 0476 Kirigami.LoadingPlaceholder { 0477 anchors.centerIn: parent 0478 } 0479 } 0480 }