Applications: Remove ChanViewer app

The HTTP JSON API this relied on is no longer available via HTTP and
I would rather make the website work in Browser anyway. :^)
This commit is contained in:
Andreas Kling 2020-04-23 18:36:13 +02:00
parent 9142890822
commit 2454c3b7fb
Notes: sideshowbarker 2024-07-19 07:22:07 +09:00
11 changed files with 1 additions and 541 deletions

View file

@ -1,117 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "BoardListModel.h"
#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <LibCore/HttpRequest.h>
#include <LibCore/NetworkJob.h>
#include <LibCore/NetworkResponse.h>
#include <stdio.h>
BoardListModel::BoardListModel()
{
update();
}
BoardListModel::~BoardListModel()
{
}
void BoardListModel::update()
{
Core::HttpRequest request;
request.set_url("http://a.4cdn.org/boards.json");
if (m_pending_job)
m_pending_job->cancel();
m_pending_job = request.schedule();
m_pending_job->on_finish = [this](bool success) {
auto* response = m_pending_job->response();
dbg() << "Board list download finished, success=" << success << ", response=" << response;
if (!success)
return;
dbg() << "Board list payload size: " << response->payload().size();
auto json = JsonValue::from_string(response->payload());
if (json.is_object()) {
auto new_boards = json.as_object().get("boards");
if (new_boards.is_array())
m_boards = move(new_boards.as_array());
}
did_update();
};
}
int BoardListModel::row_count(const GUI::ModelIndex&) const
{
return m_boards.size();
}
String BoardListModel::column_name(int column) const
{
switch (column) {
case Column::Board:
return "Board";
default:
ASSERT_NOT_REACHED();
}
}
GUI::Model::ColumnMetadata BoardListModel::column_metadata([[maybe_unused]] int column) const
{
return {};
}
GUI::Variant BoardListModel::data(const GUI::ModelIndex& index, Role role) const
{
auto& board = m_boards.at(index.row()).as_object();
if (role == Role::Display) {
switch (index.column()) {
case Column::Board:
return String::format("/%s/ - %s",
board.get("board").to_string().characters(),
board.get("title").to_string().characters());
default:
ASSERT_NOT_REACHED();
}
}
if (role == Role::Custom) {
switch (index.column()) {
case Column::Board:
return board.get("board").to_string();
default:
ASSERT_NOT_REACHED();
}
}
return {};
}

View file

@ -1,55 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/JsonArray.h>
#include <LibCore/HttpJob.h>
#include <LibGUI/Model.h>
class BoardListModel final : public GUI::Model {
public:
enum Column {
Board,
__Count,
};
static NonnullRefPtr<BoardListModel> create() { return adopt(*new BoardListModel); }
virtual ~BoardListModel() override;
virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override;
virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return Column::__Count; }
virtual String column_name(int) const override;
virtual ColumnMetadata column_metadata(int) const override;
virtual GUI::Variant data(const GUI::ModelIndex&, Role = Role::Display) const override;
virtual void update() override;
private:
BoardListModel();
JsonArray m_boards;
RefPtr<Core::NetworkJob> m_pending_job;
};

View file

@ -1,10 +0,0 @@
OBJS = \
ThreadCatalogModel.o \
BoardListModel.o \
main.o
PROGRAM = ChanViewer
LIB_DEPS = GUI Gfx IPC Thread Pthread Core
include ../../Makefile.common

View file

