From 29d3a4ddfd8370d897f3722b086c4acd770e6392 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Tue, 24 Sep 2024 01:08:38 +0900 Subject: [PATCH 01/19] =?UTF-8?q?=E3=83=A9=E3=83=99=E3=83=AA=E3=83=B3?= =?UTF-8?q?=E3=82=B0=E3=81=95=E3=82=8C=E3=81=9F=E3=83=9D=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=81=8B=E3=82=89=E5=BC=95=E7=94=A8=E3=81=95=E3=82=8C=E3=81=9F?= =?UTF-8?q?=E3=83=9D=E3=82=B9=E3=83=88=E3=81=AE=E8=A1=A8=E7=A4=BA=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/view/TimelineView.qml | 4 +++- tests/deps.pri | 3 +++ web/content/docs/release-note.en.md | 3 +++ web/content/docs/release-note.ja.md | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/qml/view/TimelineView.qml b/app/qml/view/TimelineView.qml index 098fe2cc..dbf30490 100644 --- a/app/qml/view/TimelineView.qml +++ b/app/qml/view/TimelineView.qml @@ -143,7 +143,9 @@ ScrollView { postImagePreview.embedAlts: model.embedImagesAlt postImagePreview.onRequestViewImages: (index) => requestViewImages(index, model.embedImagesFull, model.embedImagesAlt) - quoteFilterFrame.visible: model.quoteFilterMatched && !model.quoteRecordBlocked + quoteFilterFrame.visible: model.quoteFilterMatched && + !model.quoteRecordBlocked && + contentMediaFilterFrame.showContent quoteFilterFrame.labelText: qsTr("Quoted content warning") blockedQuoteFrame.visible: model.quoteRecordBlocked blockedQuoteFrameLabel.text: model.quoteRecordBlockedStatus diff --git a/tests/deps.pri b/tests/deps.pri index 5181738d..9ecc7532 100644 --- a/tests/deps.pri +++ b/tests/deps.pri @@ -12,3 +12,6 @@ else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../l else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../lib/release/lib.lib else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../lib/debug/lib.lib else:unix: PRE_TARGETDEPS += $$OUT_PWD/../../lib/liblib.a + +# openssl.priなどで追加した依存ファイルのコピーに必要 +win32:QMAKE_POST_LINK += nmake -f $(MAKEFILE) install diff --git a/web/content/docs/release-note.en.md b/web/content/docs/release-note.en.md index 20784039..a14243b0 100644 --- a/web/content/docs/release-note.en.md +++ b/web/content/docs/release-note.en.md @@ -8,6 +8,9 @@ description: This is a multi-column Bluesky client. ## 2024 +- Fix + - Fix the display of posts quoted from labeled posts + ### v0.37.0 - 2024/9/22 - Add diff --git a/web/content/docs/release-note.ja.md b/web/content/docs/release-note.ja.md index 7dd5a5bd..44cf11a5 100644 --- a/web/content/docs/release-note.ja.md +++ b/web/content/docs/release-note.ja.md @@ -8,6 +8,9 @@ description: マルチカラム対応Blueskyクライアント ## 2024 +- 修正 + - ラベリングされたポストから引用されたポストの表示を修正 + ### v0.37.0 - 2024/9/22 - 追加 From a8e77691dccb10742433821ae84f65403513166f Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Tue, 24 Sep 2024 01:14:56 +0900 Subject: [PATCH 02/19] =?UTF-8?q?=E5=BC=95=E7=94=A8=E3=81=A8=E7=94=BB?= =?UTF-8?q?=E5=83=8F=E3=81=AE=E3=83=95=E3=82=A3=E3=83=AB=E3=82=BF=E3=83=BC?= =?UTF-8?q?=E3=82=92=E7=8B=AC=E7=AB=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/parts/PostDelegate.qml | 3 +-- app/qml/view/TimelineView.qml | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/qml/parts/PostDelegate.qml b/app/qml/parts/PostDelegate.qml index 05714ed3..bbb79032 100644 --- a/app/qml/parts/PostDelegate.qml +++ b/app/qml/parts/PostDelegate.qml @@ -265,8 +265,7 @@ ClickableFrame { Layout.preferredWidth: parent.width Layout.topMargin: 5 visible: postFrame.hasQuote && - quoteFilterFrame.showContent && - contentMediaFilterFrame.showContent + quoteFilterFrame.showContent basisWidth: bodyLayout.basisWidth onOpenLink: (url) => postFrame.openLink(url) onDisplayLink: (url) => postFrame.displayLink(url) diff --git a/app/qml/view/TimelineView.qml b/app/qml/view/TimelineView.qml index dbf30490..098fe2cc 100644 --- a/app/qml/view/TimelineView.qml +++ b/app/qml/view/TimelineView.qml @@ -143,9 +143,7 @@ ScrollView { postImagePreview.embedAlts: model.embedImagesAlt postImagePreview.onRequestViewImages: (index) => requestViewImages(index, model.embedImagesFull, model.embedImagesAlt) - quoteFilterFrame.visible: model.quoteFilterMatched && - !model.quoteRecordBlocked && - contentMediaFilterFrame.showContent + quoteFilterFrame.visible: model.quoteFilterMatched && !model.quoteRecordBlocked quoteFilterFrame.labelText: qsTr("Quoted content warning") blockedQuoteFrame.visible: model.quoteRecordBlocked blockedQuoteFrameLabel.text: model.quoteRecordBlockedStatus From d93abee4c26b62788604da9d416f649c6fd7b3d0 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Wed, 25 Sep 2024 23:47:38 +0900 Subject: [PATCH 03/19] =?UTF-8?q?=E7=94=BB=E5=83=8F=E3=81=AE=E3=83=97?= =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E3=81=AE=E3=83=AC=E3=82=A4?= =?UTF-8?q?=E3=82=A2=E3=82=A6=E3=83=88=E3=82=92=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/parts/ImagePreview.qml | 127 ++++++++++++--------- app/qml/view/TimelineView.qml | 1 + app/qtquick/timeline/timelinelistmodel.cpp | 4 + app/qtquick/timeline/timelinelistmodel.h | 1 + lib/atprotocol/lexicons_func_unknown.cpp | 16 +++ lib/atprotocol/lexicons_func_unknown.h | 1 + 6 files changed, 97 insertions(+), 53 deletions(-) diff --git a/app/qml/parts/ImagePreview.qml b/app/qml/parts/ImagePreview.qml index 45ed9467..40287c50 100644 --- a/app/qml/parts/ImagePreview.qml +++ b/app/qml/parts/ImagePreview.qml @@ -6,88 +6,109 @@ import tech.relog.hagoromo.singleton 1.0 import "../controls" -GridLayout { +Frame { id: imagePreviewLayout visible: embedImages.length > 0 - columnSpacing: 6 - rowSpacing: 6 - columns: 2 + contentWidth: contentRootLayout.implicitWidth + contentHeight: contentRootLayout.implicitHeight + topInset: 0 + leftInset: 0 + rightInset: 0 + bottomInset: 0 + topPadding: 0 + leftPadding: 0 + rightPadding: 0 + bottomPadding: 0 + + background: Rectangle { + color: "transparent" + } // 0:compact, 1:normal, 2:when one is whole, 3:all whole property int layoutType: 1 property int layoutWidth: 100 property var embedImages: [] property var embedAlts: [] + property var embedImageRatios: [] property int cellWidthAdjust: 3 - property int cellWidth: imagePreviewLayout.layoutWidth / columns - cellWidthAdjust + property int cellWidth: imagePreviewLayout.layoutWidth / contentRootLayout.columns - cellWidthAdjust signal requestViewImages(int index) states: [ State { when: layoutType === 0 - PropertyChanges { target: imagePreviewLayout; columns: 4 } + PropertyChanges { target: contentRootLayout; columns: 4 } PropertyChanges { target: imagePreviewLayout; cellWidthAdjust: 5 } }, State { when: layoutType === 1 || layoutType === 2 - PropertyChanges { target: imagePreviewLayout; columns: 2 } + PropertyChanges { target: contentRootLayout; columns: 2 } PropertyChanges { target: imagePreviewLayout; cellWidthAdjust: 3 } }, State { when: layoutType === 3 - PropertyChanges { target: imagePreviewLayout; columns: 1 } + PropertyChanges { target: contentRootLayout; columns: 1 } PropertyChanges { target: imagePreviewLayout; cellWidthAdjust: 0 } } ] - Repeater { - id: repeater - model: imagePreviewLayout.embedImages - delegate: ImageWithIndicator { - id: image - property bool isWide: false - property bool isTall: false - Layout.preferredWidth: isWide ? imagePreviewLayout.layoutWidth : imagePreviewLayout.cellWidth - Layout.preferredHeight: isTall ? (imagePreviewLayout.layoutWidth * sourceSize.height / sourceSize.width) : imagePreviewLayout.cellWidth - Layout.columnSpan: isWide ? 2 : 1 - fillMode: Image.PreserveAspectCrop - source: modelData - states: [ - State { - when: imagePreviewLayout.layoutType === 0 - PropertyChanges { target: image; isWide: false } - PropertyChanges { target: image; isTall: false } - }, - State { - when: imagePreviewLayout.layoutType === 1 - PropertyChanges { target: image; isWide: (repeater.count % 2 === 1 && model.index === (repeater.count - 1)) } - PropertyChanges { target: image; isTall: false } - }, - State { - when: imagePreviewLayout.layoutType === 2 - PropertyChanges { target: image; isWide: (repeater.count % 2 === 1 && model.index === (repeater.count - 1)) } - PropertyChanges { target: image; isTall: (repeater.count === 1) } - }, - State { - when: imagePreviewLayout.layoutType === 3 - PropertyChanges { target: image; isWide: false } - PropertyChanges { target: image; isTall: true } + GridLayout { + id: contentRootLayout + columnSpacing: 6 + rowSpacing: 6 + columns: 2 + Repeater { + id: repeater + model: imagePreviewLayout.embedImages + delegate: ImageWithIndicator { + id: image + property bool isWide: false + property bool isTall: false + Layout.preferredWidth: isWide ? imagePreviewLayout.layoutWidth : imagePreviewLayout.cellWidth + Layout.preferredHeight: isTall ? (imagePreviewLayout.layoutWidth * ( + model.index < embedImageRatios.length ? parseFloat(embedImageRatios[model.index]) : (sourceSize.height / sourceSize.width) + ) + ) : imagePreviewLayout.cellWidth + Layout.columnSpan: isWide ? 2 : 1 + fillMode: Image.PreserveAspectCrop + source: modelData + states: [ + State { + when: imagePreviewLayout.layoutType === 0 + PropertyChanges { target: image; isWide: false } + PropertyChanges { target: image; isTall: false } + }, + State { + when: imagePreviewLayout.layoutType === 1 + PropertyChanges { target: image; isWide: (repeater.count % 2 === 1 && model.index === (repeater.count - 1)) } + PropertyChanges { target: image; isTall: false } + }, + State { + when: imagePreviewLayout.layoutType === 2 + PropertyChanges { target: image; isWide: (repeater.count % 2 === 1 && model.index === (repeater.count - 1)) } + PropertyChanges { target: image; isTall: (repeater.count === 1) } + }, + State { + when: imagePreviewLayout.layoutType === 3 + PropertyChanges { target: image; isWide: false } + PropertyChanges { target: image; isTall: true } + } + ] + TagLabel { + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 3 + visible: model.index < embedAlts.length ? embedAlts[model.index].length > 0 : false + source: "" + fontPointSize: AdjustedValues.f8 + text: "Alt" + } + MouseArea { + anchors.fill: parent + onClicked: imagePreviewLayout.requestViewImages(model.index) } - ] - TagLabel { - anchors.left: parent.left - anchors.bottom: parent.bottom - anchors.margins: 3 - visible: model.index < embedAlts.length ? embedAlts[model.index].length > 0 : false - source: "" - fontPointSize: AdjustedValues.f8 - text: "Alt" - } - MouseArea { - anchors.fill: parent - onClicked: imagePreviewLayout.requestViewImages(model.index) } } } diff --git a/app/qml/view/TimelineView.qml b/app/qml/view/TimelineView.qml index 098fe2cc..a31bbcaa 100644 --- a/app/qml/view/TimelineView.qml +++ b/app/qml/view/TimelineView.qml @@ -141,6 +141,7 @@ ScrollView { postImagePreview.layoutType: timelineView.imageLayoutType postImagePreview.embedImages: model.embedImages postImagePreview.embedAlts: model.embedImagesAlt + postImagePreview.embedImageRatios: model.embedImagesRatio postImagePreview.onRequestViewImages: (index) => requestViewImages(index, model.embedImagesFull, model.embedImagesAlt) quoteFilterFrame.visible: model.quoteFilterMatched && !model.quoteRecordBlocked diff --git a/app/qtquick/timeline/timelinelistmodel.cpp b/app/qtquick/timeline/timelinelistmodel.cpp index e2020a13..bf367b12 100644 --- a/app/qtquick/timeline/timelinelistmodel.cpp +++ b/app/qtquick/timeline/timelinelistmodel.cpp @@ -181,6 +181,9 @@ QVariant TimelineListModel::item(int row, TimelineListModelRoles role) const else if (role == EmbedImagesAltRole) return LexiconsTypeUnknown::copyImagesFromPostView(current.post, LexiconsTypeUnknown::CopyImageType::Alt); + else if (role == EmbedImagesRatioRole) + return LexiconsTypeUnknown::copyImagesFromPostView( + current.post, LexiconsTypeUnknown::CopyImageType::Ratio); else if (role == IsRepostedRole) return current.post.viewer.repost.contains(account().did); @@ -764,6 +767,7 @@ QHash TimelineListModel::roleNames() const roles[EmbedImagesRole] = "embedImages"; roles[EmbedImagesFullRole] = "embedImagesFull"; roles[EmbedImagesAltRole] = "embedImagesAlt"; + roles[EmbedImagesRatioRole] = "embedImagesRatio"; roles[IsRepostedRole] = "isReposted"; roles[IsLikedRole] = "isLiked"; diff --git a/app/qtquick/timeline/timelinelistmodel.h b/app/qtquick/timeline/timelinelistmodel.h index 1e09497f..78186bc6 100644 --- a/app/qtquick/timeline/timelinelistmodel.h +++ b/app/qtquick/timeline/timelinelistmodel.h @@ -60,6 +60,7 @@ class TimelineListModel : public AtpAbstractListModel EmbedImagesRole, EmbedImagesFullRole, EmbedImagesAltRole, + EmbedImagesRatioRole, IsRepostedRole, IsLikedRole, diff --git a/lib/atprotocol/lexicons_func_unknown.cpp b/lib/atprotocol/lexicons_func_unknown.cpp index 4df9a86f..0e290c1f 100644 --- a/lib/atprotocol/lexicons_func_unknown.cpp +++ b/lib/atprotocol/lexicons_func_unknown.cpp @@ -107,6 +107,14 @@ QStringList copyImagesFromPostView(const AppBskyFeedDefs::PostView &post, const images.append(image.fullsize); else if (type == CopyImageType::Alt) images.append(image.alt); + else if (type == CopyImageType::Ratio) { + if (image.aspectRatio.width == 0) { + images.append("1"); + } else { + images.append(QString::number(static_cast(image.aspectRatio.height) + / static_cast(image.aspectRatio.width))); + } + } } return images; } else if (post.embed_type @@ -123,6 +131,14 @@ QStringList copyImagesFromPostView(const AppBskyFeedDefs::PostView &post, const images.append(image.fullsize); else if (type == CopyImageType::Alt) images.append(image.alt); + else if (type == CopyImageType::Ratio) { + if (image.aspectRatio.width == 0) { + images.append("1"); + } else { + images.append(QString::number(static_cast(image.aspectRatio.height) + / static_cast(image.aspectRatio.width))); + } + } } return images; } else { diff --git a/lib/atprotocol/lexicons_func_unknown.h b/lib/atprotocol/lexicons_func_unknown.h index 4f0ef2dc..ddc73a57 100644 --- a/lib/atprotocol/lexicons_func_unknown.h +++ b/lib/atprotocol/lexicons_func_unknown.h @@ -53,6 +53,7 @@ enum class CopyImageType : int { Thumb, FullSize, Alt, + Ratio, }; QStringList copyImagesFromPostView(const AppBskyFeedDefs::PostView &post, const CopyImageType type); From cff030e1883c876ab627aeabca9bec750e32d09a Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Thu, 26 Sep 2024 00:04:22 +0900 Subject: [PATCH 04/19] =?UTF-8?q?=E3=83=AA=E3=83=B3=E3=82=AF=E3=82=AB?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=81=AE=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6?= =?UTF-8?q?=E3=83=88=E3=82=92=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/parts/ExternalLinkCard.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/qml/parts/ExternalLinkCard.qml b/app/qml/parts/ExternalLinkCard.qml index d5b4c4ef..e8466cad 100644 --- a/app/qml/parts/ExternalLinkCard.qml +++ b/app/qml/parts/ExternalLinkCard.qml @@ -32,7 +32,7 @@ ClickableFrame { ImageWithIndicator { id: thumbImage Layout.preferredWidth: externalLinkFrame.width - Layout.preferredHeight: status !== Image.Null ? externalLinkFrame.width * 0.5 : 5 + Layout.preferredHeight: thumbImage.source !== "" ? externalLinkFrame.width * 0.5 : 5 fillMode: Image.PreserveAspectCrop } Label { From dd317ec777383a279376c02e9f0675bf8f32b7e3 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Thu, 26 Sep 2024 00:18:11 +0900 Subject: [PATCH 05/19] =?UTF-8?q?=E5=8B=95=E7=94=BB=E3=81=AE=E3=83=AC?= =?UTF-8?q?=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88=E3=82=92=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/parts/VideoFrame.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/qml/parts/VideoFrame.qml b/app/qml/parts/VideoFrame.qml index a4bbfb5d..9d5a2c00 100644 --- a/app/qml/parts/VideoFrame.qml +++ b/app/qml/parts/VideoFrame.qml @@ -33,7 +33,7 @@ ClickableFrame { id: thumbImage width: videoFrame.width height: { - if(status !== Image.Null) { + if(thumbImage.source !== "") { if(sourceSize.width > sourceSize.height){ return (width / sourceSize.width) * sourceSize.height }else{ From 810ff1e568a51829ae90cf119890008a5d83e601 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Thu, 26 Sep 2024 23:04:57 +0900 Subject: [PATCH 06/19] =?UTF-8?q?=E7=94=BB=E5=83=8F=E3=83=AC=E3=82=A4?= =?UTF-8?q?=E3=82=A2=E3=82=A6=E3=83=88=E3=81=AE=E8=AA=BF=E6=95=B4=EF=BC=88?= =?UTF-8?q?=E3=82=B9=E3=83=AC=E3=83=83=E3=83=89=E3=83=BB=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/view/NotificationListView.qml | 1 + app/qml/view/PostThreadView.qml | 1 + app/qtquick/notification/notificationlistmodel.cpp | 8 ++++++++ app/qtquick/notification/notificationlistmodel.h | 1 + 4 files changed, 11 insertions(+) diff --git a/app/qml/view/NotificationListView.qml b/app/qml/view/NotificationListView.qml index 92bd3013..5d4b29e9 100644 --- a/app/qml/view/NotificationListView.qml +++ b/app/qml/view/NotificationListView.qml @@ -116,6 +116,7 @@ ScrollView { postImagePreview.layoutType: notificationListView.imageLayoutType postImagePreview.embedImages: model.embedImages postImagePreview.embedAlts: model.embedImagesAlt + postImagePreview.embedImageRatios: model.embedImagesRatio postImagePreview.onRequestViewImages: (index) => requestViewImages(index, model.embedImagesFull, model.embedImagesAlt) blockedQuoteFrame.visible: model.quoteRecordBlocked blockedQuoteFrameLabel.text: model.quoteRecordBlockedStatus diff --git a/app/qml/view/PostThreadView.qml b/app/qml/view/PostThreadView.qml index 32761be6..3153db6d 100644 --- a/app/qml/view/PostThreadView.qml +++ b/app/qml/view/PostThreadView.qml @@ -144,6 +144,7 @@ ColumnLayout { postImagePreview.layoutType: postThreadView.imageLayoutType postImagePreview.embedImages: model.embedImages postImagePreview.embedAlts: model.embedImagesAlt + postImagePreview.embedImageRatios: model.embedImagesRatio postImagePreview.onRequestViewImages: (index) => requestViewImages(index, model.embedImagesFull, model.embedImagesAlt) quoteFilterFrame.visible: model.quoteFilterMatched && !model.quoteRecordBlocked diff --git a/app/qtquick/notification/notificationlistmodel.cpp b/app/qtquick/notification/notificationlistmodel.cpp index b0866e0d..4d331b11 100644 --- a/app/qtquick/notification/notificationlistmodel.cpp +++ b/app/qtquick/notification/notificationlistmodel.cpp @@ -186,6 +186,13 @@ QVariant NotificationListModel::item(int row, NotificationListModelRoles role) c AtProtocolType::LexiconsTypeUnknown::CopyImageType::Alt); else return QStringList(); + } else if (role == EmbedImagesRatioRole) { + if (m_postHash.contains(current.cid)) + return AtProtocolType::LexiconsTypeUnknown::copyImagesFromPostView( + m_postHash[current.cid], + AtProtocolType::LexiconsTypeUnknown::CopyImageType::Ratio); + else + return QStringList(); //---------------------------------------- } else if (role == ReplyCountRole) { @@ -928,6 +935,7 @@ QHash NotificationListModel::roleNames() const roles[EmbedImagesRole] = "embedImages"; roles[EmbedImagesFullRole] = "embedImagesFull"; roles[EmbedImagesAltRole] = "embedImagesAlt"; + roles[EmbedImagesRatioRole] = "embedImagesRatio"; roles[IsRepostedRole] = "isReposted"; roles[IsLikedRole] = "isLiked"; diff --git a/app/qtquick/notification/notificationlistmodel.h b/app/qtquick/notification/notificationlistmodel.h index 0283d80c..2603a978 100644 --- a/app/qtquick/notification/notificationlistmodel.h +++ b/app/qtquick/notification/notificationlistmodel.h @@ -53,6 +53,7 @@ class NotificationListModel : public AtpAbstractListModel EmbedImagesRole, EmbedImagesFullRole, EmbedImagesAltRole, + EmbedImagesRatioRole, IsRepostedRole, IsLikedRole, From 6a8eead9e469e8d6c918f3ec53da0fedc9a4d551 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Fri, 27 Sep 2024 23:29:06 +0900 Subject: [PATCH 07/19] =?UTF-8?q?=E8=AA=8D=E8=A8=BC=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=81=AA=E3=81=84=E3=82=A2=E3=82=AB=E3=82=A6=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=81=8C=E3=81=82=E3=82=8B=E3=81=A8=E3=81=8D=E3=81=AE=E3=83=95?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/dialogs/AccountDialog.qml | 8 ++++ app/qml/dialogs/MessageDialog.qml | 2 +- app/qml/main.qml | 45 ++++++++++++++++--- app/qml/parts/SideBar.qml | 9 ++-- app/qtquick/account/accountlistmodel.cpp | 56 ++++++++++++++++++++---- app/qtquick/account/accountlistmodel.h | 12 ++++- 6 files changed, 111 insertions(+), 21 deletions(-) diff --git a/app/qml/dialogs/AccountDialog.qml b/app/qml/dialogs/AccountDialog.qml index 8888c251..2940c0ed 100644 --- a/app/qml/dialogs/AccountDialog.qml +++ b/app/qml/dialogs/AccountDialog.qml @@ -123,6 +123,14 @@ Dialog { fontPointSize: AdjustedValues.f8 visible: model.isMain } + TagLabel { + source: "" + text: " Please login" + color: Material.color(Material.Red) + fontPointSize: AdjustedValues.f8 + visible: !model.authorized + } + Item { Layout.fillWidth: true Layout.preferredHeight: 1 diff --git a/app/qml/dialogs/MessageDialog.qml b/app/qml/dialogs/MessageDialog.qml index fd571679..d48dbcd1 100644 --- a/app/qml/dialogs/MessageDialog.qml +++ b/app/qml/dialogs/MessageDialog.qml @@ -17,7 +17,7 @@ Dialog { property int parentWidth: parent.width property alias text: messageTextArea.text - property string status: "normal" + property string status: "normal" // normal, error property bool useCancel: false function show(status, title, message){ diff --git a/app/qml/main.qml b/app/qml/main.qml index e83bfebf..6e515dfd 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -161,8 +161,27 @@ ApplicationWindow { AccountDialog { id: accountDialog + property bool showLogainAgainMessage: false accountModel: accountListModel - onClosed: accountListModel.syncColumn() + onOpened: { + if(showLogainAgainMessage){ + messageDialog.show("error", qsTr("Authentication error"), + qsTr("Some accounts require you to log in again.")) + } + showLogainAgainMessage = false + } + onClosed: { + if(columnManageModel.rowCount() === 0){ + if(accountListModel.allAccountsReady){ + // すべてのアカウント情報の認証が終わったのでカラムを復元 + console.log("start loading columns") + columnManageModel.load() + listsListModel.load() + } + }else{ + accountListModel.syncColumn() + } + } onErrorOccured: (account_uuid, code, message) => appWindow.errorHandler(account_uuid, code, message) onRequestAddMutedWords: (account_uuid) => { if(addMutedWordDialog.account.set(accountListModel, account_uuid)){ @@ -450,18 +469,29 @@ ApplicationWindow { id: accountListModel onUpdatedSession: (row, uuid) => { console.log("onUpdatedSession:" + row + ", " + uuid) - if(columnManageModel.rowCount() === 0 && allAccountsReady()){ - // すべてのアカウント情報の認証が終わったのでカラムを復元 - console.log("start loading columns") - columnManageModel.load() - listsListModel.load() - } } onUpdatedAccount: (row, uuid) => { console.log("onUpdatedAccount:" + row + ", " + uuid) // カラムを更新しにいく repeater.updateAccount(uuid) } + onFinished: { + console.log("onFinished:" + allAccountsReady + ", count=" + columnManageModel.rowCount()) + if(columnManageModel.rowCount() === 0){ + if(allAccountsReady){ + // すべてのアカウント情報の認証が終わったのでカラムを復元 + console.log("start loading columns") + columnManageModel.load() + listsListModel.load() + }else{ + // 失敗しているアカウントがあるのでダイアログを出す + messageDialog.close() + accountDialog.showLogainAgainMessage = true + accountDialog.open() + } + } + } + onErrorOccured: (code, message) => appWindow.errorHandler("", code, message) function syncColumn(){ @@ -717,6 +747,7 @@ ApplicationWindow { SideBar { anchors.fill: parent anchors.margins: 1 + ready: accountListModel.allAccountsReady post.onClicked: postDialog.open() search.onClicked: searchDialog.open() addColumn.onClicked: addColumnDialog.open() diff --git a/app/qml/parts/SideBar.qml b/app/qml/parts/SideBar.qml index 8199dc85..93d0296c 100644 --- a/app/qml/parts/SideBar.qml +++ b/app/qml/parts/SideBar.qml @@ -11,6 +11,7 @@ ColumnLayout { anchors.margins: 1 spacing: 0 + property bool ready: false property alias post: post property alias search: search property alias addColumn: addColumn @@ -23,7 +24,7 @@ ColumnLayout { width: parent.width Layout.preferredWidth: parent.width Layout.preferredHeight: AdjustedValues.b36 - enabled: accountListModel.count > 0 + enabled: parent.ready display: AbstractButton.IconOnly iconSource: "../images/edit.png" // iconText: qsTr("New Post") @@ -35,7 +36,7 @@ ColumnLayout { width: parent.width Layout.preferredWidth: parent.width Layout.preferredHeight: AdjustedValues.b36 - enabled: accountListModel.count > 0 + enabled: parent.ready display: AbstractButton.IconOnly iconSource: "../images/search.png" onWidthChanged: console.log("search:" + width) @@ -51,7 +52,7 @@ ColumnLayout { width: parent.width Layout.preferredWidth: parent.width Layout.preferredHeight: AdjustedValues.b36 - enabled: accountListModel.count > 0 + enabled: parent.ready display: AbstractButton.IconOnly iconSource: "../images/column.png" // iconText: qsTr("Add column") @@ -63,7 +64,7 @@ ColumnLayout { Layout.preferredWidth: parent.width Layout.preferredHeight: AdjustedValues.b36 visible: false - enabled: accountListModel.count > 0 + enabled: parent.ready display: AbstractButton.IconOnly iconSource: "../images/hand.png" } diff --git a/app/qtquick/account/accountlistmodel.cpp b/app/qtquick/account/accountlistmodel.cpp index e55d7cf7..59c06e89 100644 --- a/app/qtquick/account/accountlistmodel.cpp +++ b/app/qtquick/account/accountlistmodel.cpp @@ -24,7 +24,8 @@ using AtProtocolInterface::ComAtprotoServerCreateSessionEx; using AtProtocolInterface::ComAtprotoServerRefreshSessionEx; using AtProtocolInterface::DirectoryPlc; -AccountListModel::AccountListModel(QObject *parent) : QAbstractListModel { parent } +AccountListModel::AccountListModel(QObject *parent) + : QAbstractListModel { parent }, m_allAccountsReady(false) { connect(&m_timer, &QTimer::timeout, [=]() { for (int row = 0; row < m_accountList.count(); row++) { @@ -93,6 +94,8 @@ QVariant AccountListModel::item(int row, AccountListModelRoles role) const else if (role == StatusRole) return static_cast(m_accountList.at(row).status); + else if (role == AuthorizedRole) + return m_accountList.at(row).status == AccountStatus::Authorized; return QVariant(); } @@ -189,6 +192,7 @@ void AccountListModel::updateAccount(const QString &service, const QString &iden emit countChanged(); } + checkAllAccountsReady(); save(); } @@ -202,6 +206,7 @@ void AccountListModel::removeAccount(int row) endRemoveRows(); emit countChanged(); + checkAllAccountsReady(); save(); } @@ -257,16 +262,16 @@ void AccountListModel::setMainAccount(int row) save(); } -bool AccountListModel::allAccountsReady() const +bool AccountListModel::checkAllAccountsReady() { - bool ready = true; + int ready_count = 0; for (const AccountData &item : qAsConst(m_accountList)) { - if (item.status == AccountStatus::Unknown) { - ready = false; - break; + if (item.status == AccountStatus::Authorized) { + ready_count++; } } - return ready; + setAllAccountsReady(!m_accountList.isEmpty() && m_accountList.count() == ready_count); + return allAccountsReady(); } void AccountListModel::refreshAccountSession(const QString &uuid) @@ -352,6 +357,7 @@ void AccountListModel::load() item.password = m_encryption.decrypt( doc.array().at(i).toObject().value("password").toString()); item.refreshJwt = m_encryption.decrypt(temp_refresh); + item.handle = item.identifier; for (const auto &value : doc.array().at(i).toObject().value("post_languages").toArray()) { item.post_languages.append(value.toString()); @@ -425,6 +431,7 @@ QHash AccountListModel::roleNames() const roles[ThreadGateOptionsRole] = "threadGateOptions"; roles[PostGateQuoteEnabledRole] = "postGateQuoteEnabled"; roles[StatusRole] = "status"; + roles[AuthorizedRole] = "authorized"; return roles; } @@ -459,6 +466,10 @@ void AccountListModel::createSession(int row) emit errorOccured(session->errorCode(), session->errorMessage()); } emit dataChanged(index(row), index(row)); + if (allAccountTried()) { + emit finished(); + } + checkAllAccountsReady(); session->deleteLater(); }); session->setAccount(m_accountList.at(row)); @@ -488,16 +499,21 @@ void AccountListModel::refreshSession(int row, bool initial) // 詳細を取得 getProfile(row); } else { - m_accountList[row].status = AccountStatus::Unauthorized; if (initial) { // 初期化時のみ(つまりloadから呼ばれたときだけは失敗したらcreateSessionで再スタート) qDebug() << "Initial refresh session fail."; + m_accountList[row].status = AccountStatus::Unknown; createSession(row); } else { + m_accountList[row].status = AccountStatus::Unauthorized; emit errorOccured(session->errorCode(), session->errorMessage()); } } emit dataChanged(index(row), index(row)); + if (allAccountTried()) { + emit finished(); + } + checkAllAccountsReady(); session->deleteLater(); }); session->setAccount(m_accountList.at(row)); @@ -591,7 +607,31 @@ void AccountListModel::getServiceEndpoint(const QString &did, const QString &ser plc->directory(did); } +bool AccountListModel::allAccountTried() const +{ + int count = 0; + for (const AccountData &item : qAsConst(m_accountList)) { + if (item.status != AccountStatus::Unknown) { + count++; + } + } + return (m_accountList.count() == count); +} + int AccountListModel::count() const { return m_accountList.count(); } + +bool AccountListModel::allAccountsReady() const +{ + return m_allAccountsReady; +} + +void AccountListModel::setAllAccountsReady(bool newAllAccountsReady) +{ + if (m_allAccountsReady == newAllAccountsReady) + return; + m_allAccountsReady = newAllAccountsReady; + emit allAccountsReadyChanged(); +} diff --git a/app/qtquick/account/accountlistmodel.h b/app/qtquick/account/accountlistmodel.h index 1aec64d7..06ce1e37 100644 --- a/app/qtquick/account/accountlistmodel.h +++ b/app/qtquick/account/accountlistmodel.h @@ -13,6 +13,8 @@ class AccountListModel : public QAbstractListModel Q_OBJECT Q_PROPERTY(int count READ count NOTIFY countChanged CONSTANT) + Q_PROPERTY(bool allAccountsReady READ allAccountsReady WRITE setAllAccountsReady NOTIFY + allAccountsReadyChanged FINAL) public: explicit AccountListModel(QObject *parent = nullptr); @@ -38,6 +40,7 @@ class AccountListModel : public QAbstractListModel ThreadGateOptionsRole, PostGateQuoteEnabledRole, StatusRole, + AuthorizedRole, }; Q_ENUM(AccountListModelRoles) @@ -58,7 +61,7 @@ class AccountListModel : public QAbstractListModel Q_INVOKABLE int indexAt(const QString &uuid); Q_INVOKABLE int getMainAccountIndex() const; Q_INVOKABLE void setMainAccount(int row); - Q_INVOKABLE bool allAccountsReady() const; + Q_INVOKABLE bool checkAllAccountsReady(); Q_INVOKABLE void refreshAccountSession(const QString &uuid); Q_INVOKABLE void refreshAccountProfile(const QString &uuid); @@ -68,12 +71,17 @@ class AccountListModel : public QAbstractListModel Q_INVOKABLE QVariant account(int row) const; int count() const; + bool allAccountsReady() const; + void setAllAccountsReady(bool newAllAccountsReady); signals: void errorOccured(const QString &code, const QString &message); void updatedSession(int row, const QString &uuid); void updatedAccount(int row, const QString &uuid); void countChanged(); + void finished(); + + void allAccountsReadyChanged(); protected: QHash roleNames() const; @@ -83,6 +91,7 @@ class AccountListModel : public QAbstractListModel QVariant m_accountTemp; QTimer m_timer; Encryption m_encryption; + bool m_allAccountsReady; QString appDataFolder() const; @@ -92,6 +101,7 @@ class AccountListModel : public QAbstractListModel void getRawProfile(int row); void getServiceEndpoint(const QString &did, const QString &service, std::function callback); + bool allAccountTried() const; }; #endif // ACCOUNTLISTMODEL_H From 69f187e8e79a4fe328874d7cc758ef5af04d085c Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Fri, 27 Sep 2024 23:32:08 +0900 Subject: [PATCH 08/19] =?UTF-8?q?=E8=B5=B7=E5=8B=95=E6=99=82=E3=81=AB?= =?UTF-8?q?=E3=82=A2=E3=82=AB=E3=82=A6=E3=83=B3=E3=83=88=E3=81=8C=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=81=A8=E3=81=8D=E3=81=AF=E7=AE=A1=E7=90=86=E3=83=80?= =?UTF-8?q?=E3=82=A4=E3=82=A2=E3=83=AD=E3=82=B0=E3=82=92=E9=96=8B=E3=81=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/main.qml | 2 ++ app/qtquick/account/accountlistmodel.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/app/qml/main.qml b/app/qml/main.qml index 6e515dfd..e866978a 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -478,6 +478,8 @@ ApplicationWindow { onFinished: { console.log("onFinished:" + allAccountsReady + ", count=" + columnManageModel.rowCount()) if(columnManageModel.rowCount() === 0){ + accountDialog.open() + }else if(columnManageModel.rowCount() === 0){ if(allAccountsReady){ // すべてのアカウント情報の認証が終わったのでカラムを復元 console.log("start loading columns") diff --git a/app/qtquick/account/accountlistmodel.cpp b/app/qtquick/account/accountlistmodel.cpp index 59c06e89..9af60c9a 100644 --- a/app/qtquick/account/accountlistmodel.cpp +++ b/app/qtquick/account/accountlistmodel.cpp @@ -399,6 +399,10 @@ void AccountListModel::load() m_accountList[0].is_main = true; } } + + if (m_accountList.isEmpty()) { + emit finished(); + } } QVariant AccountListModel::account(int row) const From 7ea079c3b18deef5103f01243ead512f0da6c137 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 00:03:45 +0900 Subject: [PATCH 09/19] =?UTF-8?q?=E3=83=AA=E3=83=AA=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=83=8E=E3=83=BC=E3=83=88=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/content/docs/release-note.en.md | 2 ++ web/content/docs/release-note.ja.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/web/content/docs/release-note.en.md b/web/content/docs/release-note.en.md index a14243b0..f79540a9 100644 --- a/web/content/docs/release-note.en.md +++ b/web/content/docs/release-note.en.md @@ -8,6 +8,8 @@ description: This is a multi-column Bluesky client. ## 2024 +- Update + - Change the flow when there are unauthenticated accounts - Fix - Fix the display of posts quoted from labeled posts diff --git a/web/content/docs/release-note.ja.md b/web/content/docs/release-note.ja.md index 44cf11a5..b8d1a3dd 100644 --- a/web/content/docs/release-note.ja.md +++ b/web/content/docs/release-note.ja.md @@ -8,6 +8,8 @@ description: マルチカラム対応Blueskyクライアント ## 2024 +- 更新 + - 認証できないアカウントがあるときのフローを変更 - 修正 - ラベリングされたポストから引用されたポストの表示を修正 From 46b58a185e1269444edc4955857fdc2475798a8e Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 00:29:54 +0900 Subject: [PATCH 10/19] =?UTF-8?q?lexcon=E3=81=A8=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E7=94=9F=E6=88=90=E3=82=B3=E3=83=BC=E3=83=89=E3=81=AE=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1stparty/atproto | 2 +- .../bsky/feed/appbskyfeedgetauthorfeed.cpp | 6 +++- .../app/bsky/feed/appbskyfeedgetauthorfeed.h | 2 +- lib/atprotocol/lexicons.h | 34 +++++++++++++------ lib/atprotocol/lexicons_func.cpp | 22 +++++++++++- lib/atprotocol/lexicons_func.h | 2 ++ 6 files changed, 53 insertions(+), 15 deletions(-) diff --git a/1stparty/atproto b/1stparty/atproto index 85c85350..eb20ff64 160000 --- a/1stparty/atproto +++ b/1stparty/atproto @@ -1 +1 @@ -Subproject commit 85c85350d13fb4468c12045e086ad91733b4bcb3 +Subproject commit eb20ff64a2d8e3061c652e1e247bf9b0fe3c41a6 diff --git a/lib/atprotocol/app/bsky/feed/appbskyfeedgetauthorfeed.cpp b/lib/atprotocol/app/bsky/feed/appbskyfeedgetauthorfeed.cpp index 1627c761..d0732b42 100644 --- a/lib/atprotocol/app/bsky/feed/appbskyfeedgetauthorfeed.cpp +++ b/lib/atprotocol/app/bsky/feed/appbskyfeedgetauthorfeed.cpp @@ -10,7 +10,8 @@ AppBskyFeedGetAuthorFeed::AppBskyFeedGetAuthorFeed(QObject *parent) } void AppBskyFeedGetAuthorFeed::getAuthorFeed(const QString &actor, const int limit, - const QString &cursor, const QString &filter) + const QString &cursor, const QString &filter, + const bool includePins) { QUrlQuery url_query; if (!actor.isEmpty()) { @@ -25,6 +26,9 @@ void AppBskyFeedGetAuthorFeed::getAuthorFeed(const QString &actor, const int lim if (!filter.isEmpty()) { url_query.addQueryItem(QStringLiteral("filter"), filter); } + if (includePins) { + url_query.addQueryItem(QStringLiteral("includePins"), "true"); + } get(QStringLiteral("xrpc/app.bsky.feed.getAuthorFeed"), url_query); } diff --git a/lib/atprotocol/app/bsky/feed/appbskyfeedgetauthorfeed.h b/lib/atprotocol/app/bsky/feed/appbskyfeedgetauthorfeed.h index ef0e895b..353d43f5 100644 --- a/lib/atprotocol/app/bsky/feed/appbskyfeedgetauthorfeed.h +++ b/lib/atprotocol/app/bsky/feed/appbskyfeedgetauthorfeed.h @@ -11,7 +11,7 @@ class AppBskyFeedGetAuthorFeed : public AppBskyFeedGetTimeline explicit AppBskyFeedGetAuthorFeed(QObject *parent = nullptr); void getAuthorFeed(const QString &actor, const int limit, const QString &cursor, - const QString &filter); + const QString &filter, const bool includePins); }; } diff --git a/lib/atprotocol/lexicons.h b/lib/atprotocol/lexicons.h index 581fed4f..08918ae5 100644 --- a/lib/atprotocol/lexicons.h +++ b/lib/atprotocol/lexicons.h @@ -179,6 +179,16 @@ struct Relationship }; } +// com.atproto.repo.strongRef +namespace ComAtprotoRepoStrongRef { +struct Main +{ + QString uri; // at-uri + QString cid; // cid +}; +// A URI with a content-hash fingerprint. +} + // app.bsky.actor.defs namespace AppBskyActorDefs { struct ProfileAssociatedChat @@ -250,6 +260,7 @@ struct ProfileViewDetailed QString createdAt; // datetime ViewerState viewer; QList labels; + ComAtprotoRepoStrongRef::Main pinnedPost; }; struct AdultContentPref { @@ -370,16 +381,6 @@ struct Preferences }; } -// com.atproto.repo.strongRef -namespace ComAtprotoRepoStrongRef { -struct Main -{ - QString uri; // at-uri - QString cid; // cid -}; -// A URI with a content-hash fingerprint. -} - // app.bsky.actor.profile namespace AppBskyActorProfile { enum class MainLabelsType : int { @@ -399,8 +400,8 @@ struct Main // application, on the overall account. // union end : labels ComAtprotoRepoStrongRef::Main joinedViaStarterPack; + ComAtprotoRepoStrongRef::Main pinnedPost; QString createdAt; // datetime - QString pinnedPost; // at-uri , (Unofficial field) }; } @@ -573,6 +574,7 @@ namespace AppBskyFeedDefs { enum class SkeletonFeedPostReasonType : int { none, reason_SkeletonReasonRepost, + reason_SkeletonReasonPin, }; enum class ThreadViewPostParentType : int { none, @@ -589,6 +591,7 @@ enum class ThreadViewPostRepliesType : int { enum class FeedViewPostReasonType : int { none, reason_ReasonRepost, + reason_ReasonPin, }; enum class ReplyRefRootType : int { none, @@ -642,6 +645,7 @@ struct ViewerState bool threadMuted = false; bool replyDisabled = false; bool embeddingDisabled = false; + bool pinned = false; }; struct ThreadgateView { @@ -705,6 +709,9 @@ struct ReasonRepost AppBskyActorDefs::ProfileViewBasic by; QString indexedAt; // datetime }; +struct ReasonPin +{ +}; struct FeedViewPost { PostView post; @@ -712,6 +719,7 @@ struct FeedViewPost // union start : reason FeedViewPostReasonType reason_type = FeedViewPostReasonType::none; ReasonRepost reason_ReasonRepost; + ReasonPin reason_ReasonPin; // union end : reason QString feedContext; // Context provided by feed generator that may be passed back alongside // interactions. @@ -736,12 +744,16 @@ struct SkeletonReasonRepost { QString repost; // at-uri }; +struct SkeletonReasonPin +{ +}; struct SkeletonFeedPost { QString post; // at-uri // union start : reason SkeletonFeedPostReasonType reason_type = SkeletonFeedPostReasonType::none; SkeletonReasonRepost reason_SkeletonReasonRepost; + SkeletonReasonPin reason_SkeletonReasonPin; // union end : reason QString feedContext; // Context that will be passed through to client and may be passed to feed // generator back alongside interactions. diff --git a/lib/atprotocol/lexicons_func.cpp b/lib/atprotocol/lexicons_func.cpp index 77c45fa1..2a229cca 100644 --- a/lib/atprotocol/lexicons_func.cpp +++ b/lib/atprotocol/lexicons_func.cpp @@ -112,6 +112,7 @@ void copyProfileViewDetailed(const QJsonObject &src, AppBskyActorDefs::ProfileVi ComAtprotoLabelDefs::copyLabel(s.toObject(), child); dest.labels.append(child); } + ComAtprotoRepoStrongRef::copyMain(src.value("pinnedPost").toObject(), dest.pinnedPost); } } void copyAdultContentPref(const QJsonObject &src, AppBskyActorDefs::AdultContentPref &dest) @@ -560,8 +561,8 @@ void copyMain(const QJsonObject &src, AppBskyActorProfile::Main &dest) } ComAtprotoRepoStrongRef::copyMain(src.value("joinedViaStarterPack").toObject(), dest.joinedViaStarterPack); + ComAtprotoRepoStrongRef::copyMain(src.value("pinnedPost").toObject(), dest.pinnedPost); dest.createdAt = src.value("createdAt").toString(); - dest.pinnedPost = src.value("pinnedPost").toString(); } } } @@ -929,6 +930,7 @@ void copyViewerState(const QJsonObject &src, AppBskyFeedDefs::ViewerState &dest) dest.threadMuted = src.value("threadMuted").toBool(); dest.replyDisabled = src.value("replyDisabled").toBool(); dest.embeddingDisabled = src.value("embeddingDisabled").toBool(); + dest.pinned = src.value("pinned").toBool(); } } void copyThreadgateView(const QJsonObject &src, AppBskyFeedDefs::ThreadgateView &dest) @@ -1053,6 +1055,10 @@ void copyReasonRepost(const QJsonObject &src, AppBskyFeedDefs::ReasonRepost &des dest.indexedAt = src.value("indexedAt").toString(); } } +void copyReasonPin(const QJsonObject &src, AppBskyFeedDefs::ReasonPin &dest) +{ + if (!src.isEmpty()) { } +} void copyFeedViewPost(const QJsonObject &src, AppBskyFeedDefs::FeedViewPost &dest) { if (!src.isEmpty()) { @@ -1064,6 +1070,10 @@ void copyFeedViewPost(const QJsonObject &src, AppBskyFeedDefs::FeedViewPost &des AppBskyFeedDefs::copyReasonRepost(src.value("reason").toObject(), dest.reason_ReasonRepost); } + if (reason_type == QStringLiteral("app.bsky.feed.defs#reasonPin")) { + dest.reason_type = AppBskyFeedDefs::FeedViewPostReasonType::reason_ReasonPin; + AppBskyFeedDefs::copyReasonPin(src.value("reason").toObject(), dest.reason_ReasonPin); + } dest.feedContext = src.value("feedContext").toString(); } } @@ -1126,6 +1136,10 @@ void copySkeletonReasonRepost(const QJsonObject &src, AppBskyFeedDefs::SkeletonR dest.repost = src.value("repost").toString(); } } +void copySkeletonReasonPin(const QJsonObject &src, AppBskyFeedDefs::SkeletonReasonPin &dest) +{ + if (!src.isEmpty()) { } +} void copySkeletonFeedPost(const QJsonObject &src, AppBskyFeedDefs::SkeletonFeedPost &dest) { if (!src.isEmpty()) { @@ -1137,6 +1151,12 @@ void copySkeletonFeedPost(const QJsonObject &src, AppBskyFeedDefs::SkeletonFeedP AppBskyFeedDefs::copySkeletonReasonRepost(src.value("reason").toObject(), dest.reason_SkeletonReasonRepost); } + if (reason_type == QStringLiteral("app.bsky.feed.defs#skeletonReasonPin")) { + dest.reason_type = + AppBskyFeedDefs::SkeletonFeedPostReasonType::reason_SkeletonReasonPin; + AppBskyFeedDefs::copySkeletonReasonPin(src.value("reason").toObject(), + dest.reason_SkeletonReasonPin); + } dest.feedContext = src.value("feedContext").toString(); } } diff --git a/lib/atprotocol/lexicons_func.h b/lib/atprotocol/lexicons_func.h index 1d82a7c6..5ba028dd 100644 --- a/lib/atprotocol/lexicons_func.h +++ b/lib/atprotocol/lexicons_func.h @@ -125,9 +125,11 @@ void copyNotFoundPost(const QJsonObject &src, AppBskyFeedDefs::NotFoundPost &des void copyBlockedPost(const QJsonObject &src, AppBskyFeedDefs::BlockedPost &dest); void copyReplyRef(const QJsonObject &src, AppBskyFeedDefs::ReplyRef &dest); void copyReasonRepost(const QJsonObject &src, AppBskyFeedDefs::ReasonRepost &dest); +void copyReasonPin(const QJsonObject &src, AppBskyFeedDefs::ReasonPin &dest); void copyFeedViewPost(const QJsonObject &src, AppBskyFeedDefs::FeedViewPost &dest); void copyThreadViewPost(const QJsonObject &src, AppBskyFeedDefs::ThreadViewPost &dest); void copySkeletonReasonRepost(const QJsonObject &src, AppBskyFeedDefs::SkeletonReasonRepost &dest); +void copySkeletonReasonPin(const QJsonObject &src, AppBskyFeedDefs::SkeletonReasonPin &dest); void copySkeletonFeedPost(const QJsonObject &src, AppBskyFeedDefs::SkeletonFeedPost &dest); void copyInteraction(const QJsonObject &src, AppBskyFeedDefs::Interaction &dest); } From c3d9912f61b88ffb7df9d539b0038a63861ed378 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 00:48:40 +0900 Subject: [PATCH 11/19] =?UTF-8?q?=E3=83=93=E3=83=AB=E3=83=89=E3=81=A7?= =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qtquick/account/accountlistmodel.cpp | 5 +++-- app/qtquick/operation/recordoperator.cpp | 5 ++++- app/qtquick/profile/userprofile.cpp | 2 +- app/qtquick/timeline/authorfeedlistmodel.cpp | 4 ++-- .../atproto/repo/comatprotorepoputrecordex.cpp | 15 +++++++++------ .../com/atproto/repo/comatprotorepoputrecordex.h | 3 ++- tests/atprotocol_test/tst_atprotocol_test.cpp | 7 ++++--- 7 files changed, 25 insertions(+), 16 deletions(-) diff --git a/app/qtquick/account/accountlistmodel.cpp b/app/qtquick/account/accountlistmodel.cpp index 9af60c9a..bf002c6d 100644 --- a/app/qtquick/account/accountlistmodel.cpp +++ b/app/qtquick/account/accountlistmodel.cpp @@ -575,8 +575,9 @@ void AccountListModel::getRawProfile(int row) AtProtocolType::AppBskyActorProfile::Main profile = AtProtocolType::LexiconsTypeUnknown::fromQVariant< AtProtocolType::AppBskyActorProfile::Main>(record->value()); - qDebug() << "Update pinned post" << profile.pinnedPost; - PinnedPostCache::getInstance()->update(m_accountList.at(row).did, profile.pinnedPost); + qDebug() << "Update pinned post" << profile.pinnedPost.uri; + PinnedPostCache::getInstance()->update(m_accountList.at(row).did, + profile.pinnedPost.uri); } else { emit errorOccured(record->errorCode(), record->errorMessage()); diff --git a/app/qtquick/operation/recordoperator.cpp b/app/qtquick/operation/recordoperator.cpp index 3e3c6f3b..e991a53f 100644 --- a/app/qtquick/operation/recordoperator.cpp +++ b/app/qtquick/operation/recordoperator.cpp @@ -816,9 +816,12 @@ void RecordOperator::updatePostPinning(const QString &post_uri) setRunning(false); new_profile->deleteLater(); }); + ComAtprotoRepoStrongRef::Main pinned_post; + pinned_post.uri = post_uri; + pinned_post.cid = ""; new_profile->setAccount(m_account); new_profile->profile(old_record.avatar, old_record.banner, old_record.description, - old_record.displayName, post_uri, old_cid); + old_record.displayName, pinned_post, old_cid); } else { setProgressMessage(QString()); emit errorOccured(old_profile->errorCode(), old_profile->errorMessage()); diff --git a/app/qtquick/profile/userprofile.cpp b/app/qtquick/profile/userprofile.cpp index bd91b96b..b811bdaa 100644 --- a/app/qtquick/profile/userprofile.cpp +++ b/app/qtquick/profile/userprofile.cpp @@ -517,7 +517,7 @@ void UserProfile::getRawProfile() AtProtocolType::AppBskyActorProfile::Main profile = AtProtocolType::LexiconsTypeUnknown::fromQVariant< AtProtocolType::AppBskyActorProfile::Main>(record->value()); - setPinnedPost(profile.pinnedPost); + setPinnedPost(profile.pinnedPost.uri); } setRunning(false); record->deleteLater(); diff --git a/app/qtquick/timeline/authorfeedlistmodel.cpp b/app/qtquick/timeline/authorfeedlistmodel.cpp index d8c55951..fbcd8244 100644 --- a/app/qtquick/timeline/authorfeedlistmodel.cpp +++ b/app/qtquick/timeline/authorfeedlistmodel.cpp @@ -42,7 +42,7 @@ bool AuthorFeedListModel::getLatest() } timeline->setAccount(account()); timeline->setLabelers(labelerDids()); - timeline->getAuthorFeed(authorDid(), -1, QString(), filter_type); + timeline->getAuthorFeed(authorDid(), -1, QString(), filter_type, false); }); return true; } @@ -78,7 +78,7 @@ bool AuthorFeedListModel::getNext() } timeline->setAccount(account()); timeline->setLabelers(labelerDids()); - timeline->getAuthorFeed(authorDid(), -1, m_cursor, filter_type); + timeline->getAuthorFeed(authorDid(), -1, m_cursor, filter_type, false); }); return true; } diff --git a/lib/extension/com/atproto/repo/comatprotorepoputrecordex.cpp b/lib/extension/com/atproto/repo/comatprotorepoputrecordex.cpp index a989b789..d42669eb 100644 --- a/lib/extension/com/atproto/repo/comatprotorepoputrecordex.cpp +++ b/lib/extension/com/atproto/repo/comatprotorepoputrecordex.cpp @@ -8,10 +8,10 @@ ComAtprotoRepoPutRecordEx::ComAtprotoRepoPutRecordEx(QObject *parent) { } -void ComAtprotoRepoPutRecordEx::profile(const AtProtocolType::Blob &avatar, - const AtProtocolType::Blob &banner, - const QString &description, const QString &display_name, - const QString &pinned_post_uri, const QString &cid) +void ComAtprotoRepoPutRecordEx::profile( + const AtProtocolType::Blob &avatar, const AtProtocolType::Blob &banner, + const QString &description, const QString &display_name, + const AtProtocolType::ComAtprotoRepoStrongRef::Main &pinned_post, const QString &cid) { QString type = QStringLiteral("app.bsky.actor.profile"); QJsonObject json_record; @@ -32,8 +32,11 @@ void ComAtprotoRepoPutRecordEx::profile(const AtProtocolType::Blob &avatar, setJsonBlob(banner, json_banner); json_record.insert("banner", json_banner); } - if (!pinned_post_uri.isEmpty()) { - json_record.insert("pinnedPost", pinned_post_uri); + if (!pinned_post.uri.isEmpty()) { + QJsonObject json_subject; + json_subject.insert("cid", pinned_post.cid); + json_subject.insert("uri", pinned_post.uri); + json_record.insert("pinnedPost", json_subject); } putRecord(this->did(), type, QStringLiteral("self"), true, json_record, cid, QString()); diff --git a/lib/extension/com/atproto/repo/comatprotorepoputrecordex.h b/lib/extension/com/atproto/repo/comatprotorepoputrecordex.h index 7b8ffc33..f1cc6f3d 100644 --- a/lib/extension/com/atproto/repo/comatprotorepoputrecordex.h +++ b/lib/extension/com/atproto/repo/comatprotorepoputrecordex.h @@ -12,7 +12,8 @@ class ComAtprotoRepoPutRecordEx : public ComAtprotoRepoPutRecord void profile(const AtProtocolType::Blob &avatar, const AtProtocolType::Blob &banner, const QString &description, const QString &display_name, - const QString &pinned_post_uri, const QString &cid); + const AtProtocolType::ComAtprotoRepoStrongRef::Main &pinned_post, + const QString &cid); void list(const AtProtocolType::Blob &avatar, const QString &purpose, const QString &description, const QString &name, const QString &rkey); void postGate(const QString &uri, diff --git a/tests/atprotocol_test/tst_atprotocol_test.cpp b/tests/atprotocol_test/tst_atprotocol_test.cpp index 3236127c..154e400f 100644 --- a/tests/atprotocol_test/tst_atprotocol_test.cpp +++ b/tests/atprotocol_test/tst_atprotocol_test.cpp @@ -1809,6 +1809,7 @@ void atprotocol_test::test_ComAtprotoRepoGetRecord_profile() void atprotocol_test::test_ComAtprotoRepoPutRecord_profile() { AtProtocolInterface::ComAtprotoRepoPutRecordEx record; + AtProtocolType::ComAtprotoRepoStrongRef::Main pinned_post; AtProtocolType::Blob avatar; AtProtocolType::Blob banner; @@ -1821,7 +1822,7 @@ void atprotocol_test::test_ComAtprotoRepoPutRecord_profile() avatar.size = 52880; { QSignalSpy spy(&record, SIGNAL(finished(bool))); - record.profile(avatar, banner, "description", "display name", QString(), + record.profile(avatar, banner, "description", "display name", pinned_post, "bafyreie3ckzfk5xadlunbotovrffkhsfb2hdnr7bujofy2bb5ro45elcmy"); spy.wait(); QVERIFY2(spy.count() == 1, QString("spy.count()=%1").arg(spy.count()).toUtf8()); @@ -1840,7 +1841,7 @@ void atprotocol_test::test_ComAtprotoRepoPutRecord_profile() banner.size = 51567; { QSignalSpy spy(&record, SIGNAL(finished(bool))); - record.profile(avatar, banner, "epub\nLeME", "IoriAYANE", QString(), + record.profile(avatar, banner, "epub\nLeME", "IoriAYANE", pinned_post, "bafyreif4chy7iugq3blmvqt6sgqeo72pxkkr4v4fnzjqii2yriijh545ei"); spy.wait(); QVERIFY2(spy.count() == 1, QString("spy.count()=%1").arg(spy.count()).toUtf8()); @@ -2089,7 +2090,7 @@ void atprotocol_test::test_AppBskyFeedGetAuthorFeed() { QSignalSpy spy(&api, SIGNAL(finished(bool))); - api.getAuthorFeed("", 0, QString(), QString()); + api.getAuthorFeed("", 0, QString(), QString(), false); spy.wait(); QVERIFY2(spy.count() == 1, QString("spy.count()=%1").arg(spy.count()).toUtf8()); QList arguments = spy.takeFirst(); From b148563e95c9e22a536038359afa4dc6dcf02ce4 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 01:31:21 +0900 Subject: [PATCH 12/19] =?UTF-8?q?=E3=83=94=E3=83=B3=E6=AD=A2=E3=82=81?= =?UTF-8?q?=E3=82=92=E5=85=AC=E5=BC=8F=E3=81=AE=E6=96=B9=E5=BC=8F=E3=81=A7?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qtquick/operation/recordoperator.cpp | 4 ++-- app/qtquick/operation/recordoperator.h | 2 +- app/qtquick/timeline/timelinelistmodel.cpp | 4 +++- .../hagoromo_test2/data/profile/1/com.atproto.repo.putRecord | 5 ++++- .../data/profile/3.1/com.atproto.repo.putRecord | 5 ++++- .../response/profile/1/xrpc/com.atproto.repo.getRecord | 5 ++++- .../response/profile/3.1/xrpc/com.atproto.repo.getRecord | 5 ++++- tests/hagoromo_test2/tst_hagoromo_test2.cpp | 5 +++-- 8 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/qtquick/operation/recordoperator.cpp b/app/qtquick/operation/recordoperator.cpp index e991a53f..26a197be 100644 --- a/app/qtquick/operation/recordoperator.cpp +++ b/app/qtquick/operation/recordoperator.cpp @@ -791,7 +791,7 @@ void RecordOperator::updateProfile(const QString &avatar_url, const QString &ban old_profile->profile(m_account.did); } -void RecordOperator::updatePostPinning(const QString &post_uri) +void RecordOperator::updatePostPinning(const QString &post_uri, const QString &post_cid) { if (running()) return; @@ -818,7 +818,7 @@ void RecordOperator::updatePostPinning(const QString &post_uri) }); ComAtprotoRepoStrongRef::Main pinned_post; pinned_post.uri = post_uri; - pinned_post.cid = ""; + pinned_post.cid = post_cid; new_profile->setAccount(m_account); new_profile->profile(old_record.avatar, old_record.banner, old_record.description, old_record.displayName, pinned_post, old_cid); diff --git a/app/qtquick/operation/recordoperator.h b/app/qtquick/operation/recordoperator.h index 90c07033..c07e63f5 100644 --- a/app/qtquick/operation/recordoperator.h +++ b/app/qtquick/operation/recordoperator.h @@ -71,7 +71,7 @@ class RecordOperator : public QObject Q_INVOKABLE void updateProfile(const QString &avatar_url, const QString &banner_url, const QString &description, const QString &display_name); - Q_INVOKABLE void updatePostPinning(const QString &post_uri); + Q_INVOKABLE void updatePostPinning(const QString &post_uri, const QString &post_cid); Q_INVOKABLE void updateList(const QString &uri, const QString &avatar_url, const QString &description, const QString &name); Q_INVOKABLE void updateThreadGate(const QString &uri, const QString &threadgate_uri, diff --git a/app/qtquick/timeline/timelinelistmodel.cpp b/app/qtquick/timeline/timelinelistmodel.cpp index bf367b12..13f43692 100644 --- a/app/qtquick/timeline/timelinelistmodel.cpp +++ b/app/qtquick/timeline/timelinelistmodel.cpp @@ -610,8 +610,10 @@ bool TimelineListModel::pin(int row) const AppBskyFeedDefs::FeedViewPost ¤t = m_viewPostHash.value(m_cidList.at(row)); QString pin_uri; + QString pin_cid; if (!item(row, PinnedByMeRole).toBool()) { pin_uri = current.post.uri; + pin_cid = current.post.cid; } if (runningPostPinning(row)) @@ -638,7 +640,7 @@ bool TimelineListModel::pin(int row) }); ope->setAccount(account().service, account().did, account().handle, account().email, account().accessJwt, account().refreshJwt); - ope->updatePostPinning(pin_uri); + ope->updatePostPinning(pin_uri, pin_cid); return true; } diff --git a/tests/hagoromo_test2/data/profile/1/com.atproto.repo.putRecord b/tests/hagoromo_test2/data/profile/1/com.atproto.repo.putRecord index 01e70c9b..2c0c2bb8 100644 --- a/tests/hagoromo_test2/data/profile/1/com.atproto.repo.putRecord +++ b/tests/hagoromo_test2/data/profile/1/com.atproto.repo.putRecord @@ -22,7 +22,10 @@ }, "description": "description", "displayName": "display_name", - "pinnedPost": "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n" + "pinnedPost": { + "uri": "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n", + "cid": "cid_hoge_before" + } }, "swapRecord": "bafyreif4chy7iugq3blmvqt6sgqeo72pxkkr4v4fnzjqii2yriijh545ei", "validate": true diff --git a/tests/hagoromo_test2/data/profile/3.1/com.atproto.repo.putRecord b/tests/hagoromo_test2/data/profile/3.1/com.atproto.repo.putRecord index cdbb5182..8bf392ba 100644 --- a/tests/hagoromo_test2/data/profile/3.1/com.atproto.repo.putRecord +++ b/tests/hagoromo_test2/data/profile/3.1/com.atproto.repo.putRecord @@ -22,7 +22,10 @@ }, "description": "epub\nLeME", "displayName": "IoriAYANE", - "pinnedPost": "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n" + "pinnedPost": { + "uri": "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n", + "cid": "cid_after" + } }, "swapRecord": "bafyreif4chy7iugq3blmvqt6sgqeo72pxkkr4v4fnzjqii2yriijh545ei", "validate": true diff --git a/tests/hagoromo_test2/response/profile/1/xrpc/com.atproto.repo.getRecord b/tests/hagoromo_test2/response/profile/1/xrpc/com.atproto.repo.getRecord index 4d78a45c..e7ec9719 100644 --- a/tests/hagoromo_test2/response/profile/1/xrpc/com.atproto.repo.getRecord +++ b/tests/hagoromo_test2/response/profile/1/xrpc/com.atproto.repo.getRecord @@ -19,7 +19,10 @@ "mimeType": "image/jpeg", "size": 51567 }, - "pinnedPost": "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n", + "pinnedPost": { + "uri": "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n", + "cid": "cid_hoge_before" + }, "description": "epub\nLeME", "displayName": "IoriAYANE" } diff --git a/tests/hagoromo_test2/response/profile/3.1/xrpc/com.atproto.repo.getRecord b/tests/hagoromo_test2/response/profile/3.1/xrpc/com.atproto.repo.getRecord index 4d78a45c..d95453b2 100644 --- a/tests/hagoromo_test2/response/profile/3.1/xrpc/com.atproto.repo.getRecord +++ b/tests/hagoromo_test2/response/profile/3.1/xrpc/com.atproto.repo.getRecord @@ -19,7 +19,10 @@ "mimeType": "image/jpeg", "size": 51567 }, - "pinnedPost": "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n", + "pinnedPost": { + "uri": "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n", + "cid": "cid_before" + }, "description": "epub\nLeME", "displayName": "IoriAYANE" } diff --git a/tests/hagoromo_test2/tst_hagoromo_test2.cpp b/tests/hagoromo_test2/tst_hagoromo_test2.cpp index d89ef4cf..2d777f80 100644 --- a/tests/hagoromo_test2/tst_hagoromo_test2.cpp +++ b/tests/hagoromo_test2/tst_hagoromo_test2.cpp @@ -153,7 +153,8 @@ void hagoromo_test::test_RecordOperator_profile() { QSignalSpy spy(&ope, SIGNAL(finished(bool, const QString &, const QString &))); ope.updatePostPinning( - "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n"); + "at://did:plc:ipj5qejfoqu6eukvt72uhyit/app.bsky.feed.post/3k5ml2mujje2n", + "cid_after"); spy.wait(); QVERIFY2(spy.count() == 1, QString("spy.count()=%1").arg(spy.count()).toUtf8()); @@ -166,7 +167,7 @@ void hagoromo_test::test_RecordOperator_profile() QString(), "dummy", QString()); { QSignalSpy spy(&ope, SIGNAL(finished(bool, const QString &, const QString &))); - ope.updatePostPinning(QString()); + ope.updatePostPinning(QString(), QString()); spy.wait(); QVERIFY2(spy.count() == 1, QString("spy.count()=%1").arg(spy.count()).toUtf8()); From 9e5baa6c1f2d2d2f6e39ab306ed45b4431ce5c79 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 01:51:56 +0900 Subject: [PATCH 13/19] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E5=87=A6?= =?UTF-8?q?=E7=90=86=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qml/main.qml | 2 +- app/qtquick/account/accountlistmodel.cpp | 5 ++- app/qtquick/profile/userprofile.cpp | 53 +++++++++--------------- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/app/qml/main.qml b/app/qml/main.qml index e866978a..9daede1b 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -477,7 +477,7 @@ ApplicationWindow { } onFinished: { console.log("onFinished:" + allAccountsReady + ", count=" + columnManageModel.rowCount()) - if(columnManageModel.rowCount() === 0){ + if(rowCount() === 0){ accountDialog.open() }else if(columnManageModel.rowCount() === 0){ if(allAccountsReady){ diff --git a/app/qtquick/account/accountlistmodel.cpp b/app/qtquick/account/accountlistmodel.cpp index bf002c6d..e4d3a205 100644 --- a/app/qtquick/account/accountlistmodel.cpp +++ b/app/qtquick/account/accountlistmodel.cpp @@ -400,6 +400,7 @@ void AccountListModel::load() } } + checkAllAccountsReady(); if (m_accountList.isEmpty()) { emit finished(); } @@ -470,10 +471,10 @@ void AccountListModel::createSession(int row) emit errorOccured(session->errorCode(), session->errorMessage()); } emit dataChanged(index(row), index(row)); + checkAllAccountsReady(); if (allAccountTried()) { emit finished(); } - checkAllAccountsReady(); session->deleteLater(); }); session->setAccount(m_accountList.at(row)); @@ -514,10 +515,10 @@ void AccountListModel::refreshSession(int row, bool initial) } } emit dataChanged(index(row), index(row)); + checkAllAccountsReady(); if (allAccountTried()) { emit finished(); } - checkAllAccountsReady(); session->deleteLater(); }); session->setAccount(m_accountList.at(row)); diff --git a/app/qtquick/profile/userprofile.cpp b/app/qtquick/profile/userprofile.cpp index b811bdaa..78d707cf 100644 --- a/app/qtquick/profile/userprofile.cpp +++ b/app/qtquick/profile/userprofile.cpp @@ -110,6 +110,7 @@ void UserProfile::getProfile(const QString &did) } setBelongingLists( ListItemsCache::getInstance()->getListNames(m_account.did, detail.did)); + setPinnedPost(detail.pinnedPost.uri); if (detail.associated.chat.allowIncoming == "none") { setAssociatedChatAllow(false); @@ -507,39 +508,25 @@ void UserProfile::getRawProfile() return; } - getRawInformation( - did(), - [=](const QString &service_endpoint, const QString ®istration_date, - const QList &handle_history) { - ComAtprotoRepoGetRecordEx *record = new ComAtprotoRepoGetRecordEx(this); - connect(record, &ComAtprotoRepoGetRecordEx::finished, this, [=](bool success) { - if (success) { - AtProtocolType::AppBskyActorProfile::Main profile = - AtProtocolType::LexiconsTypeUnknown::fromQVariant< - AtProtocolType::AppBskyActorProfile::Main>(record->value()); - setPinnedPost(profile.pinnedPost.uri); - } - setRunning(false); - record->deleteLater(); - }); - record->setAccount(m_account); - if (!service_endpoint.isEmpty()) { - record->setService(service_endpoint); - setServiceEndpoint(service_endpoint); - } else { - // プロフィールを参照されるユーザーのサービスが参照する側と同じとは限らない(bsky.socialだったとしても) - setServiceEndpoint(QString()); - } - setRegistrationDate(registration_date); - QStringList history; - for (const auto &item : handle_history) { - history.append(item.date); - history.append(item.handle); - history.append(item.endpoint); - } - setHandleHistory(history); - record->profile(did()); - }); + getRawInformation(did(), + [=](const QString &service_endpoint, const QString ®istration_date, + const QList &handle_history) { + if (!service_endpoint.isEmpty()) { + setServiceEndpoint(service_endpoint); + } else { + // プロフィールを参照されるユーザーのサービスが参照する側と同じとは限らない(bsky.socialだったとしても) + setServiceEndpoint(QString()); + } + setRegistrationDate(registration_date); + QStringList history; + for (const auto &item : handle_history) { + history.append(item.date); + history.append(item.handle); + history.append(item.endpoint); + } + setHandleHistory(history); + setRunning(false); + }); } QString UserProfile::labelsTitle(const QString &label, const bool for_image, From d8ba7f4a1a3e185b9d73e4b81f83aaba268571d3 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 02:54:35 +0900 Subject: [PATCH 14/19] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E5=87=A6?= =?UTF-8?q?=E7=90=86=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qtquick/account/accountlistmodel.cpp | 28 +++--------------------- app/qtquick/account/accountlistmodel.h | 1 - 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/app/qtquick/account/accountlistmodel.cpp b/app/qtquick/account/accountlistmodel.cpp index e4d3a205..ce2d06cd 100644 --- a/app/qtquick/account/accountlistmodel.cpp +++ b/app/qtquick/account/accountlistmodel.cpp @@ -555,7 +555,9 @@ void AccountListModel::getProfile(int row) emit updatedAccount(row, m_accountList[row].uuid); emit dataChanged(index(row), index(row)); - getRawProfile(row); + qDebug() << "Update pinned post" << detail.pinnedPost.uri; + PinnedPostCache::getInstance()->update(m_accountList.at(row).did, + detail.pinnedPost.uri); } else { emit errorOccured(profile->errorCode(), profile->errorMessage()); } @@ -565,30 +567,6 @@ void AccountListModel::getProfile(int row) }); } -void AccountListModel::getRawProfile(int row) -{ - if (row < 0 || row >= m_accountList.count()) - return; - - ComAtprotoRepoGetRecordEx *record = new ComAtprotoRepoGetRecordEx(this); - connect(record, &ComAtprotoRepoGetRecordEx::finished, this, [=](bool success) { - if (success) { - AtProtocolType::AppBskyActorProfile::Main profile = - AtProtocolType::LexiconsTypeUnknown::fromQVariant< - AtProtocolType::AppBskyActorProfile::Main>(record->value()); - qDebug() << "Update pinned post" << profile.pinnedPost.uri; - PinnedPostCache::getInstance()->update(m_accountList.at(row).did, - profile.pinnedPost.uri); - - } else { - emit errorOccured(record->errorCode(), record->errorMessage()); - } - record->deleteLater(); - }); - record->setAccount(m_accountList.at(row)); - record->profile(m_accountList.at(row).did); -} - void AccountListModel::getServiceEndpoint(const QString &did, const QString &service, std::function callback) { diff --git a/app/qtquick/account/accountlistmodel.h b/app/qtquick/account/accountlistmodel.h index 06ce1e37..37c650ca 100644 --- a/app/qtquick/account/accountlistmodel.h +++ b/app/qtquick/account/accountlistmodel.h @@ -98,7 +98,6 @@ class AccountListModel : public QAbstractListModel void createSession(int row); void refreshSession(int row, bool initial = false); void getProfile(int row); - void getRawProfile(int row); void getServiceEndpoint(const QString &did, const QString &service, std::function callback); bool allAccountTried() const; From 5bd142660faa3dd99ed01484a9884ae22ffc694c Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 12:19:04 +0900 Subject: [PATCH 15/19] =?UTF-8?q?=E4=BB=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/qtquick/timeline/timelinelistmodel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/qtquick/timeline/timelinelistmodel.cpp b/app/qtquick/timeline/timelinelistmodel.cpp index 13f43692..f29d4b13 100644 --- a/app/qtquick/timeline/timelinelistmodel.cpp +++ b/app/qtquick/timeline/timelinelistmodel.cpp @@ -192,6 +192,7 @@ QVariant TimelineListModel::item(int row, TimelineListModelRoles role) const else if (role == PinnedRole) return isPinnedPost(current.post.cid) && row == 0; else if (role == PinnedByMeRole) + // return current.post.viewer.pinned; return PinnedPostCache::getInstance()->pinned(account().did, current.post.uri); else if (role == ThreadMutedRole) return current.post.viewer.threadMuted; @@ -385,6 +386,7 @@ void TimelineListModel::update(int row, TimelineListModelRoles role, const QVari QVector() << role << IsLikedRole << LikeCountRole); } else if (role == PinnedByMeRole) { qDebug() << "update Pinned by me:" << value.toString(); + current.post.viewer.pinned = value.toBool(); emit dataChanged(index(row), index(row), QVector() << role << PinnedRole); } else if (role == ThreadMutedRole) { bool muted = value.toBool(); From 240992f806389bf3015916593c06399e1149f335 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 12:45:01 +0900 Subject: [PATCH 16/19] =?UTF-8?q?=E3=83=AA=E3=83=AA=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=83=8E=E3=83=BC=E3=83=88=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/content/docs/release-note.en.md | 1 + web/content/docs/release-note.ja.md | 1 + 2 files changed, 2 insertions(+) diff --git a/web/content/docs/release-note.en.md b/web/content/docs/release-note.en.md index f79540a9..994c3a4e 100644 --- a/web/content/docs/release-note.en.md +++ b/web/content/docs/release-note.en.md @@ -9,6 +9,7 @@ description: This is a multi-column Bluesky client. ## 2024 - Update + - Make the implementation of pinned posts officially compliant - Change the flow when there are unauthenticated accounts - Fix - Fix the display of posts quoted from labeled posts diff --git a/web/content/docs/release-note.ja.md b/web/content/docs/release-note.ja.md index b8d1a3dd..ad369a78 100644 --- a/web/content/docs/release-note.ja.md +++ b/web/content/docs/release-note.ja.md @@ -9,6 +9,7 @@ description: マルチカラム対応Blueskyクライアント ## 2024 - 更新 + - 固定ポストを公式準拠に変更 - 認証できないアカウントがあるときのフローを変更 - 修正 - ラベリングされたポストから引用されたポストの表示を修正 From d67e41c9061ac00c85684ccdc503d7b68d874d88 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 12:46:09 +0900 Subject: [PATCH 17/19] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E3=83=95?= =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/lexicons/app.bsky.actor.profile.json | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 scripts/lexicons/app.bsky.actor.profile.json diff --git a/scripts/lexicons/app.bsky.actor.profile.json b/scripts/lexicons/app.bsky.actor.profile.json deleted file mode 100644 index 79d5ce3e..00000000 --- a/scripts/lexicons/app.bsky.actor.profile.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "defs": { - "main": { - "record": { - "properties": { - "pinnedPost": { - "type": "string", - "description": "(Unofficial field)", - "format": "at-uri" - } - } - } - } - } -} From 43445d2b43587d13258754b6bf20f896e29ba750 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 13:14:25 +0900 Subject: [PATCH 18/19] =?UTF-8?q?=E7=8B=AC=E8=87=AA=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E3=81=AB=E4=BB=AE=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/atprotocol/lexicons_func.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/atprotocol/lexicons_func.cpp b/lib/atprotocol/lexicons_func.cpp index 2a229cca..43ca6f22 100644 --- a/lib/atprotocol/lexicons_func.cpp +++ b/lib/atprotocol/lexicons_func.cpp @@ -112,7 +112,11 @@ void copyProfileViewDetailed(const QJsonObject &src, AppBskyActorDefs::ProfileVi ComAtprotoLabelDefs::copyLabel(s.toObject(), child); dest.labels.append(child); } - ComAtprotoRepoStrongRef::copyMain(src.value("pinnedPost").toObject(), dest.pinnedPost); + if (src.value("pinnedPost").isString()) { + dest.pinnedPost.uri = src.value("pinnedPost").toString(); + } else { + ComAtprotoRepoStrongRef::copyMain(src.value("pinnedPost").toObject(), dest.pinnedPost); + } } } void copyAdultContentPref(const QJsonObject &src, AppBskyActorDefs::AdultContentPref &dest) From 3c8f7c20f187738597e2a960e4ac21e647853c64 Mon Sep 17 00:00:00 2001 From: Takayuki Orito Date: Sat, 28 Sep 2024 16:08:42 +0900 Subject: [PATCH 19/19] =?UTF-8?q?=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E6=83=85=E5=A0=B1=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/main.cpp | 2 +- web/content/docs/release-note.en.md | 2 ++ web/content/docs/release-note.ja.md | 2 ++ web/layouts/shortcodes/download_link.html | 8 ++++---- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/main.cpp b/app/main.cpp index e93570ae..e29cd2b6 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) app.setOrganizationName(QStringLiteral("relog")); app.setOrganizationDomain(QStringLiteral("hagoromo.relog.tech")); app.setApplicationName(QStringLiteral("Hagoromo")); - app.setApplicationVersion(QStringLiteral("0.37.0")); + app.setApplicationVersion(QStringLiteral("0.38.0")); #ifndef HAGOROMO_RELEASE_BUILD app.setApplicationVersion(app.applicationVersion() + "d"); #endif diff --git a/web/content/docs/release-note.en.md b/web/content/docs/release-note.en.md index 994c3a4e..1d7248d0 100644 --- a/web/content/docs/release-note.en.md +++ b/web/content/docs/release-note.en.md @@ -8,6 +8,8 @@ description: This is a multi-column Bluesky client. ## 2024 +### v0.38.0 - 2024/9/28 + - Update - Make the implementation of pinned posts officially compliant - Change the flow when there are unauthenticated accounts diff --git a/web/content/docs/release-note.ja.md b/web/content/docs/release-note.ja.md index ad369a78..f1448318 100644 --- a/web/content/docs/release-note.ja.md +++ b/web/content/docs/release-note.ja.md @@ -8,6 +8,8 @@ description: マルチカラム対応Blueskyクライアント ## 2024 +### v0.38.0 - 2024/9/28 + - 更新 - 固定ポストを公式準拠に変更 - 認証できないアカウントがあるときのフローを変更 diff --git a/web/layouts/shortcodes/download_link.html b/web/layouts/shortcodes/download_link.html index 2fa5aefb..490e5959 100644 --- a/web/layouts/shortcodes/download_link.html +++ b/web/layouts/shortcodes/download_link.html @@ -1,9 +1,9 @@