From 5511c195766de625bf6c4bf39950940814c27aad Mon Sep 17 00:00:00 2001 From: ConfuSomu Date: Wed, 3 Jan 2024 19:20:26 +0100 Subject: Move activity list to a tab widget This allows us to have more tabs in the future with additional information, such as information about the Actor or even other activity views. This commit was quite a lot of work and refactoring! --- src/widgets/tab_activity_list.cpp | 182 ++++++++++++++++++++++++++++++++++++++ src/widgets/tab_activity_list.h | 69 +++++++++++++++ src/widgets/tab_activity_list.ui | 63 +++++++++++++ 3 files changed, 314 insertions(+) create mode 100644 src/widgets/tab_activity_list.cpp create mode 100644 src/widgets/tab_activity_list.h create mode 100644 src/widgets/tab_activity_list.ui (limited to 'src/widgets') diff --git a/src/widgets/tab_activity_list.cpp b/src/widgets/tab_activity_list.cpp new file mode 100644 index 0000000..03065eb --- /dev/null +++ b/src/widgets/tab_activity_list.cpp @@ -0,0 +1,182 @@ +#include "tab_activity_list.h" +#include "./ui_tab_activity_list.h" +#include "status_info.h" +#include "src/net/instance.h" + +#include +#include +#include +#include +#include +#include + +TabActivityList::TabActivityList(Archive** archive, QWidget* parent) + : data_archive(archive), QWidget(parent), ui(new Ui::TabActivityList) +{ + ui->setupUi(this); + // QGridLayouts have margins around each element, but here we already have margins outside of the element, so these ones are not welcome + ui->gridLayout->setContentsMargins(0, 0, 0, 0); + + status_info_widget = new StatusInfoWidget(this); + ui->gridLayout->addWidget(status_info_widget, 1, 1); +} + +TabActivityList::~TabActivityList() { + delete ui; +} + +void TabActivityList::on_listWidget_itemActivated(QListWidgetItem *item) { + StatusListItem* status = dynamic_cast(item); + if (status != nullptr) { + status_info_widget->show_list_item(status); + } +} + +void TabActivityList::on_buttonRandom_clicked() { + if ((*data_archive) == nullptr) return; // No archive open, avoids crashing + + int index = QRandomGenerator::global()->bounded(ui->listWidget->count()); + QListWidgetItem* item = ui->listWidget->item(index); + on_listWidget_itemActivated(item); + ui->listWidget->setCurrentItem(item); +} + +void TabActivityList::on_buttonCopy_clicked() { + if ((*data_archive) == nullptr or ui->listWidget->selectedItems().isEmpty()) return; + + StatusListItem* item = dynamic_cast(ui->listWidget->selectedItems()[0]); + if (item != nullptr) { + QString status_text = (*data_archive)->get_html_status_text(item->get_status_index()); + QMimeData* clipboard_data = new QMimeData; + clipboard_data->setHtml(status_text); + QGuiApplication::clipboard()->setMimeData(clipboard_data); + } +} + +void TabActivityList::on_buttonSearch_clicked() { + if (!find_dialog) { + find_dialog = new FindDialog(this); + find_dialog->set_qlist_widget(ui->listWidget); + connect(find_dialog, &FindDialog::item_selected, this, &TabActivityList::select_list_item); + connect(this, &TabActivityList::search_text_changed, find_dialog, &FindDialog::set_search_text); + connect(find_dialog, &FindDialog::search_text_changed, this, &TabActivityList::set_search_text); + + if (not ui->textInputSearch->text().isEmpty()) + emit search_text_changed(ui->textInputSearch->text(), true); + } + + find_dialog->show(); + find_dialog->raise(); + find_dialog->activateWindow(); +} + +void TabActivityList::select_list_item(QListWidgetItem* item) { + on_listWidget_itemActivated(item); +} + +void TabActivityList::on_textInputSearch_textEdited(const QString &text) { + emit search_text_changed(text); +} + +void TabActivityList::set_search_text(const QString &text) { + ui->textInputSearch->setText(text); +} + +void TabActivityList::actionOpen_URL_triggered(bool checked) { + bool ok; + QString url = QInputDialog::getText(this, tr("Open status from URL"), tr("Status URL:"), QLineEdit::Normal, "https://…", &ok); + + // TODO: Move all of this to another thread + // TODO: Reuse the Instance object + // Really hacky code but works as a PoC and allows testing + if (ok and not url.isEmpty()) { + Instance* instance = Instance::create_instance(); + APPost* post = instance->get_post_from_url(url); + // Activity will be freed by StatusInfoWidget + APActivity* activity = new APActivity({.object = post}); + status_info_widget->do_process_activity(activity); + delete instance; instance = nullptr; + } else return; +} + +void TabActivityList::relist_statuses() { + if (*data_archive) { + ui->listWidget->clear(); + (*data_archive)->update_status_list(view_filters, ui->listWidget); + view_filters_changed = false; + } + // Cursor overriden only when opening new archive + if (QApplication::overrideCursor()) + QApplication::restoreOverrideCursor(); +} + +// Function used to reset filters when we have detected that the "All toots" toggle has been toggled on or shouldn't be toggled anymore +void TabActivityList::reset_view_filters() { + if (view_actions.actionAll_toots->isChecked()) + view_filters = {true, true, true, true, view_filters.includeReblogs, view_filters.onlyWithAttachment}; + else + view_filters = {false, false, false, false, view_filters.includeReblogs, view_filters.onlyWithAttachment}; +} + +void TabActivityList::actionAll_toots_triggered(bool checked) { + view_actions.actionAll_toots->setChecked(true); + view_actions.actionPublic_toots->setChecked(false); + view_actions.actionUnlisted_toots->setChecked(false); + view_actions.actionPrivate_toots->setChecked(false); + view_actions.actionDirect_messages->setChecked(false); + view_actions.actionOnly_with_attachment->setChecked(false); + + reset_view_filters(); + relist_statuses(); +} + +void TabActivityList::actionPublic_toots_triggered(bool checked) { + if (view_actions.actionAll_toots->isChecked()) { + view_actions.actionAll_toots->setChecked(false); + reset_view_filters(); + } + view_filters.includePublic = checked; + view_filters_changed = true; +} + +void TabActivityList::actionUnlisted_toots_triggered(bool checked) { + if (view_actions.actionAll_toots->isChecked()) { + view_actions.actionAll_toots->setChecked(false); + reset_view_filters(); + } + view_filters.includeUnlisted = checked; + view_filters_changed = true; +} + +void TabActivityList::actionPrivate_toots_triggered(bool checked) { + if (view_actions.actionAll_toots->isChecked()) { + view_actions.actionAll_toots->setChecked(false); + reset_view_filters(); + } + view_filters.includePrivate = checked; + view_filters_changed = true; +} + +void TabActivityList::actionDirect_messages_triggered(bool checked) { + if (view_actions.actionAll_toots->isChecked()) { + view_actions.actionAll_toots->setChecked(false); + reset_view_filters(); + } + view_filters.includeDirect = checked; + view_filters_changed = true; +} + +void TabActivityList::actionOnly_with_attachment_triggered(bool checked) { + view_filters.onlyWithAttachment = checked; + view_filters_changed = true; +} + +void TabActivityList::actionReblogs_triggered(bool checked) { + view_filters.includeReblogs = checked; + view_filters_changed = true; +} + +void TabActivityList::menuView_aboutToHide() { + if (view_filters_changed) + relist_statuses(); +} diff --git a/src/widgets/tab_activity_list.h b/src/widgets/tab_activity_list.h new file mode 100644 index 0000000..ae6d426 --- /dev/null +++ b/src/widgets/tab_activity_list.h @@ -0,0 +1,69 @@ +#pragma once +#include +#include +#include "src/widgets/status_info.h" +#include "src/finddialog.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class TabActivityList; } +QT_END_NAMESPACE + +class TabActivityList : public QWidget { + Q_OBJECT + +public: + struct ViewActions { + QAction* actionAll_toots = nullptr; + QAction* actionPublic_toots = nullptr; + QAction* actionUnlisted_toots = nullptr; + QAction* actionPrivate_toots = nullptr; + QAction* actionDirect_messages = nullptr; + QAction* actionOnly_with_attachment = nullptr; + } view_actions; + + + TabActivityList(Archive** archive, QWidget *parent = nullptr); + ~TabActivityList(); + +public slots: + void actionAll_toots_triggered(bool checked); + void actionPublic_toots_triggered(bool checked); + void actionUnlisted_toots_triggered(bool checked); + void actionPrivate_toots_triggered(bool checked); + void actionDirect_messages_triggered(bool checked); + void actionOnly_with_attachment_triggered(bool checked); + void actionReblogs_triggered(bool checked); + + void on_buttonRandom_clicked(); + void on_buttonCopy_clicked(); + void on_buttonSearch_clicked(); + + void actionOpen_URL_triggered(bool checked); + void menuView_aboutToHide(); + + void relist_statuses(); + + void select_list_item(QListWidgetItem* item); + void set_search_text(const QString &text); + +signals: + void search_text_changed(const QString &text, bool search_immediately = false); + +private slots: + void on_textInputSearch_textEdited(const QString &text); + void on_listWidget_itemActivated(QListWidgetItem *item); + +private: + void reset_view_filters(); + + StatusInfoWidget* status_info_widget = nullptr; + + Ui::TabActivityList* ui; + + // Pointer to MainWindow's data archive pointer + Archive **data_archive = nullptr; + FindDialog* find_dialog = nullptr; + + ViewStatusTypes view_filters; + bool view_filters_changed = false; +}; diff --git a/src/widgets/tab_activity_list.ui b/src/widgets/tab_activity_list.ui new file mode 100644 index 0000000..989aa12 --- /dev/null +++ b/src/widgets/tab_activity_list.ui @@ -0,0 +1,63 @@ + + + TabActivityList + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + + + + Search + + + + + + + + + + + Random status + + + + + + + Copy status text + + + + + + + + + Qt::ScrollBarAlwaysOff + + + true + + + + + + + + -- cgit v1.2.3-54-g00ecf