@ -1,170 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ThreadCatalogModel.h"
#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <LibCore/HttpRequest.h>
#include <LibCore/NetworkJob.h>
#include <LibCore/NetworkResponse.h>
#include <stdio.h>
ThreadCatalogModel::ThreadCatalogModel()
{
update();
}
ThreadCatalogModel::~ThreadCatalogModel()
{
}
void ThreadCatalogModel::set_board(const String& board)
{
if (m_board == board)
return;
m_board = board;
update();
}
void ThreadCatalogModel::update()
{
Core::HttpRequest request;
request.set_url(String::format("http://a.4cdn.org/%s/catalog.json", m_board.characters()));
if (m_pending_job)
m_pending_job->cancel();
m_pending_job = request.schedule();
if (on_load_started)
on_load_started();
m_pending_job->on_finish = [this](bool success) {
auto* response = m_pending_job->response();
dbg() << "Catalog download finished, success=" << success << ", response=" << response;
if (!success) {
if (on_load_finished)
on_load_finished(false);
return;
}
dbg() << "Catalog payload size: " << response->payload().size();
auto json = JsonValue::from_string(response->payload());
if (json.is_array()) {
JsonArray new_catalog;
for (auto& page : json.as_array().values()) {
if (!page.is_object())
continue;
auto threads_value = page.as_object().get("threads");
if (!threads_value.is_array())
continue;
for (auto& thread : threads_value.as_array().values()) {
new_catalog.append(thread);
}
}
m_catalog = move(new_catalog);
}
did_update();
if (on_load_finished)
on_load_finished(true);
};
}
int ThreadCatalogModel::row_count(const GUI::ModelIndex&) const
{
return m_catalog.size();
}
String ThreadCatalogModel::column_name(int column) const
{
switch (column) {
case Column::ThreadNumber:
return "#";
case Column::Subject:
return "Subject";
case Column::Text:
return "Text";
case Column::ReplyCount:
return "Replies";
case Column::ImageCount:
return "Images";
case Column::PostTime:
return "Time";
default:
ASSERT_NOT_REACHED();
}
}
GUI::Model::ColumnMetadata ThreadCatalogModel::column_metadata(int column) const
{
switch (column) {
case Column::ThreadNumber:
return { 70, Gfx::TextAlignment::CenterRight };
case Column::Subject:
return { 170, Gfx::TextAlignment::CenterLeft };
case Column::Text:
return { 270, Gfx::TextAlignment::CenterLeft };
case Column::ReplyCount:
return { 45, Gfx::TextAlignment::CenterRight };
case Column::ImageCount:
return { 40, Gfx::TextAlignment::CenterRight };
case Column::PostTime:
return { 120, Gfx::TextAlignment::CenterLeft };
default:
ASSERT_NOT_REACHED();
}
}
GUI::Variant ThreadCatalogModel::data(const GUI::ModelIndex& index, Role role) const
{
auto& thread = m_catalog.at(index.row()).as_object();
if (role == Role::Display) {
switch (index.column()) {
case Column::ThreadNumber:
return thread.get("no").to_u32();
case Column::Subject:
return thread.get("sub").as_string_or({});
case Column::Text:
return thread.get("com").as_string_or({});
case Column::ReplyCount:
return thread.get("replies").to_u32();
case Column::ImageCount:
return thread.get("images").to_u32();
case Column::PostTime:
return thread.get("now").to_string();
default:
ASSERT_NOT_REACHED();
}
}
return {};
}

View file

@ -1,67 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/JsonArray.h>
#include <LibCore/HttpJob.h>
#include <LibGUI/Model.h>
class ThreadCatalogModel final : public GUI::Model {
public:
enum Column {
ThreadNumber,
Subject,
Text,
ReplyCount,
ImageCount,
PostTime,
__Count,
};
static NonnullRefPtr<ThreadCatalogModel> create() { return adopt(*new ThreadCatalogModel); }
virtual ~ThreadCatalogModel() override;
virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override;
virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return Column::__Count; }
virtual String column_name(int) const override;
virtual ColumnMetadata column_metadata(int) const override;
virtual GUI::Variant data(const GUI::ModelIndex&, Role = Role::Display) const override;
virtual void update() override;
const String& board() const { return m_board; }
void set_board(const String&);
Function<void()> on_load_started;
Function<void(bool success)> on_load_finished;
private:
ThreadCatalogModel();
String m_board { "g" };
JsonArray m_catalog;
RefPtr<Core::NetworkJob> m_pending_job;
};

View file

@ -1,111 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "BoardListModel.h"
#include "ThreadCatalogModel.h"
#include <LibGUI/AboutDialog.h>
#include <LibGUI/Action.h>
#include <LibGUI/Application.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/ComboBox.h>
#include <LibGUI/Menu.h>
#include <LibGUI/MenuBar.h>
#include <LibGUI/StatusBar.h>
#include <LibGUI/TableView.h>
#include <LibGUI/Window.h>
#include <stdio.h>
int main(int argc, char** argv)
{
if (pledge("stdio dns inet shared_buffer rpath cpath fattr", nullptr) < 0) {
perror("pledge");
return 1;
}
GUI::Application app(argc, argv);
if (pledge("stdio dns inet shared_buffer rpath", nullptr) < 0) {
perror("pledge");
return 1;
}
auto window = GUI::Window::construct();
window->set_title("ChanViewer");
window->set_rect(100, 100, 800, 500);
window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-chanviewer.png"));
auto& widget = window->set_main_widget<GUI::Widget>();
widget.set_fill_with_background_color(true);
widget.set_layout<GUI::VerticalBoxLayout>();
auto& board_combo = widget.add<GUI::ComboBox>();
board_combo.set_only_allow_values_from_model(true);
board_combo.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
board_combo.set_preferred_size(0, 20);
board_combo.set_model(BoardListModel::create());
auto& catalog_view = widget.add<GUI::TableView>();
catalog_view.set_model(ThreadCatalogModel::create());
auto& catalog_model = *static_cast<ThreadCatalogModel*>(catalog_view.model());
auto& statusbar = widget.add<GUI::StatusBar>();
board_combo.on_change = [&] (auto&, const GUI::ModelIndex& index) {
auto selected_board = board_combo.model()->data(index, GUI::Model::Role::Custom);
ASSERT(selected_board.is_string());
catalog_model.set_board(selected_board.to_string());
};
catalog_model.on_load_started = [&] {
statusbar.set_text(String::format("Loading /%s/...", catalog_model.board().characters()));
};
catalog_model.on_load_finished = [&](bool success) {
statusbar.set_text(success ? "Load finished" : "Load failed");
if (success) {
window->set_title(String::format("/%s/ - ChanViewer", catalog_model.board().characters()));
}
};
window->show();
auto menubar = GUI::MenuBar::construct();
auto& app_menu = menubar->add_menu("ChanViewer");
app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
GUI::Application::the().quit(0);
return;
}));
auto& help_menu = menubar->add_menu("Help");
help_menu.add_action(GUI::Action::create("About", [&](const GUI::Action&) {
GUI::AboutDialog::show("ChanViewer", Gfx::Bitmap::load_from_file("/res/icons/32x32/app-chanviewer.png"), window);
}));
app.set_menubar(move(menubar));
return app.exec();
}

View file

@ -1,8 +0,0 @@
[App]
Name=ChanViewer
Executable=/bin/ChanViewer
Category=Internet
[Icons]
16x16=/res/icons/16x16/app-chanviewer.png
32x32=/res/icons/32x32/app-chanviewer.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

View file

@ -30,7 +30,7 @@ latest news and financial information, and visit Web sites around the world,
most of which will make you really angry.
Serenity includes several internet applications, such as an IRC (Internet relay
chat) client, 4chan browser, telnet server, and basic utilities like ping.
chat) client, WWW browser, telnet server, and basic utilities like ping.
Come chat with us today! How bad can it be?

View file

@ -136,7 +136,6 @@ cp ../Applications/PaintBrush/PaintBrush mnt/bin/PaintBrush
cp ../Applications/QuickShow/QuickShow mnt/bin/QuickShow
cp ../Applications/Piano/Piano mnt/bin/Piano
cp ../Applications/SystemMenu/SystemMenu mnt/bin/SystemMenu
cp ../Applications/ChanViewer/ChanViewer mnt/bin/ChanViewer
cp ../Applications/Calculator/Calculator mnt/bin/Calculator
cp ../Applications/Calendar/Calendar mnt/bin/Calendar
cp ../Applications/SoundPlayer/SoundPlayer mnt/bin/SoundPlayer
@ -195,7 +194,6 @@ ln -s PaintBrush mnt/bin/pb
ln -s QuickShow mnt/bin/qs
ln -s Piano mnt/bin/pi
ln -s SystemDialog mnt/bin/sd
ln -s ChanViewer mnt/bin/cv
ln -s Calculator mnt/bin/calc
ln -s Calendar mnt/bin/calendar
ln -s Inspector mnt/bin/ins